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