162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ext4/resize.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Support for resizing an ext4 filesystem while it is mounted. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2001, 2002 Andreas Dilger <adilger@clusterfs.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This could probably be made into a module, because it is not often in use. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define EXT4FS_DEBUG 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/jiffies.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "ext4_jbd2.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistruct ext4_rcu_ptr { 2262306a36Sopenharmony_ci struct rcu_head rcu; 2362306a36Sopenharmony_ci void *ptr; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void ext4_rcu_ptr_callback(struct rcu_head *head) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct ext4_rcu_ptr *ptr; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci ptr = container_of(head, struct ext4_rcu_ptr, rcu); 3162306a36Sopenharmony_ci kvfree(ptr->ptr); 3262306a36Sopenharmony_ci kfree(ptr); 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_civoid ext4_kvfree_array_rcu(void *to_free) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct ext4_rcu_ptr *ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (ptr) { 4062306a36Sopenharmony_ci ptr->ptr = to_free; 4162306a36Sopenharmony_ci call_rcu(&ptr->rcu, ext4_rcu_ptr_callback); 4262306a36Sopenharmony_ci return; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci synchronize_rcu(); 4562306a36Sopenharmony_ci kvfree(to_free); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ciint ext4_resize_begin(struct super_block *sb) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 5162306a36Sopenharmony_ci int ret = 0; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (!capable(CAP_SYS_RESOURCE)) 5462306a36Sopenharmony_ci return -EPERM; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* 5762306a36Sopenharmony_ci * If the reserved GDT blocks is non-zero, the resize_inode feature 5862306a36Sopenharmony_ci * should always be set. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci if (EXT4_SB(sb)->s_es->s_reserved_gdt_blocks && 6162306a36Sopenharmony_ci !ext4_has_feature_resize_inode(sb)) { 6262306a36Sopenharmony_ci ext4_error(sb, "resize_inode disabled but reserved GDT blocks non-zero"); 6362306a36Sopenharmony_ci return -EFSCORRUPTED; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* 6762306a36Sopenharmony_ci * If we are not using the primary superblock/GDT copy don't resize, 6862306a36Sopenharmony_ci * because the user tools have no way of handling this. Probably a 6962306a36Sopenharmony_ci * bad time to do it anyways. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_ci if (EXT4_B2C(sbi, sbi->s_sbh->b_blocknr) != 7262306a36Sopenharmony_ci le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) { 7362306a36Sopenharmony_ci ext4_warning(sb, "won't resize using backup superblock at %llu", 7462306a36Sopenharmony_ci (unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr); 7562306a36Sopenharmony_ci return -EPERM; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* 7962306a36Sopenharmony_ci * We are not allowed to do online-resizing on a filesystem mounted 8062306a36Sopenharmony_ci * with error, because it can destroy the filesystem easily. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { 8362306a36Sopenharmony_ci ext4_warning(sb, "There are errors in the filesystem, " 8462306a36Sopenharmony_ci "so online resizing is not allowed"); 8562306a36Sopenharmony_ci return -EPERM; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (ext4_has_feature_sparse_super2(sb)) { 8962306a36Sopenharmony_ci ext4_msg(sb, KERN_ERR, "Online resizing not supported with sparse_super2"); 9062306a36Sopenharmony_ci return -EOPNOTSUPP; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (test_and_set_bit_lock(EXT4_FLAGS_RESIZING, 9462306a36Sopenharmony_ci &EXT4_SB(sb)->s_ext4_flags)) 9562306a36Sopenharmony_ci ret = -EBUSY; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return ret; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciint ext4_resize_end(struct super_block *sb, bool update_backups) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci clear_bit_unlock(EXT4_FLAGS_RESIZING, &EXT4_SB(sb)->s_ext4_flags); 10362306a36Sopenharmony_ci smp_mb__after_atomic(); 10462306a36Sopenharmony_ci if (update_backups) 10562306a36Sopenharmony_ci return ext4_update_overhead(sb, true); 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic ext4_group_t ext4_meta_bg_first_group(struct super_block *sb, 11062306a36Sopenharmony_ci ext4_group_t group) { 11162306a36Sopenharmony_ci return (group >> EXT4_DESC_PER_BLOCK_BITS(sb)) << 11262306a36Sopenharmony_ci EXT4_DESC_PER_BLOCK_BITS(sb); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic ext4_fsblk_t ext4_meta_bg_first_block_no(struct super_block *sb, 11662306a36Sopenharmony_ci ext4_group_t group) { 11762306a36Sopenharmony_ci group = ext4_meta_bg_first_group(sb, group); 11862306a36Sopenharmony_ci return ext4_group_first_block_no(sb, group); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic ext4_grpblk_t ext4_group_overhead_blocks(struct super_block *sb, 12262306a36Sopenharmony_ci ext4_group_t group) { 12362306a36Sopenharmony_ci ext4_grpblk_t overhead; 12462306a36Sopenharmony_ci overhead = ext4_bg_num_gdb(sb, group); 12562306a36Sopenharmony_ci if (ext4_bg_has_super(sb, group)) 12662306a36Sopenharmony_ci overhead += 1 + 12762306a36Sopenharmony_ci le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks); 12862306a36Sopenharmony_ci return overhead; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#define outside(b, first, last) ((b) < (first) || (b) >= (last)) 13262306a36Sopenharmony_ci#define inside(b, first, last) ((b) >= (first) && (b) < (last)) 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int verify_group_input(struct super_block *sb, 13562306a36Sopenharmony_ci struct ext4_new_group_data *input) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 13862306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 13962306a36Sopenharmony_ci ext4_fsblk_t start = ext4_blocks_count(es); 14062306a36Sopenharmony_ci ext4_fsblk_t end = start + input->blocks_count; 14162306a36Sopenharmony_ci ext4_group_t group = input->group; 14262306a36Sopenharmony_ci ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; 14362306a36Sopenharmony_ci unsigned overhead; 14462306a36Sopenharmony_ci ext4_fsblk_t metaend; 14562306a36Sopenharmony_ci struct buffer_head *bh = NULL; 14662306a36Sopenharmony_ci ext4_grpblk_t free_blocks_count, offset; 14762306a36Sopenharmony_ci int err = -EINVAL; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (group != sbi->s_groups_count) { 15062306a36Sopenharmony_ci ext4_warning(sb, "Cannot add at group %u (only %u groups)", 15162306a36Sopenharmony_ci input->group, sbi->s_groups_count); 15262306a36Sopenharmony_ci return -EINVAL; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci overhead = ext4_group_overhead_blocks(sb, group); 15662306a36Sopenharmony_ci metaend = start + overhead; 15762306a36Sopenharmony_ci input->free_clusters_count = free_blocks_count = 15862306a36Sopenharmony_ci input->blocks_count - 2 - overhead - sbi->s_itb_per_group; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (test_opt(sb, DEBUG)) 16162306a36Sopenharmony_ci printk(KERN_DEBUG "EXT4-fs: adding %s group %u: %u blocks " 16262306a36Sopenharmony_ci "(%d free, %u reserved)\n", 16362306a36Sopenharmony_ci ext4_bg_has_super(sb, input->group) ? "normal" : 16462306a36Sopenharmony_ci "no-super", input->group, input->blocks_count, 16562306a36Sopenharmony_ci free_blocks_count, input->reserved_blocks); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ext4_get_group_no_and_offset(sb, start, NULL, &offset); 16862306a36Sopenharmony_ci if (offset != 0) 16962306a36Sopenharmony_ci ext4_warning(sb, "Last group not full"); 17062306a36Sopenharmony_ci else if (input->reserved_blocks > input->blocks_count / 5) 17162306a36Sopenharmony_ci ext4_warning(sb, "Reserved blocks too high (%u)", 17262306a36Sopenharmony_ci input->reserved_blocks); 17362306a36Sopenharmony_ci else if (free_blocks_count < 0) 17462306a36Sopenharmony_ci ext4_warning(sb, "Bad blocks count %u", 17562306a36Sopenharmony_ci input->blocks_count); 17662306a36Sopenharmony_ci else if (IS_ERR(bh = ext4_sb_bread(sb, end - 1, 0))) { 17762306a36Sopenharmony_ci err = PTR_ERR(bh); 17862306a36Sopenharmony_ci bh = NULL; 17962306a36Sopenharmony_ci ext4_warning(sb, "Cannot read last block (%llu)", 18062306a36Sopenharmony_ci end - 1); 18162306a36Sopenharmony_ci } else if (outside(input->block_bitmap, start, end)) 18262306a36Sopenharmony_ci ext4_warning(sb, "Block bitmap not in group (block %llu)", 18362306a36Sopenharmony_ci (unsigned long long)input->block_bitmap); 18462306a36Sopenharmony_ci else if (outside(input->inode_bitmap, start, end)) 18562306a36Sopenharmony_ci ext4_warning(sb, "Inode bitmap not in group (block %llu)", 18662306a36Sopenharmony_ci (unsigned long long)input->inode_bitmap); 18762306a36Sopenharmony_ci else if (outside(input->inode_table, start, end) || 18862306a36Sopenharmony_ci outside(itend - 1, start, end)) 18962306a36Sopenharmony_ci ext4_warning(sb, "Inode table not in group (blocks %llu-%llu)", 19062306a36Sopenharmony_ci (unsigned long long)input->inode_table, itend - 1); 19162306a36Sopenharmony_ci else if (input->inode_bitmap == input->block_bitmap) 19262306a36Sopenharmony_ci ext4_warning(sb, "Block bitmap same as inode bitmap (%llu)", 19362306a36Sopenharmony_ci (unsigned long long)input->block_bitmap); 19462306a36Sopenharmony_ci else if (inside(input->block_bitmap, input->inode_table, itend)) 19562306a36Sopenharmony_ci ext4_warning(sb, "Block bitmap (%llu) in inode table " 19662306a36Sopenharmony_ci "(%llu-%llu)", 19762306a36Sopenharmony_ci (unsigned long long)input->block_bitmap, 19862306a36Sopenharmony_ci (unsigned long long)input->inode_table, itend - 1); 19962306a36Sopenharmony_ci else if (inside(input->inode_bitmap, input->inode_table, itend)) 20062306a36Sopenharmony_ci ext4_warning(sb, "Inode bitmap (%llu) in inode table " 20162306a36Sopenharmony_ci "(%llu-%llu)", 20262306a36Sopenharmony_ci (unsigned long long)input->inode_bitmap, 20362306a36Sopenharmony_ci (unsigned long long)input->inode_table, itend - 1); 20462306a36Sopenharmony_ci else if (inside(input->block_bitmap, start, metaend)) 20562306a36Sopenharmony_ci ext4_warning(sb, "Block bitmap (%llu) in GDT table (%llu-%llu)", 20662306a36Sopenharmony_ci (unsigned long long)input->block_bitmap, 20762306a36Sopenharmony_ci start, metaend - 1); 20862306a36Sopenharmony_ci else if (inside(input->inode_bitmap, start, metaend)) 20962306a36Sopenharmony_ci ext4_warning(sb, "Inode bitmap (%llu) in GDT table (%llu-%llu)", 21062306a36Sopenharmony_ci (unsigned long long)input->inode_bitmap, 21162306a36Sopenharmony_ci start, metaend - 1); 21262306a36Sopenharmony_ci else if (inside(input->inode_table, start, metaend) || 21362306a36Sopenharmony_ci inside(itend - 1, start, metaend)) 21462306a36Sopenharmony_ci ext4_warning(sb, "Inode table (%llu-%llu) overlaps GDT table " 21562306a36Sopenharmony_ci "(%llu-%llu)", 21662306a36Sopenharmony_ci (unsigned long long)input->inode_table, 21762306a36Sopenharmony_ci itend - 1, start, metaend - 1); 21862306a36Sopenharmony_ci else 21962306a36Sopenharmony_ci err = 0; 22062306a36Sopenharmony_ci brelse(bh); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return err; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* 22662306a36Sopenharmony_ci * ext4_new_flex_group_data is used by 64bit-resize interface to add a flex 22762306a36Sopenharmony_ci * group each time. 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_cistruct ext4_new_flex_group_data { 23062306a36Sopenharmony_ci struct ext4_new_group_data *groups; /* new_group_data for groups 23162306a36Sopenharmony_ci in the flex group */ 23262306a36Sopenharmony_ci __u16 *bg_flags; /* block group flags of groups 23362306a36Sopenharmony_ci in @groups */ 23462306a36Sopenharmony_ci ext4_group_t resize_bg; /* number of allocated 23562306a36Sopenharmony_ci new_group_data */ 23662306a36Sopenharmony_ci ext4_group_t count; /* number of groups in @groups 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* 24162306a36Sopenharmony_ci * Avoiding memory allocation failures due to too many groups added each time. 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_ci#define MAX_RESIZE_BG 16384 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* 24662306a36Sopenharmony_ci * alloc_flex_gd() allocates a ext4_new_flex_group_data with size of 24762306a36Sopenharmony_ci * @flexbg_size. 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * Returns NULL on failure otherwise address of the allocated structure. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_cistatic struct ext4_new_flex_group_data *alloc_flex_gd(unsigned int flexbg_size) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct ext4_new_flex_group_data *flex_gd; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci flex_gd = kmalloc(sizeof(*flex_gd), GFP_NOFS); 25662306a36Sopenharmony_ci if (flex_gd == NULL) 25762306a36Sopenharmony_ci goto out3; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (unlikely(flexbg_size > MAX_RESIZE_BG)) 26062306a36Sopenharmony_ci flex_gd->resize_bg = MAX_RESIZE_BG; 26162306a36Sopenharmony_ci else 26262306a36Sopenharmony_ci flex_gd->resize_bg = flexbg_size; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci flex_gd->groups = kmalloc_array(flex_gd->resize_bg, 26562306a36Sopenharmony_ci sizeof(struct ext4_new_group_data), 26662306a36Sopenharmony_ci GFP_NOFS); 26762306a36Sopenharmony_ci if (flex_gd->groups == NULL) 26862306a36Sopenharmony_ci goto out2; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci flex_gd->bg_flags = kmalloc_array(flex_gd->resize_bg, sizeof(__u16), 27162306a36Sopenharmony_ci GFP_NOFS); 27262306a36Sopenharmony_ci if (flex_gd->bg_flags == NULL) 27362306a36Sopenharmony_ci goto out1; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return flex_gd; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ciout1: 27862306a36Sopenharmony_ci kfree(flex_gd->groups); 27962306a36Sopenharmony_ciout2: 28062306a36Sopenharmony_ci kfree(flex_gd); 28162306a36Sopenharmony_ciout3: 28262306a36Sopenharmony_ci return NULL; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic void free_flex_gd(struct ext4_new_flex_group_data *flex_gd) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci kfree(flex_gd->bg_flags); 28862306a36Sopenharmony_ci kfree(flex_gd->groups); 28962306a36Sopenharmony_ci kfree(flex_gd); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* 29362306a36Sopenharmony_ci * ext4_alloc_group_tables() allocates block bitmaps, inode bitmaps 29462306a36Sopenharmony_ci * and inode tables for a flex group. 29562306a36Sopenharmony_ci * 29662306a36Sopenharmony_ci * This function is used by 64bit-resize. Note that this function allocates 29762306a36Sopenharmony_ci * group tables from the 1st group of groups contained by @flexgd, which may 29862306a36Sopenharmony_ci * be a partial of a flex group. 29962306a36Sopenharmony_ci * 30062306a36Sopenharmony_ci * @sb: super block of fs to which the groups belongs 30162306a36Sopenharmony_ci * 30262306a36Sopenharmony_ci * Returns 0 on a successful allocation of the metadata blocks in the 30362306a36Sopenharmony_ci * block group. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_cistatic int ext4_alloc_group_tables(struct super_block *sb, 30662306a36Sopenharmony_ci struct ext4_new_flex_group_data *flex_gd, 30762306a36Sopenharmony_ci unsigned int flexbg_size) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct ext4_new_group_data *group_data = flex_gd->groups; 31062306a36Sopenharmony_ci ext4_fsblk_t start_blk; 31162306a36Sopenharmony_ci ext4_fsblk_t last_blk; 31262306a36Sopenharmony_ci ext4_group_t src_group; 31362306a36Sopenharmony_ci ext4_group_t bb_index = 0; 31462306a36Sopenharmony_ci ext4_group_t ib_index = 0; 31562306a36Sopenharmony_ci ext4_group_t it_index = 0; 31662306a36Sopenharmony_ci ext4_group_t group; 31762306a36Sopenharmony_ci ext4_group_t last_group; 31862306a36Sopenharmony_ci unsigned overhead; 31962306a36Sopenharmony_ci __u16 uninit_mask = (flexbg_size > 1) ? ~EXT4_BG_BLOCK_UNINIT : ~0; 32062306a36Sopenharmony_ci int i; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci BUG_ON(flex_gd->count == 0 || group_data == NULL); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci src_group = group_data[0].group; 32562306a36Sopenharmony_ci last_group = src_group + flex_gd->count - 1; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci BUG_ON((flexbg_size > 1) && ((src_group & ~(flexbg_size - 1)) != 32862306a36Sopenharmony_ci (last_group & ~(flexbg_size - 1)))); 32962306a36Sopenharmony_cinext_group: 33062306a36Sopenharmony_ci group = group_data[0].group; 33162306a36Sopenharmony_ci if (src_group >= group_data[0].group + flex_gd->count) 33262306a36Sopenharmony_ci return -ENOSPC; 33362306a36Sopenharmony_ci start_blk = ext4_group_first_block_no(sb, src_group); 33462306a36Sopenharmony_ci last_blk = start_blk + group_data[src_group - group].blocks_count; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci overhead = ext4_group_overhead_blocks(sb, src_group); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci start_blk += overhead; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* We collect contiguous blocks as much as possible. */ 34162306a36Sopenharmony_ci src_group++; 34262306a36Sopenharmony_ci for (; src_group <= last_group; src_group++) { 34362306a36Sopenharmony_ci overhead = ext4_group_overhead_blocks(sb, src_group); 34462306a36Sopenharmony_ci if (overhead == 0) 34562306a36Sopenharmony_ci last_blk += group_data[src_group - group].blocks_count; 34662306a36Sopenharmony_ci else 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* Allocate block bitmaps */ 35162306a36Sopenharmony_ci for (; bb_index < flex_gd->count; bb_index++) { 35262306a36Sopenharmony_ci if (start_blk >= last_blk) 35362306a36Sopenharmony_ci goto next_group; 35462306a36Sopenharmony_ci group_data[bb_index].block_bitmap = start_blk++; 35562306a36Sopenharmony_ci group = ext4_get_group_number(sb, start_blk - 1); 35662306a36Sopenharmony_ci group -= group_data[0].group; 35762306a36Sopenharmony_ci group_data[group].mdata_blocks++; 35862306a36Sopenharmony_ci flex_gd->bg_flags[group] &= uninit_mask; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Allocate inode bitmaps */ 36262306a36Sopenharmony_ci for (; ib_index < flex_gd->count; ib_index++) { 36362306a36Sopenharmony_ci if (start_blk >= last_blk) 36462306a36Sopenharmony_ci goto next_group; 36562306a36Sopenharmony_ci group_data[ib_index].inode_bitmap = start_blk++; 36662306a36Sopenharmony_ci group = ext4_get_group_number(sb, start_blk - 1); 36762306a36Sopenharmony_ci group -= group_data[0].group; 36862306a36Sopenharmony_ci group_data[group].mdata_blocks++; 36962306a36Sopenharmony_ci flex_gd->bg_flags[group] &= uninit_mask; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Allocate inode tables */ 37362306a36Sopenharmony_ci for (; it_index < flex_gd->count; it_index++) { 37462306a36Sopenharmony_ci unsigned int itb = EXT4_SB(sb)->s_itb_per_group; 37562306a36Sopenharmony_ci ext4_fsblk_t next_group_start; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (start_blk + itb > last_blk) 37862306a36Sopenharmony_ci goto next_group; 37962306a36Sopenharmony_ci group_data[it_index].inode_table = start_blk; 38062306a36Sopenharmony_ci group = ext4_get_group_number(sb, start_blk); 38162306a36Sopenharmony_ci next_group_start = ext4_group_first_block_no(sb, group + 1); 38262306a36Sopenharmony_ci group -= group_data[0].group; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (start_blk + itb > next_group_start) { 38562306a36Sopenharmony_ci flex_gd->bg_flags[group + 1] &= uninit_mask; 38662306a36Sopenharmony_ci overhead = start_blk + itb - next_group_start; 38762306a36Sopenharmony_ci group_data[group + 1].mdata_blocks += overhead; 38862306a36Sopenharmony_ci itb -= overhead; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci group_data[group].mdata_blocks += itb; 39262306a36Sopenharmony_ci flex_gd->bg_flags[group] &= uninit_mask; 39362306a36Sopenharmony_ci start_blk += EXT4_SB(sb)->s_itb_per_group; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* Update free clusters count to exclude metadata blocks */ 39762306a36Sopenharmony_ci for (i = 0; i < flex_gd->count; i++) { 39862306a36Sopenharmony_ci group_data[i].free_clusters_count -= 39962306a36Sopenharmony_ci EXT4_NUM_B2C(EXT4_SB(sb), 40062306a36Sopenharmony_ci group_data[i].mdata_blocks); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (test_opt(sb, DEBUG)) { 40462306a36Sopenharmony_ci int i; 40562306a36Sopenharmony_ci group = group_data[0].group; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci printk(KERN_DEBUG "EXT4-fs: adding a flex group with " 40862306a36Sopenharmony_ci "%u groups, flexbg size is %u:\n", flex_gd->count, 40962306a36Sopenharmony_ci flexbg_size); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci for (i = 0; i < flex_gd->count; i++) { 41262306a36Sopenharmony_ci ext4_debug( 41362306a36Sopenharmony_ci "adding %s group %u: %u blocks (%u free, %u mdata blocks)\n", 41462306a36Sopenharmony_ci ext4_bg_has_super(sb, group + i) ? "normal" : 41562306a36Sopenharmony_ci "no-super", group + i, 41662306a36Sopenharmony_ci group_data[i].blocks_count, 41762306a36Sopenharmony_ci group_data[i].free_clusters_count, 41862306a36Sopenharmony_ci group_data[i].mdata_blocks); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci return 0; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic struct buffer_head *bclean(handle_t *handle, struct super_block *sb, 42562306a36Sopenharmony_ci ext4_fsblk_t blk) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct buffer_head *bh; 42862306a36Sopenharmony_ci int err; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci bh = sb_getblk(sb, blk); 43162306a36Sopenharmony_ci if (unlikely(!bh)) 43262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 43362306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 43462306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, bh, EXT4_JTR_NONE); 43562306a36Sopenharmony_ci if (err) { 43662306a36Sopenharmony_ci brelse(bh); 43762306a36Sopenharmony_ci bh = ERR_PTR(err); 43862306a36Sopenharmony_ci } else { 43962306a36Sopenharmony_ci memset(bh->b_data, 0, sb->s_blocksize); 44062306a36Sopenharmony_ci set_buffer_uptodate(bh); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return bh; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int ext4_resize_ensure_credits_batch(handle_t *handle, int credits) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci return ext4_journal_ensure_credits_fn(handle, credits, 44962306a36Sopenharmony_ci EXT4_MAX_TRANS_DATA, 0, 0); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/* 45362306a36Sopenharmony_ci * set_flexbg_block_bitmap() mark clusters [@first_cluster, @last_cluster] used. 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * Helper function for ext4_setup_new_group_blocks() which set . 45662306a36Sopenharmony_ci * 45762306a36Sopenharmony_ci * @sb: super block 45862306a36Sopenharmony_ci * @handle: journal handle 45962306a36Sopenharmony_ci * @flex_gd: flex group data 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_cistatic int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle, 46262306a36Sopenharmony_ci struct ext4_new_flex_group_data *flex_gd, 46362306a36Sopenharmony_ci ext4_fsblk_t first_cluster, ext4_fsblk_t last_cluster) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 46662306a36Sopenharmony_ci ext4_group_t count = last_cluster - first_cluster + 1; 46762306a36Sopenharmony_ci ext4_group_t count2; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci ext4_debug("mark clusters [%llu-%llu] used\n", first_cluster, 47062306a36Sopenharmony_ci last_cluster); 47162306a36Sopenharmony_ci for (count2 = count; count > 0; 47262306a36Sopenharmony_ci count -= count2, first_cluster += count2) { 47362306a36Sopenharmony_ci ext4_fsblk_t start; 47462306a36Sopenharmony_ci struct buffer_head *bh; 47562306a36Sopenharmony_ci ext4_group_t group; 47662306a36Sopenharmony_ci int err; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci group = ext4_get_group_number(sb, EXT4_C2B(sbi, first_cluster)); 47962306a36Sopenharmony_ci start = EXT4_B2C(sbi, ext4_group_first_block_no(sb, group)); 48062306a36Sopenharmony_ci group -= flex_gd->groups[0].group; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci count2 = EXT4_CLUSTERS_PER_GROUP(sb) - (first_cluster - start); 48362306a36Sopenharmony_ci if (count2 > count) 48462306a36Sopenharmony_ci count2 = count; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (flex_gd->bg_flags[group] & EXT4_BG_BLOCK_UNINIT) { 48762306a36Sopenharmony_ci BUG_ON(flex_gd->count > 1); 48862306a36Sopenharmony_ci continue; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci err = ext4_resize_ensure_credits_batch(handle, 1); 49262306a36Sopenharmony_ci if (err < 0) 49362306a36Sopenharmony_ci return err; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci bh = sb_getblk(sb, flex_gd->groups[group].block_bitmap); 49662306a36Sopenharmony_ci if (unlikely(!bh)) 49762306a36Sopenharmony_ci return -ENOMEM; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 50062306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, bh, 50162306a36Sopenharmony_ci EXT4_JTR_NONE); 50262306a36Sopenharmony_ci if (err) { 50362306a36Sopenharmony_ci brelse(bh); 50462306a36Sopenharmony_ci return err; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci ext4_debug("mark block bitmap %#04llx (+%llu/%u)\n", 50762306a36Sopenharmony_ci first_cluster, first_cluster - start, count2); 50862306a36Sopenharmony_ci mb_set_bits(bh->b_data, first_cluster - start, count2); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, bh); 51162306a36Sopenharmony_ci brelse(bh); 51262306a36Sopenharmony_ci if (unlikely(err)) 51362306a36Sopenharmony_ci return err; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/* 52062306a36Sopenharmony_ci * Set up the block and inode bitmaps, and the inode table for the new groups. 52162306a36Sopenharmony_ci * This doesn't need to be part of the main transaction, since we are only 52262306a36Sopenharmony_ci * changing blocks outside the actual filesystem. We still do journaling to 52362306a36Sopenharmony_ci * ensure the recovery is correct in case of a failure just after resize. 52462306a36Sopenharmony_ci * If any part of this fails, we simply abort the resize. 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci * setup_new_flex_group_blocks handles a flex group as follow: 52762306a36Sopenharmony_ci * 1. copy super block and GDT, and initialize group tables if necessary. 52862306a36Sopenharmony_ci * In this step, we only set bits in blocks bitmaps for blocks taken by 52962306a36Sopenharmony_ci * super block and GDT. 53062306a36Sopenharmony_ci * 2. allocate group tables in block bitmaps, that is, set bits in block 53162306a36Sopenharmony_ci * bitmap for blocks taken by group tables. 53262306a36Sopenharmony_ci */ 53362306a36Sopenharmony_cistatic int setup_new_flex_group_blocks(struct super_block *sb, 53462306a36Sopenharmony_ci struct ext4_new_flex_group_data *flex_gd) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci int group_table_count[] = {1, 1, EXT4_SB(sb)->s_itb_per_group}; 53762306a36Sopenharmony_ci ext4_fsblk_t start; 53862306a36Sopenharmony_ci ext4_fsblk_t block; 53962306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 54062306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 54162306a36Sopenharmony_ci struct ext4_new_group_data *group_data = flex_gd->groups; 54262306a36Sopenharmony_ci __u16 *bg_flags = flex_gd->bg_flags; 54362306a36Sopenharmony_ci handle_t *handle; 54462306a36Sopenharmony_ci ext4_group_t group, count; 54562306a36Sopenharmony_ci struct buffer_head *bh = NULL; 54662306a36Sopenharmony_ci int reserved_gdb, i, j, err = 0, err2; 54762306a36Sopenharmony_ci int meta_bg; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci BUG_ON(!flex_gd->count || !group_data || 55062306a36Sopenharmony_ci group_data[0].group != sbi->s_groups_count); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks); 55362306a36Sopenharmony_ci meta_bg = ext4_has_feature_meta_bg(sb); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* This transaction may be extended/restarted along the way */ 55662306a36Sopenharmony_ci handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, EXT4_MAX_TRANS_DATA); 55762306a36Sopenharmony_ci if (IS_ERR(handle)) 55862306a36Sopenharmony_ci return PTR_ERR(handle); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci group = group_data[0].group; 56162306a36Sopenharmony_ci for (i = 0; i < flex_gd->count; i++, group++) { 56262306a36Sopenharmony_ci unsigned long gdblocks; 56362306a36Sopenharmony_ci ext4_grpblk_t overhead; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci gdblocks = ext4_bg_num_gdb(sb, group); 56662306a36Sopenharmony_ci start = ext4_group_first_block_no(sb, group); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (meta_bg == 0 && !ext4_bg_has_super(sb, group)) 56962306a36Sopenharmony_ci goto handle_itb; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (meta_bg == 1) 57262306a36Sopenharmony_ci goto handle_itb; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci block = start + ext4_bg_has_super(sb, group); 57562306a36Sopenharmony_ci /* Copy all of the GDT blocks into the backup in this group */ 57662306a36Sopenharmony_ci for (j = 0; j < gdblocks; j++, block++) { 57762306a36Sopenharmony_ci struct buffer_head *gdb; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ext4_debug("update backup group %#04llx\n", block); 58062306a36Sopenharmony_ci err = ext4_resize_ensure_credits_batch(handle, 1); 58162306a36Sopenharmony_ci if (err < 0) 58262306a36Sopenharmony_ci goto out; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci gdb = sb_getblk(sb, block); 58562306a36Sopenharmony_ci if (unlikely(!gdb)) { 58662306a36Sopenharmony_ci err = -ENOMEM; 58762306a36Sopenharmony_ci goto out; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci BUFFER_TRACE(gdb, "get_write_access"); 59162306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, gdb, 59262306a36Sopenharmony_ci EXT4_JTR_NONE); 59362306a36Sopenharmony_ci if (err) { 59462306a36Sopenharmony_ci brelse(gdb); 59562306a36Sopenharmony_ci goto out; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci memcpy(gdb->b_data, sbi_array_rcu_deref(sbi, 59862306a36Sopenharmony_ci s_group_desc, j)->b_data, gdb->b_size); 59962306a36Sopenharmony_ci set_buffer_uptodate(gdb); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, gdb); 60262306a36Sopenharmony_ci if (unlikely(err)) { 60362306a36Sopenharmony_ci brelse(gdb); 60462306a36Sopenharmony_ci goto out; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci brelse(gdb); 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* Zero out all of the reserved backup group descriptor 61062306a36Sopenharmony_ci * table blocks 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ci if (ext4_bg_has_super(sb, group)) { 61362306a36Sopenharmony_ci err = sb_issue_zeroout(sb, gdblocks + start + 1, 61462306a36Sopenharmony_ci reserved_gdb, GFP_NOFS); 61562306a36Sopenharmony_ci if (err) 61662306a36Sopenharmony_ci goto out; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cihandle_itb: 62062306a36Sopenharmony_ci /* Initialize group tables of the grop @group */ 62162306a36Sopenharmony_ci if (!(bg_flags[i] & EXT4_BG_INODE_ZEROED)) 62262306a36Sopenharmony_ci goto handle_bb; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* Zero out all of the inode table blocks */ 62562306a36Sopenharmony_ci block = group_data[i].inode_table; 62662306a36Sopenharmony_ci ext4_debug("clear inode table blocks %#04llx -> %#04lx\n", 62762306a36Sopenharmony_ci block, sbi->s_itb_per_group); 62862306a36Sopenharmony_ci err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, 62962306a36Sopenharmony_ci GFP_NOFS); 63062306a36Sopenharmony_ci if (err) 63162306a36Sopenharmony_ci goto out; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cihandle_bb: 63462306a36Sopenharmony_ci if (bg_flags[i] & EXT4_BG_BLOCK_UNINIT) 63562306a36Sopenharmony_ci goto handle_ib; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Initialize block bitmap of the @group */ 63862306a36Sopenharmony_ci block = group_data[i].block_bitmap; 63962306a36Sopenharmony_ci err = ext4_resize_ensure_credits_batch(handle, 1); 64062306a36Sopenharmony_ci if (err < 0) 64162306a36Sopenharmony_ci goto out; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci bh = bclean(handle, sb, block); 64462306a36Sopenharmony_ci if (IS_ERR(bh)) { 64562306a36Sopenharmony_ci err = PTR_ERR(bh); 64662306a36Sopenharmony_ci goto out; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci overhead = ext4_group_overhead_blocks(sb, group); 64962306a36Sopenharmony_ci if (overhead != 0) { 65062306a36Sopenharmony_ci ext4_debug("mark backup superblock %#04llx (+0)\n", 65162306a36Sopenharmony_ci start); 65262306a36Sopenharmony_ci mb_set_bits(bh->b_data, 0, 65362306a36Sopenharmony_ci EXT4_NUM_B2C(sbi, overhead)); 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci ext4_mark_bitmap_end(EXT4_B2C(sbi, group_data[i].blocks_count), 65662306a36Sopenharmony_ci sb->s_blocksize * 8, bh->b_data); 65762306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, bh); 65862306a36Sopenharmony_ci brelse(bh); 65962306a36Sopenharmony_ci if (err) 66062306a36Sopenharmony_ci goto out; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cihandle_ib: 66362306a36Sopenharmony_ci if (bg_flags[i] & EXT4_BG_INODE_UNINIT) 66462306a36Sopenharmony_ci continue; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* Initialize inode bitmap of the @group */ 66762306a36Sopenharmony_ci block = group_data[i].inode_bitmap; 66862306a36Sopenharmony_ci err = ext4_resize_ensure_credits_batch(handle, 1); 66962306a36Sopenharmony_ci if (err < 0) 67062306a36Sopenharmony_ci goto out; 67162306a36Sopenharmony_ci /* Mark unused entries in inode bitmap used */ 67262306a36Sopenharmony_ci bh = bclean(handle, sb, block); 67362306a36Sopenharmony_ci if (IS_ERR(bh)) { 67462306a36Sopenharmony_ci err = PTR_ERR(bh); 67562306a36Sopenharmony_ci goto out; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), 67962306a36Sopenharmony_ci sb->s_blocksize * 8, bh->b_data); 68062306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, bh); 68162306a36Sopenharmony_ci brelse(bh); 68262306a36Sopenharmony_ci if (err) 68362306a36Sopenharmony_ci goto out; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Mark group tables in block bitmap */ 68762306a36Sopenharmony_ci for (j = 0; j < GROUP_TABLE_COUNT; j++) { 68862306a36Sopenharmony_ci count = group_table_count[j]; 68962306a36Sopenharmony_ci start = (&group_data[0].block_bitmap)[j]; 69062306a36Sopenharmony_ci block = start; 69162306a36Sopenharmony_ci for (i = 1; i < flex_gd->count; i++) { 69262306a36Sopenharmony_ci block += group_table_count[j]; 69362306a36Sopenharmony_ci if (block == (&group_data[i].block_bitmap)[j]) { 69462306a36Sopenharmony_ci count += group_table_count[j]; 69562306a36Sopenharmony_ci continue; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci err = set_flexbg_block_bitmap(sb, handle, 69862306a36Sopenharmony_ci flex_gd, 69962306a36Sopenharmony_ci EXT4_B2C(sbi, start), 70062306a36Sopenharmony_ci EXT4_B2C(sbi, 70162306a36Sopenharmony_ci start + count 70262306a36Sopenharmony_ci - 1)); 70362306a36Sopenharmony_ci if (err) 70462306a36Sopenharmony_ci goto out; 70562306a36Sopenharmony_ci count = group_table_count[j]; 70662306a36Sopenharmony_ci start = (&group_data[i].block_bitmap)[j]; 70762306a36Sopenharmony_ci block = start; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (count) { 71162306a36Sopenharmony_ci err = set_flexbg_block_bitmap(sb, handle, 71262306a36Sopenharmony_ci flex_gd, 71362306a36Sopenharmony_ci EXT4_B2C(sbi, start), 71462306a36Sopenharmony_ci EXT4_B2C(sbi, 71562306a36Sopenharmony_ci start + count 71662306a36Sopenharmony_ci - 1)); 71762306a36Sopenharmony_ci if (err) 71862306a36Sopenharmony_ci goto out; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ciout: 72362306a36Sopenharmony_ci err2 = ext4_journal_stop(handle); 72462306a36Sopenharmony_ci if (err2 && !err) 72562306a36Sopenharmony_ci err = err2; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return err; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci/* 73162306a36Sopenharmony_ci * Iterate through the groups which hold BACKUP superblock/GDT copies in an 73262306a36Sopenharmony_ci * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before 73362306a36Sopenharmony_ci * calling this for the first time. In a sparse filesystem it will be the 73462306a36Sopenharmony_ci * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... 73562306a36Sopenharmony_ci * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... 73662306a36Sopenharmony_ci */ 73762306a36Sopenharmony_ciunsigned int ext4_list_backups(struct super_block *sb, unsigned int *three, 73862306a36Sopenharmony_ci unsigned int *five, unsigned int *seven) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct ext4_super_block *es = EXT4_SB(sb)->s_es; 74162306a36Sopenharmony_ci unsigned int *min = three; 74262306a36Sopenharmony_ci int mult = 3; 74362306a36Sopenharmony_ci unsigned int ret; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (ext4_has_feature_sparse_super2(sb)) { 74662306a36Sopenharmony_ci do { 74762306a36Sopenharmony_ci if (*min > 2) 74862306a36Sopenharmony_ci return UINT_MAX; 74962306a36Sopenharmony_ci ret = le32_to_cpu(es->s_backup_bgs[*min - 1]); 75062306a36Sopenharmony_ci *min += 1; 75162306a36Sopenharmony_ci } while (!ret); 75262306a36Sopenharmony_ci return ret; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (!ext4_has_feature_sparse_super(sb)) { 75662306a36Sopenharmony_ci ret = *min; 75762306a36Sopenharmony_ci *min += 1; 75862306a36Sopenharmony_ci return ret; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (*five < *min) { 76262306a36Sopenharmony_ci min = five; 76362306a36Sopenharmony_ci mult = 5; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci if (*seven < *min) { 76662306a36Sopenharmony_ci min = seven; 76762306a36Sopenharmony_ci mult = 7; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci ret = *min; 77162306a36Sopenharmony_ci *min *= mult; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return ret; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci/* 77762306a36Sopenharmony_ci * Check that all of the backup GDT blocks are held in the primary GDT block. 77862306a36Sopenharmony_ci * It is assumed that they are stored in group order. Returns the number of 77962306a36Sopenharmony_ci * groups in current filesystem that have BACKUPS, or -ve error code. 78062306a36Sopenharmony_ci */ 78162306a36Sopenharmony_cistatic int verify_reserved_gdb(struct super_block *sb, 78262306a36Sopenharmony_ci ext4_group_t end, 78362306a36Sopenharmony_ci struct buffer_head *primary) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci const ext4_fsblk_t blk = primary->b_blocknr; 78662306a36Sopenharmony_ci unsigned three = 1; 78762306a36Sopenharmony_ci unsigned five = 5; 78862306a36Sopenharmony_ci unsigned seven = 7; 78962306a36Sopenharmony_ci unsigned grp; 79062306a36Sopenharmony_ci __le32 *p = (__le32 *)primary->b_data; 79162306a36Sopenharmony_ci int gdbackups = 0; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) { 79462306a36Sopenharmony_ci if (le32_to_cpu(*p++) != 79562306a36Sopenharmony_ci grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){ 79662306a36Sopenharmony_ci ext4_warning(sb, "reserved GDT %llu" 79762306a36Sopenharmony_ci " missing grp %d (%llu)", 79862306a36Sopenharmony_ci blk, grp, 79962306a36Sopenharmony_ci grp * 80062306a36Sopenharmony_ci (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) + 80162306a36Sopenharmony_ci blk); 80262306a36Sopenharmony_ci return -EINVAL; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci if (++gdbackups > EXT4_ADDR_PER_BLOCK(sb)) 80562306a36Sopenharmony_ci return -EFBIG; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci return gdbackups; 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci/* 81262306a36Sopenharmony_ci * Called when we need to bring a reserved group descriptor table block into 81362306a36Sopenharmony_ci * use from the resize inode. The primary copy of the new GDT block currently 81462306a36Sopenharmony_ci * is an indirect block (under the double indirect block in the resize inode). 81562306a36Sopenharmony_ci * The new backup GDT blocks will be stored as leaf blocks in this indirect 81662306a36Sopenharmony_ci * block, in group order. Even though we know all the block numbers we need, 81762306a36Sopenharmony_ci * we check to ensure that the resize inode has actually reserved these blocks. 81862306a36Sopenharmony_ci * 81962306a36Sopenharmony_ci * Don't need to update the block bitmaps because the blocks are still in use. 82062306a36Sopenharmony_ci * 82162306a36Sopenharmony_ci * We get all of the error cases out of the way, so that we are sure to not 82262306a36Sopenharmony_ci * fail once we start modifying the data on disk, because JBD has no rollback. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_cistatic int add_new_gdb(handle_t *handle, struct inode *inode, 82562306a36Sopenharmony_ci ext4_group_t group) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 82862306a36Sopenharmony_ci struct ext4_super_block *es = EXT4_SB(sb)->s_es; 82962306a36Sopenharmony_ci unsigned long gdb_num = group / EXT4_DESC_PER_BLOCK(sb); 83062306a36Sopenharmony_ci ext4_fsblk_t gdblock = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; 83162306a36Sopenharmony_ci struct buffer_head **o_group_desc, **n_group_desc = NULL; 83262306a36Sopenharmony_ci struct buffer_head *dind = NULL; 83362306a36Sopenharmony_ci struct buffer_head *gdb_bh = NULL; 83462306a36Sopenharmony_ci int gdbackups; 83562306a36Sopenharmony_ci struct ext4_iloc iloc = { .bh = NULL }; 83662306a36Sopenharmony_ci __le32 *data; 83762306a36Sopenharmony_ci int err; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (test_opt(sb, DEBUG)) 84062306a36Sopenharmony_ci printk(KERN_DEBUG 84162306a36Sopenharmony_ci "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n", 84262306a36Sopenharmony_ci gdb_num); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci gdb_bh = ext4_sb_bread(sb, gdblock, 0); 84562306a36Sopenharmony_ci if (IS_ERR(gdb_bh)) 84662306a36Sopenharmony_ci return PTR_ERR(gdb_bh); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci gdbackups = verify_reserved_gdb(sb, group, gdb_bh); 84962306a36Sopenharmony_ci if (gdbackups < 0) { 85062306a36Sopenharmony_ci err = gdbackups; 85162306a36Sopenharmony_ci goto errout; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK; 85562306a36Sopenharmony_ci dind = ext4_sb_bread(sb, le32_to_cpu(*data), 0); 85662306a36Sopenharmony_ci if (IS_ERR(dind)) { 85762306a36Sopenharmony_ci err = PTR_ERR(dind); 85862306a36Sopenharmony_ci dind = NULL; 85962306a36Sopenharmony_ci goto errout; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci data = (__le32 *)dind->b_data; 86362306a36Sopenharmony_ci if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) { 86462306a36Sopenharmony_ci ext4_warning(sb, "new group %u GDT block %llu not reserved", 86562306a36Sopenharmony_ci group, gdblock); 86662306a36Sopenharmony_ci err = -EINVAL; 86762306a36Sopenharmony_ci goto errout; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); 87162306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, EXT4_SB(sb)->s_sbh, 87262306a36Sopenharmony_ci EXT4_JTR_NONE); 87362306a36Sopenharmony_ci if (unlikely(err)) 87462306a36Sopenharmony_ci goto errout; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci BUFFER_TRACE(gdb_bh, "get_write_access"); 87762306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, gdb_bh, EXT4_JTR_NONE); 87862306a36Sopenharmony_ci if (unlikely(err)) 87962306a36Sopenharmony_ci goto errout; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci BUFFER_TRACE(dind, "get_write_access"); 88262306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, dind, EXT4_JTR_NONE); 88362306a36Sopenharmony_ci if (unlikely(err)) { 88462306a36Sopenharmony_ci ext4_std_error(sb, err); 88562306a36Sopenharmony_ci goto errout; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* ext4_reserve_inode_write() gets a reference on the iloc */ 88962306a36Sopenharmony_ci err = ext4_reserve_inode_write(handle, inode, &iloc); 89062306a36Sopenharmony_ci if (unlikely(err)) 89162306a36Sopenharmony_ci goto errout; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci n_group_desc = kvmalloc((gdb_num + 1) * sizeof(struct buffer_head *), 89462306a36Sopenharmony_ci GFP_KERNEL); 89562306a36Sopenharmony_ci if (!n_group_desc) { 89662306a36Sopenharmony_ci err = -ENOMEM; 89762306a36Sopenharmony_ci ext4_warning(sb, "not enough memory for %lu groups", 89862306a36Sopenharmony_ci gdb_num + 1); 89962306a36Sopenharmony_ci goto errout; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* 90362306a36Sopenharmony_ci * Finally, we have all of the possible failures behind us... 90462306a36Sopenharmony_ci * 90562306a36Sopenharmony_ci * Remove new GDT block from inode double-indirect block and clear out 90662306a36Sopenharmony_ci * the new GDT block for use (which also "frees" the backup GDT blocks 90762306a36Sopenharmony_ci * from the reserved inode). We don't need to change the bitmaps for 90862306a36Sopenharmony_ci * these blocks, because they are marked as in-use from being in the 90962306a36Sopenharmony_ci * reserved inode, and will become GDT blocks (primary and backup). 91062306a36Sopenharmony_ci */ 91162306a36Sopenharmony_ci data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)] = 0; 91262306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, dind); 91362306a36Sopenharmony_ci if (unlikely(err)) { 91462306a36Sopenharmony_ci ext4_std_error(sb, err); 91562306a36Sopenharmony_ci goto errout; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 91862306a36Sopenharmony_ci (9 - EXT4_SB(sb)->s_cluster_bits); 91962306a36Sopenharmony_ci ext4_mark_iloc_dirty(handle, inode, &iloc); 92062306a36Sopenharmony_ci memset(gdb_bh->b_data, 0, sb->s_blocksize); 92162306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh); 92262306a36Sopenharmony_ci if (unlikely(err)) { 92362306a36Sopenharmony_ci ext4_std_error(sb, err); 92462306a36Sopenharmony_ci iloc.bh = NULL; 92562306a36Sopenharmony_ci goto errout; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci brelse(dind); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci rcu_read_lock(); 93062306a36Sopenharmony_ci o_group_desc = rcu_dereference(EXT4_SB(sb)->s_group_desc); 93162306a36Sopenharmony_ci memcpy(n_group_desc, o_group_desc, 93262306a36Sopenharmony_ci EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); 93362306a36Sopenharmony_ci rcu_read_unlock(); 93462306a36Sopenharmony_ci n_group_desc[gdb_num] = gdb_bh; 93562306a36Sopenharmony_ci rcu_assign_pointer(EXT4_SB(sb)->s_group_desc, n_group_desc); 93662306a36Sopenharmony_ci EXT4_SB(sb)->s_gdb_count++; 93762306a36Sopenharmony_ci ext4_kvfree_array_rcu(o_group_desc); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci lock_buffer(EXT4_SB(sb)->s_sbh); 94062306a36Sopenharmony_ci le16_add_cpu(&es->s_reserved_gdt_blocks, -1); 94162306a36Sopenharmony_ci ext4_superblock_csum_set(sb); 94262306a36Sopenharmony_ci unlock_buffer(EXT4_SB(sb)->s_sbh); 94362306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); 94462306a36Sopenharmony_ci if (err) 94562306a36Sopenharmony_ci ext4_std_error(sb, err); 94662306a36Sopenharmony_ci return err; 94762306a36Sopenharmony_cierrout: 94862306a36Sopenharmony_ci kvfree(n_group_desc); 94962306a36Sopenharmony_ci brelse(iloc.bh); 95062306a36Sopenharmony_ci brelse(dind); 95162306a36Sopenharmony_ci brelse(gdb_bh); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci ext4_debug("leaving with error %d\n", err); 95462306a36Sopenharmony_ci return err; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci/* 95862306a36Sopenharmony_ci * add_new_gdb_meta_bg is the sister of add_new_gdb. 95962306a36Sopenharmony_ci */ 96062306a36Sopenharmony_cistatic int add_new_gdb_meta_bg(struct super_block *sb, 96162306a36Sopenharmony_ci handle_t *handle, ext4_group_t group) { 96262306a36Sopenharmony_ci ext4_fsblk_t gdblock; 96362306a36Sopenharmony_ci struct buffer_head *gdb_bh; 96462306a36Sopenharmony_ci struct buffer_head **o_group_desc, **n_group_desc; 96562306a36Sopenharmony_ci unsigned long gdb_num = group / EXT4_DESC_PER_BLOCK(sb); 96662306a36Sopenharmony_ci int err; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci gdblock = ext4_meta_bg_first_block_no(sb, group) + 96962306a36Sopenharmony_ci ext4_bg_has_super(sb, group); 97062306a36Sopenharmony_ci gdb_bh = ext4_sb_bread(sb, gdblock, 0); 97162306a36Sopenharmony_ci if (IS_ERR(gdb_bh)) 97262306a36Sopenharmony_ci return PTR_ERR(gdb_bh); 97362306a36Sopenharmony_ci n_group_desc = kvmalloc((gdb_num + 1) * sizeof(struct buffer_head *), 97462306a36Sopenharmony_ci GFP_KERNEL); 97562306a36Sopenharmony_ci if (!n_group_desc) { 97662306a36Sopenharmony_ci brelse(gdb_bh); 97762306a36Sopenharmony_ci err = -ENOMEM; 97862306a36Sopenharmony_ci ext4_warning(sb, "not enough memory for %lu groups", 97962306a36Sopenharmony_ci gdb_num + 1); 98062306a36Sopenharmony_ci return err; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci rcu_read_lock(); 98462306a36Sopenharmony_ci o_group_desc = rcu_dereference(EXT4_SB(sb)->s_group_desc); 98562306a36Sopenharmony_ci memcpy(n_group_desc, o_group_desc, 98662306a36Sopenharmony_ci EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); 98762306a36Sopenharmony_ci rcu_read_unlock(); 98862306a36Sopenharmony_ci n_group_desc[gdb_num] = gdb_bh; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci BUFFER_TRACE(gdb_bh, "get_write_access"); 99162306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, gdb_bh, EXT4_JTR_NONE); 99262306a36Sopenharmony_ci if (err) { 99362306a36Sopenharmony_ci kvfree(n_group_desc); 99462306a36Sopenharmony_ci brelse(gdb_bh); 99562306a36Sopenharmony_ci return err; 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci rcu_assign_pointer(EXT4_SB(sb)->s_group_desc, n_group_desc); 99962306a36Sopenharmony_ci EXT4_SB(sb)->s_gdb_count++; 100062306a36Sopenharmony_ci ext4_kvfree_array_rcu(o_group_desc); 100162306a36Sopenharmony_ci return err; 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci/* 100562306a36Sopenharmony_ci * Called when we are adding a new group which has a backup copy of each of 100662306a36Sopenharmony_ci * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks. 100762306a36Sopenharmony_ci * We need to add these reserved backup GDT blocks to the resize inode, so 100862306a36Sopenharmony_ci * that they are kept for future resizing and not allocated to files. 100962306a36Sopenharmony_ci * 101062306a36Sopenharmony_ci * Each reserved backup GDT block will go into a different indirect block. 101162306a36Sopenharmony_ci * The indirect blocks are actually the primary reserved GDT blocks, 101262306a36Sopenharmony_ci * so we know in advance what their block numbers are. We only get the 101362306a36Sopenharmony_ci * double-indirect block to verify it is pointing to the primary reserved 101462306a36Sopenharmony_ci * GDT blocks so we don't overwrite a data block by accident. The reserved 101562306a36Sopenharmony_ci * backup GDT blocks are stored in their reserved primary GDT block. 101662306a36Sopenharmony_ci */ 101762306a36Sopenharmony_cistatic int reserve_backup_gdb(handle_t *handle, struct inode *inode, 101862306a36Sopenharmony_ci ext4_group_t group) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 102162306a36Sopenharmony_ci int reserved_gdb =le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks); 102262306a36Sopenharmony_ci int cluster_bits = EXT4_SB(sb)->s_cluster_bits; 102362306a36Sopenharmony_ci struct buffer_head **primary; 102462306a36Sopenharmony_ci struct buffer_head *dind; 102562306a36Sopenharmony_ci struct ext4_iloc iloc; 102662306a36Sopenharmony_ci ext4_fsblk_t blk; 102762306a36Sopenharmony_ci __le32 *data, *end; 102862306a36Sopenharmony_ci int gdbackups = 0; 102962306a36Sopenharmony_ci int res, i; 103062306a36Sopenharmony_ci int err; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci primary = kmalloc_array(reserved_gdb, sizeof(*primary), GFP_NOFS); 103362306a36Sopenharmony_ci if (!primary) 103462306a36Sopenharmony_ci return -ENOMEM; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK; 103762306a36Sopenharmony_ci dind = ext4_sb_bread(sb, le32_to_cpu(*data), 0); 103862306a36Sopenharmony_ci if (IS_ERR(dind)) { 103962306a36Sopenharmony_ci err = PTR_ERR(dind); 104062306a36Sopenharmony_ci dind = NULL; 104162306a36Sopenharmony_ci goto exit_free; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci blk = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + EXT4_SB(sb)->s_gdb_count; 104562306a36Sopenharmony_ci data = (__le32 *)dind->b_data + (EXT4_SB(sb)->s_gdb_count % 104662306a36Sopenharmony_ci EXT4_ADDR_PER_BLOCK(sb)); 104762306a36Sopenharmony_ci end = (__le32 *)dind->b_data + EXT4_ADDR_PER_BLOCK(sb); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* Get each reserved primary GDT block and verify it holds backups */ 105062306a36Sopenharmony_ci for (res = 0; res < reserved_gdb; res++, blk++) { 105162306a36Sopenharmony_ci if (le32_to_cpu(*data) != blk) { 105262306a36Sopenharmony_ci ext4_warning(sb, "reserved block %llu" 105362306a36Sopenharmony_ci " not at offset %ld", 105462306a36Sopenharmony_ci blk, 105562306a36Sopenharmony_ci (long)(data - (__le32 *)dind->b_data)); 105662306a36Sopenharmony_ci err = -EINVAL; 105762306a36Sopenharmony_ci goto exit_bh; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci primary[res] = ext4_sb_bread(sb, blk, 0); 106062306a36Sopenharmony_ci if (IS_ERR(primary[res])) { 106162306a36Sopenharmony_ci err = PTR_ERR(primary[res]); 106262306a36Sopenharmony_ci primary[res] = NULL; 106362306a36Sopenharmony_ci goto exit_bh; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci gdbackups = verify_reserved_gdb(sb, group, primary[res]); 106662306a36Sopenharmony_ci if (gdbackups < 0) { 106762306a36Sopenharmony_ci brelse(primary[res]); 106862306a36Sopenharmony_ci err = gdbackups; 106962306a36Sopenharmony_ci goto exit_bh; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci if (++data >= end) 107262306a36Sopenharmony_ci data = (__le32 *)dind->b_data; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci for (i = 0; i < reserved_gdb; i++) { 107662306a36Sopenharmony_ci BUFFER_TRACE(primary[i], "get_write_access"); 107762306a36Sopenharmony_ci if ((err = ext4_journal_get_write_access(handle, sb, primary[i], 107862306a36Sopenharmony_ci EXT4_JTR_NONE))) 107962306a36Sopenharmony_ci goto exit_bh; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if ((err = ext4_reserve_inode_write(handle, inode, &iloc))) 108362306a36Sopenharmony_ci goto exit_bh; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* 108662306a36Sopenharmony_ci * Finally we can add each of the reserved backup GDT blocks from 108762306a36Sopenharmony_ci * the new group to its reserved primary GDT block. 108862306a36Sopenharmony_ci */ 108962306a36Sopenharmony_ci blk = group * EXT4_BLOCKS_PER_GROUP(sb); 109062306a36Sopenharmony_ci for (i = 0; i < reserved_gdb; i++) { 109162306a36Sopenharmony_ci int err2; 109262306a36Sopenharmony_ci data = (__le32 *)primary[i]->b_data; 109362306a36Sopenharmony_ci /* printk("reserving backup %lu[%u] = %lu\n", 109462306a36Sopenharmony_ci primary[i]->b_blocknr, gdbackups, 109562306a36Sopenharmony_ci blk + primary[i]->b_blocknr); */ 109662306a36Sopenharmony_ci data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr); 109762306a36Sopenharmony_ci err2 = ext4_handle_dirty_metadata(handle, NULL, primary[i]); 109862306a36Sopenharmony_ci if (!err) 109962306a36Sopenharmony_ci err = err2; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci inode->i_blocks += reserved_gdb * sb->s_blocksize >> (9 - cluster_bits); 110362306a36Sopenharmony_ci ext4_mark_iloc_dirty(handle, inode, &iloc); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ciexit_bh: 110662306a36Sopenharmony_ci while (--res >= 0) 110762306a36Sopenharmony_ci brelse(primary[res]); 110862306a36Sopenharmony_ci brelse(dind); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ciexit_free: 111162306a36Sopenharmony_ci kfree(primary); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci return err; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic inline void ext4_set_block_group_nr(struct super_block *sb, char *data, 111762306a36Sopenharmony_ci ext4_group_t group) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci struct ext4_super_block *es = (struct ext4_super_block *) data; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci es->s_block_group_nr = cpu_to_le16(group); 112262306a36Sopenharmony_ci if (ext4_has_metadata_csum(sb)) 112362306a36Sopenharmony_ci es->s_checksum = ext4_superblock_csum(sb, es); 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci/* 112762306a36Sopenharmony_ci * Update the backup copies of the ext4 metadata. These don't need to be part 112862306a36Sopenharmony_ci * of the main resize transaction, because e2fsck will re-write them if there 112962306a36Sopenharmony_ci * is a problem (basically only OOM will cause a problem). However, we 113062306a36Sopenharmony_ci * _should_ update the backups if possible, in case the primary gets trashed 113162306a36Sopenharmony_ci * for some reason and we need to run e2fsck from a backup superblock. The 113262306a36Sopenharmony_ci * important part is that the new block and inode counts are in the backup 113362306a36Sopenharmony_ci * superblocks, and the location of the new group metadata in the GDT backups. 113462306a36Sopenharmony_ci * 113562306a36Sopenharmony_ci * We do not need take the s_resize_lock for this, because these 113662306a36Sopenharmony_ci * blocks are not otherwise touched by the filesystem code when it is 113762306a36Sopenharmony_ci * mounted. We don't need to worry about last changing from 113862306a36Sopenharmony_ci * sbi->s_groups_count, because the worst that can happen is that we 113962306a36Sopenharmony_ci * do not copy the full number of backups at this time. The resize 114062306a36Sopenharmony_ci * which changed s_groups_count will backup again. 114162306a36Sopenharmony_ci */ 114262306a36Sopenharmony_cistatic void update_backups(struct super_block *sb, sector_t blk_off, char *data, 114362306a36Sopenharmony_ci int size, int meta_bg) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 114662306a36Sopenharmony_ci ext4_group_t last; 114762306a36Sopenharmony_ci const int bpg = EXT4_BLOCKS_PER_GROUP(sb); 114862306a36Sopenharmony_ci unsigned three = 1; 114962306a36Sopenharmony_ci unsigned five = 5; 115062306a36Sopenharmony_ci unsigned seven = 7; 115162306a36Sopenharmony_ci ext4_group_t group = 0; 115262306a36Sopenharmony_ci int rest = sb->s_blocksize - size; 115362306a36Sopenharmony_ci handle_t *handle; 115462306a36Sopenharmony_ci int err = 0, err2; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, EXT4_MAX_TRANS_DATA); 115762306a36Sopenharmony_ci if (IS_ERR(handle)) { 115862306a36Sopenharmony_ci group = 1; 115962306a36Sopenharmony_ci err = PTR_ERR(handle); 116062306a36Sopenharmony_ci goto exit_err; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci if (meta_bg == 0) { 116462306a36Sopenharmony_ci group = ext4_list_backups(sb, &three, &five, &seven); 116562306a36Sopenharmony_ci last = sbi->s_groups_count; 116662306a36Sopenharmony_ci } else { 116762306a36Sopenharmony_ci group = ext4_get_group_number(sb, blk_off) + 1; 116862306a36Sopenharmony_ci last = (ext4_group_t)(group + EXT4_DESC_PER_BLOCK(sb) - 2); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci while (group < sbi->s_groups_count) { 117262306a36Sopenharmony_ci struct buffer_head *bh; 117362306a36Sopenharmony_ci ext4_fsblk_t backup_block; 117462306a36Sopenharmony_ci int has_super = ext4_bg_has_super(sb, group); 117562306a36Sopenharmony_ci ext4_fsblk_t first_block = ext4_group_first_block_no(sb, group); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /* Out of journal space, and can't get more - abort - so sad */ 117862306a36Sopenharmony_ci err = ext4_resize_ensure_credits_batch(handle, 1); 117962306a36Sopenharmony_ci if (err < 0) 118062306a36Sopenharmony_ci break; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (meta_bg == 0) 118362306a36Sopenharmony_ci backup_block = ((ext4_fsblk_t)group) * bpg + blk_off; 118462306a36Sopenharmony_ci else 118562306a36Sopenharmony_ci backup_block = first_block + has_super; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci bh = sb_getblk(sb, backup_block); 118862306a36Sopenharmony_ci if (unlikely(!bh)) { 118962306a36Sopenharmony_ci err = -ENOMEM; 119062306a36Sopenharmony_ci break; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci ext4_debug("update metadata backup %llu(+%llu)\n", 119362306a36Sopenharmony_ci backup_block, backup_block - 119462306a36Sopenharmony_ci ext4_group_first_block_no(sb, group)); 119562306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 119662306a36Sopenharmony_ci if ((err = ext4_journal_get_write_access(handle, sb, bh, 119762306a36Sopenharmony_ci EXT4_JTR_NONE))) { 119862306a36Sopenharmony_ci brelse(bh); 119962306a36Sopenharmony_ci break; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci lock_buffer(bh); 120262306a36Sopenharmony_ci memcpy(bh->b_data, data, size); 120362306a36Sopenharmony_ci if (rest) 120462306a36Sopenharmony_ci memset(bh->b_data + size, 0, rest); 120562306a36Sopenharmony_ci if (has_super && (backup_block == first_block)) 120662306a36Sopenharmony_ci ext4_set_block_group_nr(sb, bh->b_data, group); 120762306a36Sopenharmony_ci set_buffer_uptodate(bh); 120862306a36Sopenharmony_ci unlock_buffer(bh); 120962306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, bh); 121062306a36Sopenharmony_ci if (unlikely(err)) 121162306a36Sopenharmony_ci ext4_std_error(sb, err); 121262306a36Sopenharmony_ci brelse(bh); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (meta_bg == 0) 121562306a36Sopenharmony_ci group = ext4_list_backups(sb, &three, &five, &seven); 121662306a36Sopenharmony_ci else if (group == last) 121762306a36Sopenharmony_ci break; 121862306a36Sopenharmony_ci else 121962306a36Sopenharmony_ci group = last; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci if ((err2 = ext4_journal_stop(handle)) && !err) 122262306a36Sopenharmony_ci err = err2; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci /* 122562306a36Sopenharmony_ci * Ugh! Need to have e2fsck write the backup copies. It is too 122662306a36Sopenharmony_ci * late to revert the resize, we shouldn't fail just because of 122762306a36Sopenharmony_ci * the backup copies (they are only needed in case of corruption). 122862306a36Sopenharmony_ci * 122962306a36Sopenharmony_ci * However, if we got here we have a journal problem too, so we 123062306a36Sopenharmony_ci * can't really start a transaction to mark the superblock. 123162306a36Sopenharmony_ci * Chicken out and just set the flag on the hope it will be written 123262306a36Sopenharmony_ci * to disk, and if not - we will simply wait until next fsck. 123362306a36Sopenharmony_ci */ 123462306a36Sopenharmony_ciexit_err: 123562306a36Sopenharmony_ci if (err) { 123662306a36Sopenharmony_ci ext4_warning(sb, "can't update backup for group %u (err %d), " 123762306a36Sopenharmony_ci "forcing fsck on next reboot", group, err); 123862306a36Sopenharmony_ci sbi->s_mount_state &= ~EXT4_VALID_FS; 123962306a36Sopenharmony_ci sbi->s_es->s_state &= cpu_to_le16(~EXT4_VALID_FS); 124062306a36Sopenharmony_ci mark_buffer_dirty(sbi->s_sbh); 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci/* 124562306a36Sopenharmony_ci * ext4_add_new_descs() adds @count group descriptor of groups 124662306a36Sopenharmony_ci * starting at @group 124762306a36Sopenharmony_ci * 124862306a36Sopenharmony_ci * @handle: journal handle 124962306a36Sopenharmony_ci * @sb: super block 125062306a36Sopenharmony_ci * @group: the group no. of the first group desc to be added 125162306a36Sopenharmony_ci * @resize_inode: the resize inode 125262306a36Sopenharmony_ci * @count: number of group descriptors to be added 125362306a36Sopenharmony_ci */ 125462306a36Sopenharmony_cistatic int ext4_add_new_descs(handle_t *handle, struct super_block *sb, 125562306a36Sopenharmony_ci ext4_group_t group, struct inode *resize_inode, 125662306a36Sopenharmony_ci ext4_group_t count) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 125962306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 126062306a36Sopenharmony_ci struct buffer_head *gdb_bh; 126162306a36Sopenharmony_ci int i, gdb_off, gdb_num, err = 0; 126262306a36Sopenharmony_ci int meta_bg; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci meta_bg = ext4_has_feature_meta_bg(sb); 126562306a36Sopenharmony_ci for (i = 0; i < count; i++, group++) { 126662306a36Sopenharmony_ci int reserved_gdb = ext4_bg_has_super(sb, group) ? 126762306a36Sopenharmony_ci le16_to_cpu(es->s_reserved_gdt_blocks) : 0; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci gdb_off = group % EXT4_DESC_PER_BLOCK(sb); 127062306a36Sopenharmony_ci gdb_num = group / EXT4_DESC_PER_BLOCK(sb); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci /* 127362306a36Sopenharmony_ci * We will only either add reserved group blocks to a backup group 127462306a36Sopenharmony_ci * or remove reserved blocks for the first group in a new group block. 127562306a36Sopenharmony_ci * Doing both would be mean more complex code, and sane people don't 127662306a36Sopenharmony_ci * use non-sparse filesystems anymore. This is already checked above. 127762306a36Sopenharmony_ci */ 127862306a36Sopenharmony_ci if (gdb_off) { 127962306a36Sopenharmony_ci gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc, 128062306a36Sopenharmony_ci gdb_num); 128162306a36Sopenharmony_ci BUFFER_TRACE(gdb_bh, "get_write_access"); 128262306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, gdb_bh, 128362306a36Sopenharmony_ci EXT4_JTR_NONE); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group)) 128662306a36Sopenharmony_ci err = reserve_backup_gdb(handle, resize_inode, group); 128762306a36Sopenharmony_ci } else if (meta_bg != 0) { 128862306a36Sopenharmony_ci err = add_new_gdb_meta_bg(sb, handle, group); 128962306a36Sopenharmony_ci } else { 129062306a36Sopenharmony_ci err = add_new_gdb(handle, resize_inode, group); 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci if (err) 129362306a36Sopenharmony_ci break; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci return err; 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_cistatic struct buffer_head *ext4_get_bitmap(struct super_block *sb, __u64 block) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci struct buffer_head *bh = sb_getblk(sb, block); 130162306a36Sopenharmony_ci if (unlikely(!bh)) 130262306a36Sopenharmony_ci return NULL; 130362306a36Sopenharmony_ci if (!bh_uptodate_or_lock(bh)) { 130462306a36Sopenharmony_ci if (ext4_read_bh(bh, 0, NULL) < 0) { 130562306a36Sopenharmony_ci brelse(bh); 130662306a36Sopenharmony_ci return NULL; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci return bh; 131162306a36Sopenharmony_ci} 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_cistatic int ext4_set_bitmap_checksums(struct super_block *sb, 131462306a36Sopenharmony_ci struct ext4_group_desc *gdp, 131562306a36Sopenharmony_ci struct ext4_new_group_data *group_data) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci struct buffer_head *bh; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (!ext4_has_metadata_csum(sb)) 132062306a36Sopenharmony_ci return 0; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci bh = ext4_get_bitmap(sb, group_data->inode_bitmap); 132362306a36Sopenharmony_ci if (!bh) 132462306a36Sopenharmony_ci return -EIO; 132562306a36Sopenharmony_ci ext4_inode_bitmap_csum_set(sb, gdp, bh, 132662306a36Sopenharmony_ci EXT4_INODES_PER_GROUP(sb) / 8); 132762306a36Sopenharmony_ci brelse(bh); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci bh = ext4_get_bitmap(sb, group_data->block_bitmap); 133062306a36Sopenharmony_ci if (!bh) 133162306a36Sopenharmony_ci return -EIO; 133262306a36Sopenharmony_ci ext4_block_bitmap_csum_set(sb, gdp, bh); 133362306a36Sopenharmony_ci brelse(bh); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci return 0; 133662306a36Sopenharmony_ci} 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci/* 133962306a36Sopenharmony_ci * ext4_setup_new_descs() will set up the group descriptor descriptors of a flex bg 134062306a36Sopenharmony_ci */ 134162306a36Sopenharmony_cistatic int ext4_setup_new_descs(handle_t *handle, struct super_block *sb, 134262306a36Sopenharmony_ci struct ext4_new_flex_group_data *flex_gd) 134362306a36Sopenharmony_ci{ 134462306a36Sopenharmony_ci struct ext4_new_group_data *group_data = flex_gd->groups; 134562306a36Sopenharmony_ci struct ext4_group_desc *gdp; 134662306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 134762306a36Sopenharmony_ci struct buffer_head *gdb_bh; 134862306a36Sopenharmony_ci ext4_group_t group; 134962306a36Sopenharmony_ci __u16 *bg_flags = flex_gd->bg_flags; 135062306a36Sopenharmony_ci int i, gdb_off, gdb_num, err = 0; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci for (i = 0; i < flex_gd->count; i++, group_data++, bg_flags++) { 135462306a36Sopenharmony_ci group = group_data->group; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci gdb_off = group % EXT4_DESC_PER_BLOCK(sb); 135762306a36Sopenharmony_ci gdb_num = group / EXT4_DESC_PER_BLOCK(sb); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci /* 136062306a36Sopenharmony_ci * get_write_access() has been called on gdb_bh by ext4_add_new_desc(). 136162306a36Sopenharmony_ci */ 136262306a36Sopenharmony_ci gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc, gdb_num); 136362306a36Sopenharmony_ci /* Update group descriptor block for new group */ 136462306a36Sopenharmony_ci gdp = (struct ext4_group_desc *)(gdb_bh->b_data + 136562306a36Sopenharmony_ci gdb_off * EXT4_DESC_SIZE(sb)); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci memset(gdp, 0, EXT4_DESC_SIZE(sb)); 136862306a36Sopenharmony_ci ext4_block_bitmap_set(sb, gdp, group_data->block_bitmap); 136962306a36Sopenharmony_ci ext4_inode_bitmap_set(sb, gdp, group_data->inode_bitmap); 137062306a36Sopenharmony_ci err = ext4_set_bitmap_checksums(sb, gdp, group_data); 137162306a36Sopenharmony_ci if (err) { 137262306a36Sopenharmony_ci ext4_std_error(sb, err); 137362306a36Sopenharmony_ci break; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci ext4_inode_table_set(sb, gdp, group_data->inode_table); 137762306a36Sopenharmony_ci ext4_free_group_clusters_set(sb, gdp, 137862306a36Sopenharmony_ci group_data->free_clusters_count); 137962306a36Sopenharmony_ci ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb)); 138062306a36Sopenharmony_ci if (ext4_has_group_desc_csum(sb)) 138162306a36Sopenharmony_ci ext4_itable_unused_set(sb, gdp, 138262306a36Sopenharmony_ci EXT4_INODES_PER_GROUP(sb)); 138362306a36Sopenharmony_ci gdp->bg_flags = cpu_to_le16(*bg_flags); 138462306a36Sopenharmony_ci ext4_group_desc_csum_set(sb, group, gdp); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh); 138762306a36Sopenharmony_ci if (unlikely(err)) { 138862306a36Sopenharmony_ci ext4_std_error(sb, err); 138962306a36Sopenharmony_ci break; 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci /* 139362306a36Sopenharmony_ci * We can allocate memory for mb_alloc based on the new group 139462306a36Sopenharmony_ci * descriptor 139562306a36Sopenharmony_ci */ 139662306a36Sopenharmony_ci err = ext4_mb_add_groupinfo(sb, group, gdp); 139762306a36Sopenharmony_ci if (err) 139862306a36Sopenharmony_ci break; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci return err; 140162306a36Sopenharmony_ci} 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_cistatic void ext4_add_overhead(struct super_block *sb, 140462306a36Sopenharmony_ci const ext4_fsblk_t overhead) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 140762306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci sbi->s_overhead += overhead; 141062306a36Sopenharmony_ci es->s_overhead_clusters = cpu_to_le32(sbi->s_overhead); 141162306a36Sopenharmony_ci smp_wmb(); 141262306a36Sopenharmony_ci} 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci/* 141562306a36Sopenharmony_ci * ext4_update_super() updates the super block so that the newly added 141662306a36Sopenharmony_ci * groups can be seen by the filesystem. 141762306a36Sopenharmony_ci * 141862306a36Sopenharmony_ci * @sb: super block 141962306a36Sopenharmony_ci * @flex_gd: new added groups 142062306a36Sopenharmony_ci */ 142162306a36Sopenharmony_cistatic void ext4_update_super(struct super_block *sb, 142262306a36Sopenharmony_ci struct ext4_new_flex_group_data *flex_gd) 142362306a36Sopenharmony_ci{ 142462306a36Sopenharmony_ci ext4_fsblk_t blocks_count = 0; 142562306a36Sopenharmony_ci ext4_fsblk_t free_blocks = 0; 142662306a36Sopenharmony_ci ext4_fsblk_t reserved_blocks = 0; 142762306a36Sopenharmony_ci struct ext4_new_group_data *group_data = flex_gd->groups; 142862306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 142962306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 143062306a36Sopenharmony_ci int i; 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci BUG_ON(flex_gd->count == 0 || group_data == NULL); 143362306a36Sopenharmony_ci /* 143462306a36Sopenharmony_ci * Make the new blocks and inodes valid next. We do this before 143562306a36Sopenharmony_ci * increasing the group count so that once the group is enabled, 143662306a36Sopenharmony_ci * all of its blocks and inodes are already valid. 143762306a36Sopenharmony_ci * 143862306a36Sopenharmony_ci * We always allocate group-by-group, then block-by-block or 143962306a36Sopenharmony_ci * inode-by-inode within a group, so enabling these 144062306a36Sopenharmony_ci * blocks/inodes before the group is live won't actually let us 144162306a36Sopenharmony_ci * allocate the new space yet. 144262306a36Sopenharmony_ci */ 144362306a36Sopenharmony_ci for (i = 0; i < flex_gd->count; i++) { 144462306a36Sopenharmony_ci blocks_count += group_data[i].blocks_count; 144562306a36Sopenharmony_ci free_blocks += EXT4_C2B(sbi, group_data[i].free_clusters_count); 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci reserved_blocks = ext4_r_blocks_count(es) * 100; 144962306a36Sopenharmony_ci reserved_blocks = div64_u64(reserved_blocks, ext4_blocks_count(es)); 145062306a36Sopenharmony_ci reserved_blocks *= blocks_count; 145162306a36Sopenharmony_ci do_div(reserved_blocks, 100); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci lock_buffer(sbi->s_sbh); 145462306a36Sopenharmony_ci ext4_blocks_count_set(es, ext4_blocks_count(es) + blocks_count); 145562306a36Sopenharmony_ci ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + free_blocks); 145662306a36Sopenharmony_ci le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb) * 145762306a36Sopenharmony_ci flex_gd->count); 145862306a36Sopenharmony_ci le32_add_cpu(&es->s_free_inodes_count, EXT4_INODES_PER_GROUP(sb) * 145962306a36Sopenharmony_ci flex_gd->count); 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci ext4_debug("free blocks count %llu", ext4_free_blocks_count(es)); 146262306a36Sopenharmony_ci /* 146362306a36Sopenharmony_ci * We need to protect s_groups_count against other CPUs seeing 146462306a36Sopenharmony_ci * inconsistent state in the superblock. 146562306a36Sopenharmony_ci * 146662306a36Sopenharmony_ci * The precise rules we use are: 146762306a36Sopenharmony_ci * 146862306a36Sopenharmony_ci * * Writers must perform a smp_wmb() after updating all 146962306a36Sopenharmony_ci * dependent data and before modifying the groups count 147062306a36Sopenharmony_ci * 147162306a36Sopenharmony_ci * * Readers must perform an smp_rmb() after reading the groups 147262306a36Sopenharmony_ci * count and before reading any dependent data. 147362306a36Sopenharmony_ci * 147462306a36Sopenharmony_ci * NB. These rules can be relaxed when checking the group count 147562306a36Sopenharmony_ci * while freeing data, as we can only allocate from a block 147662306a36Sopenharmony_ci * group after serialising against the group count, and we can 147762306a36Sopenharmony_ci * only then free after serialising in turn against that 147862306a36Sopenharmony_ci * allocation. 147962306a36Sopenharmony_ci */ 148062306a36Sopenharmony_ci smp_wmb(); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci /* Update the global fs size fields */ 148362306a36Sopenharmony_ci sbi->s_groups_count += flex_gd->count; 148462306a36Sopenharmony_ci sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count, 148562306a36Sopenharmony_ci (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci /* Update the reserved block counts only once the new group is 148862306a36Sopenharmony_ci * active. */ 148962306a36Sopenharmony_ci ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) + 149062306a36Sopenharmony_ci reserved_blocks); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci /* Update the free space counts */ 149362306a36Sopenharmony_ci percpu_counter_add(&sbi->s_freeclusters_counter, 149462306a36Sopenharmony_ci EXT4_NUM_B2C(sbi, free_blocks)); 149562306a36Sopenharmony_ci percpu_counter_add(&sbi->s_freeinodes_counter, 149662306a36Sopenharmony_ci EXT4_INODES_PER_GROUP(sb) * flex_gd->count); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci ext4_debug("free blocks count %llu", 149962306a36Sopenharmony_ci percpu_counter_read(&sbi->s_freeclusters_counter)); 150062306a36Sopenharmony_ci if (ext4_has_feature_flex_bg(sb) && sbi->s_log_groups_per_flex) { 150162306a36Sopenharmony_ci ext4_group_t flex_group; 150262306a36Sopenharmony_ci struct flex_groups *fg; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci flex_group = ext4_flex_group(sbi, group_data[0].group); 150562306a36Sopenharmony_ci fg = sbi_array_rcu_deref(sbi, s_flex_groups, flex_group); 150662306a36Sopenharmony_ci atomic64_add(EXT4_NUM_B2C(sbi, free_blocks), 150762306a36Sopenharmony_ci &fg->free_clusters); 150862306a36Sopenharmony_ci atomic_add(EXT4_INODES_PER_GROUP(sb) * flex_gd->count, 150962306a36Sopenharmony_ci &fg->free_inodes); 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci /* 151362306a36Sopenharmony_ci * Update the fs overhead information. 151462306a36Sopenharmony_ci * 151562306a36Sopenharmony_ci * For bigalloc, if the superblock already has a properly calculated 151662306a36Sopenharmony_ci * overhead, update it with a value based on numbers already computed 151762306a36Sopenharmony_ci * above for the newly allocated capacity. 151862306a36Sopenharmony_ci */ 151962306a36Sopenharmony_ci if (ext4_has_feature_bigalloc(sb) && (sbi->s_overhead != 0)) 152062306a36Sopenharmony_ci ext4_add_overhead(sb, 152162306a36Sopenharmony_ci EXT4_NUM_B2C(sbi, blocks_count - free_blocks)); 152262306a36Sopenharmony_ci else 152362306a36Sopenharmony_ci ext4_calculate_overhead(sb); 152462306a36Sopenharmony_ci es->s_overhead_clusters = cpu_to_le32(sbi->s_overhead); 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci ext4_superblock_csum_set(sb); 152762306a36Sopenharmony_ci unlock_buffer(sbi->s_sbh); 152862306a36Sopenharmony_ci if (test_opt(sb, DEBUG)) 152962306a36Sopenharmony_ci printk(KERN_DEBUG "EXT4-fs: added group %u:" 153062306a36Sopenharmony_ci "%llu blocks(%llu free %llu reserved)\n", flex_gd->count, 153162306a36Sopenharmony_ci blocks_count, free_blocks, reserved_blocks); 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci/* Add a flex group to an fs. Ensure we handle all possible error conditions 153562306a36Sopenharmony_ci * _before_ we start modifying the filesystem, because we cannot abort the 153662306a36Sopenharmony_ci * transaction and not have it write the data to disk. 153762306a36Sopenharmony_ci */ 153862306a36Sopenharmony_cistatic int ext4_flex_group_add(struct super_block *sb, 153962306a36Sopenharmony_ci struct inode *resize_inode, 154062306a36Sopenharmony_ci struct ext4_new_flex_group_data *flex_gd) 154162306a36Sopenharmony_ci{ 154262306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 154362306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 154462306a36Sopenharmony_ci ext4_fsblk_t o_blocks_count; 154562306a36Sopenharmony_ci ext4_grpblk_t last; 154662306a36Sopenharmony_ci ext4_group_t group; 154762306a36Sopenharmony_ci handle_t *handle; 154862306a36Sopenharmony_ci unsigned reserved_gdb; 154962306a36Sopenharmony_ci int err = 0, err2 = 0, credit; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci BUG_ON(!flex_gd->count || !flex_gd->groups || !flex_gd->bg_flags); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks); 155462306a36Sopenharmony_ci o_blocks_count = ext4_blocks_count(es); 155562306a36Sopenharmony_ci ext4_get_group_no_and_offset(sb, o_blocks_count, &group, &last); 155662306a36Sopenharmony_ci BUG_ON(last); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci err = setup_new_flex_group_blocks(sb, flex_gd); 155962306a36Sopenharmony_ci if (err) 156062306a36Sopenharmony_ci goto exit; 156162306a36Sopenharmony_ci /* 156262306a36Sopenharmony_ci * We will always be modifying at least the superblock and GDT 156362306a36Sopenharmony_ci * blocks. If we are adding a group past the last current GDT block, 156462306a36Sopenharmony_ci * we will also modify the inode and the dindirect block. If we 156562306a36Sopenharmony_ci * are adding a group with superblock/GDT backups we will also 156662306a36Sopenharmony_ci * modify each of the reserved GDT dindirect blocks. 156762306a36Sopenharmony_ci */ 156862306a36Sopenharmony_ci credit = 3; /* sb, resize inode, resize inode dindirect */ 156962306a36Sopenharmony_ci /* GDT blocks */ 157062306a36Sopenharmony_ci credit += 1 + DIV_ROUND_UP(flex_gd->count, EXT4_DESC_PER_BLOCK(sb)); 157162306a36Sopenharmony_ci credit += reserved_gdb; /* Reserved GDT dindirect blocks */ 157262306a36Sopenharmony_ci handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, credit); 157362306a36Sopenharmony_ci if (IS_ERR(handle)) { 157462306a36Sopenharmony_ci err = PTR_ERR(handle); 157562306a36Sopenharmony_ci goto exit; 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci BUFFER_TRACE(sbi->s_sbh, "get_write_access"); 157962306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, sbi->s_sbh, 158062306a36Sopenharmony_ci EXT4_JTR_NONE); 158162306a36Sopenharmony_ci if (err) 158262306a36Sopenharmony_ci goto exit_journal; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci group = flex_gd->groups[0].group; 158562306a36Sopenharmony_ci BUG_ON(group != sbi->s_groups_count); 158662306a36Sopenharmony_ci err = ext4_add_new_descs(handle, sb, group, 158762306a36Sopenharmony_ci resize_inode, flex_gd->count); 158862306a36Sopenharmony_ci if (err) 158962306a36Sopenharmony_ci goto exit_journal; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci err = ext4_setup_new_descs(handle, sb, flex_gd); 159262306a36Sopenharmony_ci if (err) 159362306a36Sopenharmony_ci goto exit_journal; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci ext4_update_super(sb, flex_gd); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ciexit_journal: 160062306a36Sopenharmony_ci err2 = ext4_journal_stop(handle); 160162306a36Sopenharmony_ci if (!err) 160262306a36Sopenharmony_ci err = err2; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci if (!err) { 160562306a36Sopenharmony_ci int gdb_num = group / EXT4_DESC_PER_BLOCK(sb); 160662306a36Sopenharmony_ci int gdb_num_end = ((group + flex_gd->count - 1) / 160762306a36Sopenharmony_ci EXT4_DESC_PER_BLOCK(sb)); 160862306a36Sopenharmony_ci int meta_bg = ext4_has_feature_meta_bg(sb) && 160962306a36Sopenharmony_ci gdb_num >= le32_to_cpu(es->s_first_meta_bg); 161062306a36Sopenharmony_ci sector_t padding_blocks = meta_bg ? 0 : sbi->s_sbh->b_blocknr - 161162306a36Sopenharmony_ci ext4_group_first_block_no(sb, 0); 161262306a36Sopenharmony_ci sector_t old_gdb = 0; 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci update_backups(sb, ext4_group_first_block_no(sb, 0), 161562306a36Sopenharmony_ci (char *)es, sizeof(struct ext4_super_block), 0); 161662306a36Sopenharmony_ci for (; gdb_num <= gdb_num_end; gdb_num++) { 161762306a36Sopenharmony_ci struct buffer_head *gdb_bh; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci gdb_bh = sbi_array_rcu_deref(sbi, s_group_desc, 162062306a36Sopenharmony_ci gdb_num); 162162306a36Sopenharmony_ci if (old_gdb == gdb_bh->b_blocknr) 162262306a36Sopenharmony_ci continue; 162362306a36Sopenharmony_ci update_backups(sb, gdb_bh->b_blocknr - padding_blocks, 162462306a36Sopenharmony_ci gdb_bh->b_data, gdb_bh->b_size, meta_bg); 162562306a36Sopenharmony_ci old_gdb = gdb_bh->b_blocknr; 162662306a36Sopenharmony_ci } 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ciexit: 162962306a36Sopenharmony_ci return err; 163062306a36Sopenharmony_ci} 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_cistatic int ext4_setup_next_flex_gd(struct super_block *sb, 163362306a36Sopenharmony_ci struct ext4_new_flex_group_data *flex_gd, 163462306a36Sopenharmony_ci ext4_fsblk_t n_blocks_count) 163562306a36Sopenharmony_ci{ 163662306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 163762306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 163862306a36Sopenharmony_ci struct ext4_new_group_data *group_data = flex_gd->groups; 163962306a36Sopenharmony_ci ext4_fsblk_t o_blocks_count; 164062306a36Sopenharmony_ci ext4_group_t n_group; 164162306a36Sopenharmony_ci ext4_group_t group; 164262306a36Sopenharmony_ci ext4_group_t last_group; 164362306a36Sopenharmony_ci ext4_grpblk_t last; 164462306a36Sopenharmony_ci ext4_grpblk_t clusters_per_group; 164562306a36Sopenharmony_ci unsigned long i; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci clusters_per_group = EXT4_CLUSTERS_PER_GROUP(sb); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci o_blocks_count = ext4_blocks_count(es); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci if (o_blocks_count == n_blocks_count) 165262306a36Sopenharmony_ci return 0; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci ext4_get_group_no_and_offset(sb, o_blocks_count, &group, &last); 165562306a36Sopenharmony_ci BUG_ON(last); 165662306a36Sopenharmony_ci ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &last); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci last_group = group | (flex_gd->resize_bg - 1); 165962306a36Sopenharmony_ci if (last_group > n_group) 166062306a36Sopenharmony_ci last_group = n_group; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci flex_gd->count = last_group - group + 1; 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci for (i = 0; i < flex_gd->count; i++) { 166562306a36Sopenharmony_ci int overhead; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci group_data[i].group = group + i; 166862306a36Sopenharmony_ci group_data[i].blocks_count = EXT4_BLOCKS_PER_GROUP(sb); 166962306a36Sopenharmony_ci overhead = ext4_group_overhead_blocks(sb, group + i); 167062306a36Sopenharmony_ci group_data[i].mdata_blocks = overhead; 167162306a36Sopenharmony_ci group_data[i].free_clusters_count = EXT4_CLUSTERS_PER_GROUP(sb); 167262306a36Sopenharmony_ci if (ext4_has_group_desc_csum(sb)) { 167362306a36Sopenharmony_ci flex_gd->bg_flags[i] = EXT4_BG_BLOCK_UNINIT | 167462306a36Sopenharmony_ci EXT4_BG_INODE_UNINIT; 167562306a36Sopenharmony_ci if (!test_opt(sb, INIT_INODE_TABLE)) 167662306a36Sopenharmony_ci flex_gd->bg_flags[i] |= EXT4_BG_INODE_ZEROED; 167762306a36Sopenharmony_ci } else 167862306a36Sopenharmony_ci flex_gd->bg_flags[i] = EXT4_BG_INODE_ZEROED; 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci if (last_group == n_group && ext4_has_group_desc_csum(sb)) 168262306a36Sopenharmony_ci /* We need to initialize block bitmap of last group. */ 168362306a36Sopenharmony_ci flex_gd->bg_flags[i - 1] &= ~EXT4_BG_BLOCK_UNINIT; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci if ((last_group == n_group) && (last != clusters_per_group - 1)) { 168662306a36Sopenharmony_ci group_data[i - 1].blocks_count = EXT4_C2B(sbi, last + 1); 168762306a36Sopenharmony_ci group_data[i - 1].free_clusters_count -= clusters_per_group - 168862306a36Sopenharmony_ci last - 1; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci return 1; 169262306a36Sopenharmony_ci} 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci/* Add group descriptor data to an existing or new group descriptor block. 169562306a36Sopenharmony_ci * Ensure we handle all possible error conditions _before_ we start modifying 169662306a36Sopenharmony_ci * the filesystem, because we cannot abort the transaction and not have it 169762306a36Sopenharmony_ci * write the data to disk. 169862306a36Sopenharmony_ci * 169962306a36Sopenharmony_ci * If we are on a GDT block boundary, we need to get the reserved GDT block. 170062306a36Sopenharmony_ci * Otherwise, we may need to add backup GDT blocks for a sparse group. 170162306a36Sopenharmony_ci * 170262306a36Sopenharmony_ci * We only need to hold the superblock lock while we are actually adding 170362306a36Sopenharmony_ci * in the new group's counts to the superblock. Prior to that we have 170462306a36Sopenharmony_ci * not really "added" the group at all. We re-check that we are still 170562306a36Sopenharmony_ci * adding in the last group in case things have changed since verifying. 170662306a36Sopenharmony_ci */ 170762306a36Sopenharmony_ciint ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) 170862306a36Sopenharmony_ci{ 170962306a36Sopenharmony_ci struct ext4_new_flex_group_data flex_gd; 171062306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 171162306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 171262306a36Sopenharmony_ci int reserved_gdb = ext4_bg_has_super(sb, input->group) ? 171362306a36Sopenharmony_ci le16_to_cpu(es->s_reserved_gdt_blocks) : 0; 171462306a36Sopenharmony_ci struct inode *inode = NULL; 171562306a36Sopenharmony_ci int gdb_off; 171662306a36Sopenharmony_ci int err; 171762306a36Sopenharmony_ci __u16 bg_flags = 0; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci gdb_off = input->group % EXT4_DESC_PER_BLOCK(sb); 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci if (gdb_off == 0 && !ext4_has_feature_sparse_super(sb)) { 172262306a36Sopenharmony_ci ext4_warning(sb, "Can't resize non-sparse filesystem further"); 172362306a36Sopenharmony_ci return -EPERM; 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if (ext4_blocks_count(es) + input->blocks_count < 172762306a36Sopenharmony_ci ext4_blocks_count(es)) { 172862306a36Sopenharmony_ci ext4_warning(sb, "blocks_count overflow"); 172962306a36Sopenharmony_ci return -EINVAL; 173062306a36Sopenharmony_ci } 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci if (le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb) < 173362306a36Sopenharmony_ci le32_to_cpu(es->s_inodes_count)) { 173462306a36Sopenharmony_ci ext4_warning(sb, "inodes_count overflow"); 173562306a36Sopenharmony_ci return -EINVAL; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci if (reserved_gdb || gdb_off == 0) { 173962306a36Sopenharmony_ci if (!ext4_has_feature_resize_inode(sb) || 174062306a36Sopenharmony_ci !le16_to_cpu(es->s_reserved_gdt_blocks)) { 174162306a36Sopenharmony_ci ext4_warning(sb, 174262306a36Sopenharmony_ci "No reserved GDT blocks, can't resize"); 174362306a36Sopenharmony_ci return -EPERM; 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci inode = ext4_iget(sb, EXT4_RESIZE_INO, EXT4_IGET_SPECIAL); 174662306a36Sopenharmony_ci if (IS_ERR(inode)) { 174762306a36Sopenharmony_ci ext4_warning(sb, "Error opening resize inode"); 174862306a36Sopenharmony_ci return PTR_ERR(inode); 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci } 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci err = verify_group_input(sb, input); 175462306a36Sopenharmony_ci if (err) 175562306a36Sopenharmony_ci goto out; 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci err = ext4_alloc_flex_bg_array(sb, input->group + 1); 175862306a36Sopenharmony_ci if (err) 175962306a36Sopenharmony_ci goto out; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci err = ext4_mb_alloc_groupinfo(sb, input->group + 1); 176262306a36Sopenharmony_ci if (err) 176362306a36Sopenharmony_ci goto out; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci flex_gd.count = 1; 176662306a36Sopenharmony_ci flex_gd.groups = input; 176762306a36Sopenharmony_ci flex_gd.bg_flags = &bg_flags; 176862306a36Sopenharmony_ci err = ext4_flex_group_add(sb, inode, &flex_gd); 176962306a36Sopenharmony_ciout: 177062306a36Sopenharmony_ci iput(inode); 177162306a36Sopenharmony_ci return err; 177262306a36Sopenharmony_ci} /* ext4_group_add */ 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci/* 177562306a36Sopenharmony_ci * extend a group without checking assuming that checking has been done. 177662306a36Sopenharmony_ci */ 177762306a36Sopenharmony_cistatic int ext4_group_extend_no_check(struct super_block *sb, 177862306a36Sopenharmony_ci ext4_fsblk_t o_blocks_count, ext4_grpblk_t add) 177962306a36Sopenharmony_ci{ 178062306a36Sopenharmony_ci struct ext4_super_block *es = EXT4_SB(sb)->s_es; 178162306a36Sopenharmony_ci handle_t *handle; 178262306a36Sopenharmony_ci int err = 0, err2; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci /* We will update the superblock, one block bitmap, and 178562306a36Sopenharmony_ci * one group descriptor via ext4_group_add_blocks(). 178662306a36Sopenharmony_ci */ 178762306a36Sopenharmony_ci handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, 3); 178862306a36Sopenharmony_ci if (IS_ERR(handle)) { 178962306a36Sopenharmony_ci err = PTR_ERR(handle); 179062306a36Sopenharmony_ci ext4_warning(sb, "error %d on journal start", err); 179162306a36Sopenharmony_ci return err; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); 179562306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, EXT4_SB(sb)->s_sbh, 179662306a36Sopenharmony_ci EXT4_JTR_NONE); 179762306a36Sopenharmony_ci if (err) { 179862306a36Sopenharmony_ci ext4_warning(sb, "error %d on journal write access", err); 179962306a36Sopenharmony_ci goto errout; 180062306a36Sopenharmony_ci } 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci lock_buffer(EXT4_SB(sb)->s_sbh); 180362306a36Sopenharmony_ci ext4_blocks_count_set(es, o_blocks_count + add); 180462306a36Sopenharmony_ci ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + add); 180562306a36Sopenharmony_ci ext4_superblock_csum_set(sb); 180662306a36Sopenharmony_ci unlock_buffer(EXT4_SB(sb)->s_sbh); 180762306a36Sopenharmony_ci ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count, 180862306a36Sopenharmony_ci o_blocks_count + add); 180962306a36Sopenharmony_ci /* We add the blocks to the bitmap and set the group need init bit */ 181062306a36Sopenharmony_ci err = ext4_group_add_blocks(handle, sb, o_blocks_count, add); 181162306a36Sopenharmony_ci if (err) 181262306a36Sopenharmony_ci goto errout; 181362306a36Sopenharmony_ci ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); 181462306a36Sopenharmony_ci ext4_debug("freed blocks %llu through %llu\n", o_blocks_count, 181562306a36Sopenharmony_ci o_blocks_count + add); 181662306a36Sopenharmony_cierrout: 181762306a36Sopenharmony_ci err2 = ext4_journal_stop(handle); 181862306a36Sopenharmony_ci if (err2 && !err) 181962306a36Sopenharmony_ci err = err2; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci if (!err) { 182262306a36Sopenharmony_ci if (test_opt(sb, DEBUG)) 182362306a36Sopenharmony_ci printk(KERN_DEBUG "EXT4-fs: extended group to %llu " 182462306a36Sopenharmony_ci "blocks\n", ext4_blocks_count(es)); 182562306a36Sopenharmony_ci update_backups(sb, ext4_group_first_block_no(sb, 0), 182662306a36Sopenharmony_ci (char *)es, sizeof(struct ext4_super_block), 0); 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci return err; 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci/* 183262306a36Sopenharmony_ci * Extend the filesystem to the new number of blocks specified. This entry 183362306a36Sopenharmony_ci * point is only used to extend the current filesystem to the end of the last 183462306a36Sopenharmony_ci * existing group. It can be accessed via ioctl, or by "remount,resize=<size>" 183562306a36Sopenharmony_ci * for emergencies (because it has no dependencies on reserved blocks). 183662306a36Sopenharmony_ci * 183762306a36Sopenharmony_ci * If we _really_ wanted, we could use default values to call ext4_group_add() 183862306a36Sopenharmony_ci * allow the "remount" trick to work for arbitrary resizing, assuming enough 183962306a36Sopenharmony_ci * GDT blocks are reserved to grow to the desired size. 184062306a36Sopenharmony_ci */ 184162306a36Sopenharmony_ciint ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, 184262306a36Sopenharmony_ci ext4_fsblk_t n_blocks_count) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci ext4_fsblk_t o_blocks_count; 184562306a36Sopenharmony_ci ext4_grpblk_t last; 184662306a36Sopenharmony_ci ext4_grpblk_t add; 184762306a36Sopenharmony_ci struct buffer_head *bh; 184862306a36Sopenharmony_ci ext4_group_t group; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci o_blocks_count = ext4_blocks_count(es); 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci if (test_opt(sb, DEBUG)) 185362306a36Sopenharmony_ci ext4_msg(sb, KERN_DEBUG, 185462306a36Sopenharmony_ci "extending last group from %llu to %llu blocks", 185562306a36Sopenharmony_ci o_blocks_count, n_blocks_count); 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci if (n_blocks_count == 0 || n_blocks_count == o_blocks_count) 185862306a36Sopenharmony_ci return 0; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { 186162306a36Sopenharmony_ci ext4_msg(sb, KERN_ERR, 186262306a36Sopenharmony_ci "filesystem too large to resize to %llu blocks safely", 186362306a36Sopenharmony_ci n_blocks_count); 186462306a36Sopenharmony_ci return -EINVAL; 186562306a36Sopenharmony_ci } 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci if (n_blocks_count < o_blocks_count) { 186862306a36Sopenharmony_ci ext4_warning(sb, "can't shrink FS - resize aborted"); 186962306a36Sopenharmony_ci return -EINVAL; 187062306a36Sopenharmony_ci } 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci /* Handle the remaining blocks in the last group only. */ 187362306a36Sopenharmony_ci ext4_get_group_no_and_offset(sb, o_blocks_count, &group, &last); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci if (last == 0) { 187662306a36Sopenharmony_ci ext4_warning(sb, "need to use ext2online to resize further"); 187762306a36Sopenharmony_ci return -EPERM; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci add = EXT4_BLOCKS_PER_GROUP(sb) - last; 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci if (o_blocks_count + add < o_blocks_count) { 188362306a36Sopenharmony_ci ext4_warning(sb, "blocks_count overflow"); 188462306a36Sopenharmony_ci return -EINVAL; 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci if (o_blocks_count + add > n_blocks_count) 188862306a36Sopenharmony_ci add = n_blocks_count - o_blocks_count; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci if (o_blocks_count + add < n_blocks_count) 189162306a36Sopenharmony_ci ext4_warning(sb, "will only finish group (%llu blocks, %u new)", 189262306a36Sopenharmony_ci o_blocks_count + add, add); 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci /* See if the device is actually as big as what was requested */ 189562306a36Sopenharmony_ci bh = ext4_sb_bread(sb, o_blocks_count + add - 1, 0); 189662306a36Sopenharmony_ci if (IS_ERR(bh)) { 189762306a36Sopenharmony_ci ext4_warning(sb, "can't read last block, resize aborted"); 189862306a36Sopenharmony_ci return -ENOSPC; 189962306a36Sopenharmony_ci } 190062306a36Sopenharmony_ci brelse(bh); 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci return ext4_group_extend_no_check(sb, o_blocks_count, add); 190362306a36Sopenharmony_ci} /* ext4_group_extend */ 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_cistatic int num_desc_blocks(struct super_block *sb, ext4_group_t groups) 190762306a36Sopenharmony_ci{ 190862306a36Sopenharmony_ci return (groups + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); 190962306a36Sopenharmony_ci} 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci/* 191262306a36Sopenharmony_ci * Release the resize inode and drop the resize_inode feature if there 191362306a36Sopenharmony_ci * are no more reserved gdt blocks, and then convert the file system 191462306a36Sopenharmony_ci * to enable meta_bg 191562306a36Sopenharmony_ci */ 191662306a36Sopenharmony_cistatic int ext4_convert_meta_bg(struct super_block *sb, struct inode *inode) 191762306a36Sopenharmony_ci{ 191862306a36Sopenharmony_ci handle_t *handle; 191962306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 192062306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 192162306a36Sopenharmony_ci struct ext4_inode_info *ei = EXT4_I(inode); 192262306a36Sopenharmony_ci ext4_fsblk_t nr; 192362306a36Sopenharmony_ci int i, ret, err = 0; 192462306a36Sopenharmony_ci int credits = 1; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci ext4_msg(sb, KERN_INFO, "Converting file system to meta_bg"); 192762306a36Sopenharmony_ci if (inode) { 192862306a36Sopenharmony_ci if (es->s_reserved_gdt_blocks) { 192962306a36Sopenharmony_ci ext4_error(sb, "Unexpected non-zero " 193062306a36Sopenharmony_ci "s_reserved_gdt_blocks"); 193162306a36Sopenharmony_ci return -EPERM; 193262306a36Sopenharmony_ci } 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci /* Do a quick sanity check of the resize inode */ 193562306a36Sopenharmony_ci if (inode->i_blocks != 1 << (inode->i_blkbits - 193662306a36Sopenharmony_ci (9 - sbi->s_cluster_bits))) 193762306a36Sopenharmony_ci goto invalid_resize_inode; 193862306a36Sopenharmony_ci for (i = 0; i < EXT4_N_BLOCKS; i++) { 193962306a36Sopenharmony_ci if (i == EXT4_DIND_BLOCK) { 194062306a36Sopenharmony_ci if (ei->i_data[i]) 194162306a36Sopenharmony_ci continue; 194262306a36Sopenharmony_ci else 194362306a36Sopenharmony_ci goto invalid_resize_inode; 194462306a36Sopenharmony_ci } 194562306a36Sopenharmony_ci if (ei->i_data[i]) 194662306a36Sopenharmony_ci goto invalid_resize_inode; 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci credits += 3; /* block bitmap, bg descriptor, resize inode */ 194962306a36Sopenharmony_ci } 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, credits); 195262306a36Sopenharmony_ci if (IS_ERR(handle)) 195362306a36Sopenharmony_ci return PTR_ERR(handle); 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci BUFFER_TRACE(sbi->s_sbh, "get_write_access"); 195662306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, sbi->s_sbh, 195762306a36Sopenharmony_ci EXT4_JTR_NONE); 195862306a36Sopenharmony_ci if (err) 195962306a36Sopenharmony_ci goto errout; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci lock_buffer(sbi->s_sbh); 196262306a36Sopenharmony_ci ext4_clear_feature_resize_inode(sb); 196362306a36Sopenharmony_ci ext4_set_feature_meta_bg(sb); 196462306a36Sopenharmony_ci sbi->s_es->s_first_meta_bg = 196562306a36Sopenharmony_ci cpu_to_le32(num_desc_blocks(sb, sbi->s_groups_count)); 196662306a36Sopenharmony_ci ext4_superblock_csum_set(sb); 196762306a36Sopenharmony_ci unlock_buffer(sbi->s_sbh); 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh); 197062306a36Sopenharmony_ci if (err) { 197162306a36Sopenharmony_ci ext4_std_error(sb, err); 197262306a36Sopenharmony_ci goto errout; 197362306a36Sopenharmony_ci } 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci if (inode) { 197662306a36Sopenharmony_ci nr = le32_to_cpu(ei->i_data[EXT4_DIND_BLOCK]); 197762306a36Sopenharmony_ci ext4_free_blocks(handle, inode, NULL, nr, 1, 197862306a36Sopenharmony_ci EXT4_FREE_BLOCKS_METADATA | 197962306a36Sopenharmony_ci EXT4_FREE_BLOCKS_FORGET); 198062306a36Sopenharmony_ci ei->i_data[EXT4_DIND_BLOCK] = 0; 198162306a36Sopenharmony_ci inode->i_blocks = 0; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci err = ext4_mark_inode_dirty(handle, inode); 198462306a36Sopenharmony_ci if (err) 198562306a36Sopenharmony_ci ext4_std_error(sb, err); 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_cierrout: 198962306a36Sopenharmony_ci ret = ext4_journal_stop(handle); 199062306a36Sopenharmony_ci return err ? err : ret; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ciinvalid_resize_inode: 199362306a36Sopenharmony_ci ext4_error(sb, "corrupted/inconsistent resize inode"); 199462306a36Sopenharmony_ci return -EINVAL; 199562306a36Sopenharmony_ci} 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci/* 199862306a36Sopenharmony_ci * ext4_resize_fs() resizes a fs to new size specified by @n_blocks_count 199962306a36Sopenharmony_ci * 200062306a36Sopenharmony_ci * @sb: super block of the fs to be resized 200162306a36Sopenharmony_ci * @n_blocks_count: the number of blocks resides in the resized fs 200262306a36Sopenharmony_ci */ 200362306a36Sopenharmony_ciint ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) 200462306a36Sopenharmony_ci{ 200562306a36Sopenharmony_ci struct ext4_new_flex_group_data *flex_gd = NULL; 200662306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(sb); 200762306a36Sopenharmony_ci struct ext4_super_block *es = sbi->s_es; 200862306a36Sopenharmony_ci struct buffer_head *bh; 200962306a36Sopenharmony_ci struct inode *resize_inode = NULL; 201062306a36Sopenharmony_ci ext4_grpblk_t add, offset; 201162306a36Sopenharmony_ci unsigned long n_desc_blocks; 201262306a36Sopenharmony_ci unsigned long o_desc_blocks; 201362306a36Sopenharmony_ci ext4_group_t o_group; 201462306a36Sopenharmony_ci ext4_group_t n_group; 201562306a36Sopenharmony_ci ext4_fsblk_t o_blocks_count; 201662306a36Sopenharmony_ci ext4_fsblk_t n_blocks_count_retry = 0; 201762306a36Sopenharmony_ci unsigned long last_update_time = 0; 201862306a36Sopenharmony_ci int err = 0; 201962306a36Sopenharmony_ci int meta_bg; 202062306a36Sopenharmony_ci unsigned int flexbg_size = ext4_flex_bg_size(sbi); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci /* See if the device is actually as big as what was requested */ 202362306a36Sopenharmony_ci bh = ext4_sb_bread(sb, n_blocks_count - 1, 0); 202462306a36Sopenharmony_ci if (IS_ERR(bh)) { 202562306a36Sopenharmony_ci ext4_warning(sb, "can't read last block, resize aborted"); 202662306a36Sopenharmony_ci return -ENOSPC; 202762306a36Sopenharmony_ci } 202862306a36Sopenharmony_ci brelse(bh); 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci /* 203162306a36Sopenharmony_ci * For bigalloc, trim the requested size to the nearest cluster 203262306a36Sopenharmony_ci * boundary to avoid creating an unusable filesystem. We do this 203362306a36Sopenharmony_ci * silently, instead of returning an error, to avoid breaking 203462306a36Sopenharmony_ci * callers that blindly resize the filesystem to the full size of 203562306a36Sopenharmony_ci * the underlying block device. 203662306a36Sopenharmony_ci */ 203762306a36Sopenharmony_ci if (ext4_has_feature_bigalloc(sb)) 203862306a36Sopenharmony_ci n_blocks_count &= ~((1 << EXT4_CLUSTER_BITS(sb)) - 1); 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ciretry: 204162306a36Sopenharmony_ci o_blocks_count = ext4_blocks_count(es); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci ext4_msg(sb, KERN_INFO, "resizing filesystem from %llu " 204462306a36Sopenharmony_ci "to %llu blocks", o_blocks_count, n_blocks_count); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci if (n_blocks_count < o_blocks_count) { 204762306a36Sopenharmony_ci /* On-line shrinking not supported */ 204862306a36Sopenharmony_ci ext4_warning(sb, "can't shrink FS - resize aborted"); 204962306a36Sopenharmony_ci return -EINVAL; 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci if (n_blocks_count == o_blocks_count) 205362306a36Sopenharmony_ci /* Nothing need to do */ 205462306a36Sopenharmony_ci return 0; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci n_group = ext4_get_group_number(sb, n_blocks_count - 1); 205762306a36Sopenharmony_ci if (n_group >= (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { 205862306a36Sopenharmony_ci ext4_warning(sb, "resize would cause inodes_count overflow"); 205962306a36Sopenharmony_ci return -EINVAL; 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset); 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci n_desc_blocks = num_desc_blocks(sb, n_group + 1); 206462306a36Sopenharmony_ci o_desc_blocks = num_desc_blocks(sb, sbi->s_groups_count); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci meta_bg = ext4_has_feature_meta_bg(sb); 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci if (ext4_has_feature_resize_inode(sb)) { 206962306a36Sopenharmony_ci if (meta_bg) { 207062306a36Sopenharmony_ci ext4_error(sb, "resize_inode and meta_bg enabled " 207162306a36Sopenharmony_ci "simultaneously"); 207262306a36Sopenharmony_ci return -EINVAL; 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci if (n_desc_blocks > o_desc_blocks + 207562306a36Sopenharmony_ci le16_to_cpu(es->s_reserved_gdt_blocks)) { 207662306a36Sopenharmony_ci n_blocks_count_retry = n_blocks_count; 207762306a36Sopenharmony_ci n_desc_blocks = o_desc_blocks + 207862306a36Sopenharmony_ci le16_to_cpu(es->s_reserved_gdt_blocks); 207962306a36Sopenharmony_ci n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb); 208062306a36Sopenharmony_ci n_blocks_count = (ext4_fsblk_t)n_group * 208162306a36Sopenharmony_ci EXT4_BLOCKS_PER_GROUP(sb) + 208262306a36Sopenharmony_ci le32_to_cpu(es->s_first_data_block); 208362306a36Sopenharmony_ci n_group--; /* set to last group number */ 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci if (!resize_inode) 208762306a36Sopenharmony_ci resize_inode = ext4_iget(sb, EXT4_RESIZE_INO, 208862306a36Sopenharmony_ci EXT4_IGET_SPECIAL); 208962306a36Sopenharmony_ci if (IS_ERR(resize_inode)) { 209062306a36Sopenharmony_ci ext4_warning(sb, "Error opening resize inode"); 209162306a36Sopenharmony_ci return PTR_ERR(resize_inode); 209262306a36Sopenharmony_ci } 209362306a36Sopenharmony_ci } 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci if ((!resize_inode && !meta_bg) || n_blocks_count == o_blocks_count) { 209662306a36Sopenharmony_ci err = ext4_convert_meta_bg(sb, resize_inode); 209762306a36Sopenharmony_ci if (err) 209862306a36Sopenharmony_ci goto out; 209962306a36Sopenharmony_ci if (resize_inode) { 210062306a36Sopenharmony_ci iput(resize_inode); 210162306a36Sopenharmony_ci resize_inode = NULL; 210262306a36Sopenharmony_ci } 210362306a36Sopenharmony_ci if (n_blocks_count_retry) { 210462306a36Sopenharmony_ci n_blocks_count = n_blocks_count_retry; 210562306a36Sopenharmony_ci n_blocks_count_retry = 0; 210662306a36Sopenharmony_ci goto retry; 210762306a36Sopenharmony_ci } 210862306a36Sopenharmony_ci } 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci /* 211162306a36Sopenharmony_ci * Make sure the last group has enough space so that it's 211262306a36Sopenharmony_ci * guaranteed to have enough space for all metadata blocks 211362306a36Sopenharmony_ci * that it might need to hold. (We might not need to store 211462306a36Sopenharmony_ci * the inode table blocks in the last block group, but there 211562306a36Sopenharmony_ci * will be cases where this might be needed.) 211662306a36Sopenharmony_ci */ 211762306a36Sopenharmony_ci if ((ext4_group_first_block_no(sb, n_group) + 211862306a36Sopenharmony_ci ext4_group_overhead_blocks(sb, n_group) + 2 + 211962306a36Sopenharmony_ci sbi->s_itb_per_group + sbi->s_cluster_ratio) >= n_blocks_count) { 212062306a36Sopenharmony_ci n_blocks_count = ext4_group_first_block_no(sb, n_group); 212162306a36Sopenharmony_ci n_group--; 212262306a36Sopenharmony_ci n_blocks_count_retry = 0; 212362306a36Sopenharmony_ci if (resize_inode) { 212462306a36Sopenharmony_ci iput(resize_inode); 212562306a36Sopenharmony_ci resize_inode = NULL; 212662306a36Sopenharmony_ci } 212762306a36Sopenharmony_ci goto retry; 212862306a36Sopenharmony_ci } 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci /* extend the last group */ 213162306a36Sopenharmony_ci if (n_group == o_group) 213262306a36Sopenharmony_ci add = n_blocks_count - o_blocks_count; 213362306a36Sopenharmony_ci else 213462306a36Sopenharmony_ci add = EXT4_C2B(sbi, EXT4_CLUSTERS_PER_GROUP(sb) - (offset + 1)); 213562306a36Sopenharmony_ci if (add > 0) { 213662306a36Sopenharmony_ci err = ext4_group_extend_no_check(sb, o_blocks_count, add); 213762306a36Sopenharmony_ci if (err) 213862306a36Sopenharmony_ci goto out; 213962306a36Sopenharmony_ci } 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci if (ext4_blocks_count(es) == n_blocks_count && n_blocks_count_retry == 0) 214262306a36Sopenharmony_ci goto out; 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci err = ext4_alloc_flex_bg_array(sb, n_group + 1); 214562306a36Sopenharmony_ci if (err) 214662306a36Sopenharmony_ci goto out; 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci err = ext4_mb_alloc_groupinfo(sb, n_group + 1); 214962306a36Sopenharmony_ci if (err) 215062306a36Sopenharmony_ci goto out; 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci flex_gd = alloc_flex_gd(flexbg_size); 215362306a36Sopenharmony_ci if (flex_gd == NULL) { 215462306a36Sopenharmony_ci err = -ENOMEM; 215562306a36Sopenharmony_ci goto out; 215662306a36Sopenharmony_ci } 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci /* Add flex groups. Note that a regular group is a 215962306a36Sopenharmony_ci * flex group with 1 group. 216062306a36Sopenharmony_ci */ 216162306a36Sopenharmony_ci while (ext4_setup_next_flex_gd(sb, flex_gd, n_blocks_count)) { 216262306a36Sopenharmony_ci if (time_is_before_jiffies(last_update_time + HZ * 10)) { 216362306a36Sopenharmony_ci if (last_update_time) 216462306a36Sopenharmony_ci ext4_msg(sb, KERN_INFO, 216562306a36Sopenharmony_ci "resized to %llu blocks", 216662306a36Sopenharmony_ci ext4_blocks_count(es)); 216762306a36Sopenharmony_ci last_update_time = jiffies; 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci if (ext4_alloc_group_tables(sb, flex_gd, flexbg_size) != 0) 217062306a36Sopenharmony_ci break; 217162306a36Sopenharmony_ci err = ext4_flex_group_add(sb, resize_inode, flex_gd); 217262306a36Sopenharmony_ci if (unlikely(err)) 217362306a36Sopenharmony_ci break; 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci if (!err && n_blocks_count_retry) { 217762306a36Sopenharmony_ci n_blocks_count = n_blocks_count_retry; 217862306a36Sopenharmony_ci n_blocks_count_retry = 0; 217962306a36Sopenharmony_ci free_flex_gd(flex_gd); 218062306a36Sopenharmony_ci flex_gd = NULL; 218162306a36Sopenharmony_ci if (resize_inode) { 218262306a36Sopenharmony_ci iput(resize_inode); 218362306a36Sopenharmony_ci resize_inode = NULL; 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci goto retry; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ciout: 218962306a36Sopenharmony_ci if (flex_gd) 219062306a36Sopenharmony_ci free_flex_gd(flex_gd); 219162306a36Sopenharmony_ci if (resize_inode != NULL) 219262306a36Sopenharmony_ci iput(resize_inode); 219362306a36Sopenharmony_ci if (err) 219462306a36Sopenharmony_ci ext4_warning(sb, "error (%d) occurred during " 219562306a36Sopenharmony_ci "file system resize", err); 219662306a36Sopenharmony_ci ext4_msg(sb, KERN_INFO, "resized filesystem to %llu", 219762306a36Sopenharmony_ci ext4_blocks_count(es)); 219862306a36Sopenharmony_ci return err; 219962306a36Sopenharmony_ci} 2200