--- /dev/null
+From 6bc6c2bdf1baca6522b8d9ba976257d722423085 Mon Sep 17 00:00:00 2001
+From: Ritesh Harjani <riteshh@linux.ibm.com>
+Date: Wed, 16 Feb 2022 12:32:49 +0530
+Subject: ext4: add ext4_sb_block_valid() refactored out of ext4_inode_block_valid()
+
+From: Ritesh Harjani <riteshh@linux.ibm.com>
+
+commit 6bc6c2bdf1baca6522b8d9ba976257d722423085 upstream.
+
+This API will be needed at places where we don't have an inode
+for e.g. while freeing blocks in ext4_group_add_blocks()
+
+Suggested-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Ritesh Harjani <riteshh@linux.ibm.com>
+Link: https://lore.kernel.org/r/dd34a236543ad5ae7123eeebe0cb69e6bdd44f34.1644992610.git.riteshh@linux.ibm.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/block_validity.c | 26 +++++++++++++++++---------
+ fs/ext4/ext4.h | 3 +++
+ 2 files changed, 20 insertions(+), 9 deletions(-)
+
+--- a/fs/ext4/block_validity.c
++++ b/fs/ext4/block_validity.c
+@@ -292,15 +292,10 @@ void ext4_release_system_zone(struct sup
+ call_rcu(&system_blks->rcu, ext4_destroy_system_zone);
+ }
+
+-/*
+- * Returns 1 if the passed-in block region (start_blk,
+- * start_blk+count) is valid; 0 if some part of the block region
+- * overlaps with some other filesystem metadata blocks.
+- */
+-int ext4_inode_block_valid(struct inode *inode, ext4_fsblk_t start_blk,
+- unsigned int count)
++int ext4_sb_block_valid(struct super_block *sb, struct inode *inode,
++ ext4_fsblk_t start_blk, unsigned int count)
+ {
+- struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
++ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_system_blocks *system_blks;
+ struct ext4_system_zone *entry;
+ struct rb_node *n;
+@@ -329,7 +324,9 @@ int ext4_inode_block_valid(struct inode
+ else if (start_blk >= (entry->start_blk + entry->count))
+ n = n->rb_right;
+ else {
+- ret = (entry->ino == inode->i_ino);
++ ret = 0;
++ if (inode)
++ ret = (entry->ino == inode->i_ino);
+ break;
+ }
+ }
+@@ -338,6 +335,17 @@ out_rcu:
+ return ret;
+ }
+
++/*
++ * Returns 1 if the passed-in block region (start_blk,
++ * start_blk+count) is valid; 0 if some part of the block region
++ * overlaps with some other filesystem metadata blocks.
++ */
++int ext4_inode_block_valid(struct inode *inode, ext4_fsblk_t start_blk,
++ unsigned int count)
++{
++ return ext4_sb_block_valid(inode->i_sb, inode, start_blk, count);
++}
++
+ int ext4_check_blockref(const char *function, unsigned int line,
+ struct inode *inode, __le32 *p, unsigned int max)
+ {
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -3698,6 +3698,9 @@ extern int ext4_inode_block_valid(struct
+ unsigned int count);
+ extern int ext4_check_blockref(const char *, unsigned int,
+ struct inode *, __le32 *, unsigned int);
++extern int ext4_sb_block_valid(struct super_block *sb, struct inode *inode,
++ ext4_fsblk_t start_blk, unsigned int count);
++
+
+ /* extents.c */
+ struct ext4_ext_path;
--- /dev/null
+From 8ac3939db99f99667b8eb670cf4baf292896e72d Mon Sep 17 00:00:00 2001
+From: Ritesh Harjani <riteshh@linux.ibm.com>
+Date: Wed, 16 Feb 2022 12:32:45 +0530
+Subject: ext4: refactor ext4_free_blocks() to pull out ext4_mb_clear_bb()
+
+From: Ritesh Harjani <riteshh@linux.ibm.com>
+
+commit 8ac3939db99f99667b8eb670cf4baf292896e72d upstream.
+
+ext4_free_blocks() function became too long and confusing, this patch
+just pulls out the ext4_mb_clear_bb() function logic from it
+which clears the block bitmap and frees it.
+
+No functionality change in this patch
+
+Signed-off-by: Ritesh Harjani <riteshh@linux.ibm.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/22c30fbb26ba409cf8aa5f0c7912970272c459e8.1644992610.git.riteshh@linux.ibm.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/mballoc.c | 180 ++++++++++++++++++++++++++++++------------------------
+ 1 file changed, 102 insertions(+), 78 deletions(-)
+
+--- a/fs/ext4/mballoc.c
++++ b/fs/ext4/mballoc.c
+@@ -5888,7 +5888,8 @@ static void ext4_free_blocks_simple(stru
+ }
+
+ /**
+- * ext4_free_blocks() -- Free given blocks and update quota
++ * ext4_mb_clear_bb() -- helper function for freeing blocks.
++ * Used by ext4_free_blocks()
+ * @handle: handle for this transaction
+ * @inode: inode
+ * @bh: optional buffer of the block to be freed
+@@ -5896,9 +5897,9 @@ static void ext4_free_blocks_simple(stru
+ * @count: number of blocks to be freed
+ * @flags: flags used by ext4_free_blocks
+ */
+-void ext4_free_blocks(handle_t *handle, struct inode *inode,
+- struct buffer_head *bh, ext4_fsblk_t block,
+- unsigned long count, int flags)
++static void ext4_mb_clear_bb(handle_t *handle, struct inode *inode,
++ ext4_fsblk_t block, unsigned long count,
++ int flags)
+ {
+ struct buffer_head *bitmap_bh = NULL;
+ struct super_block *sb = inode->i_sb;
+@@ -5915,80 +5916,6 @@ void ext4_free_blocks(handle_t *handle,
+
+ sbi = EXT4_SB(sb);
+
+- if (sbi->s_mount_state & EXT4_FC_REPLAY) {
+- ext4_free_blocks_simple(inode, block, count);
+- return;
+- }
+-
+- might_sleep();
+- if (bh) {
+- if (block)
+- BUG_ON(block != bh->b_blocknr);
+- else
+- block = bh->b_blocknr;
+- }
+-
+- if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) &&
+- !ext4_inode_block_valid(inode, block, count)) {
+- ext4_error(sb, "Freeing blocks not in datazone - "
+- "block = %llu, count = %lu", block, count);
+- goto error_return;
+- }
+-
+- ext4_debug("freeing block %llu\n", block);
+- trace_ext4_free_blocks(inode, block, count, flags);
+-
+- if (bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
+- BUG_ON(count > 1);
+-
+- ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
+- inode, bh, block);
+- }
+-
+- /*
+- * If the extent to be freed does not begin on a cluster
+- * boundary, we need to deal with partial clusters at the
+- * beginning and end of the extent. Normally we will free
+- * blocks at the beginning or the end unless we are explicitly
+- * requested to avoid doing so.
+- */
+- overflow = EXT4_PBLK_COFF(sbi, block);
+- if (overflow) {
+- if (flags & EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER) {
+- overflow = sbi->s_cluster_ratio - overflow;
+- block += overflow;
+- if (count > overflow)
+- count -= overflow;
+- else
+- return;
+- } else {
+- block -= overflow;
+- count += overflow;
+- }
+- }
+- overflow = EXT4_LBLK_COFF(sbi, count);
+- if (overflow) {
+- if (flags & EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER) {
+- if (count > overflow)
+- count -= overflow;
+- else
+- return;
+- } else
+- count += sbi->s_cluster_ratio - overflow;
+- }
+-
+- if (!bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
+- int i;
+- int is_metadata = flags & EXT4_FREE_BLOCKS_METADATA;
+-
+- for (i = 0; i < count; i++) {
+- cond_resched();
+- if (is_metadata)
+- bh = sb_find_get_block(inode->i_sb, block + i);
+- ext4_forget(handle, is_metadata, inode, bh, block + i);
+- }
+- }
+-
+ do_more:
+ overflow = 0;
+ ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
+@@ -6156,6 +6083,103 @@ error_return:
+ return;
+ }
+
++/**
++ * ext4_free_blocks() -- Free given blocks and update quota
++ * @handle: handle for this transaction
++ * @inode: inode
++ * @bh: optional buffer of the block to be freed
++ * @block: starting physical block to be freed
++ * @count: number of blocks to be freed
++ * @flags: flags used by ext4_free_blocks
++ */
++void ext4_free_blocks(handle_t *handle, struct inode *inode,
++ struct buffer_head *bh, ext4_fsblk_t block,
++ unsigned long count, int flags)
++{
++ struct super_block *sb = inode->i_sb;
++ unsigned int overflow;
++ struct ext4_sb_info *sbi;
++
++ sbi = EXT4_SB(sb);
++
++ if (sbi->s_mount_state & EXT4_FC_REPLAY) {
++ ext4_free_blocks_simple(inode, block, count);
++ return;
++ }
++
++ might_sleep();
++ if (bh) {
++ if (block)
++ BUG_ON(block != bh->b_blocknr);
++ else
++ block = bh->b_blocknr;
++ }
++
++ if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) &&
++ !ext4_inode_block_valid(inode, block, count)) {
++ ext4_error(sb, "Freeing blocks not in datazone - "
++ "block = %llu, count = %lu", block, count);
++ return;
++ }
++
++ ext4_debug("freeing block %llu\n", block);
++ trace_ext4_free_blocks(inode, block, count, flags);
++
++ if (bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
++ BUG_ON(count > 1);
++
++ ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
++ inode, bh, block);
++ }
++
++ /*
++ * If the extent to be freed does not begin on a cluster
++ * boundary, we need to deal with partial clusters at the
++ * beginning and end of the extent. Normally we will free
++ * blocks at the beginning or the end unless we are explicitly
++ * requested to avoid doing so.
++ */
++ overflow = EXT4_PBLK_COFF(sbi, block);
++ if (overflow) {
++ if (flags & EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER) {
++ overflow = sbi->s_cluster_ratio - overflow;
++ block += overflow;
++ if (count > overflow)
++ count -= overflow;
++ else
++ return;
++ } else {
++ block -= overflow;
++ count += overflow;
++ }
++ }
++ overflow = EXT4_LBLK_COFF(sbi, count);
++ if (overflow) {
++ if (flags & EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER) {
++ if (count > overflow)
++ count -= overflow;
++ else
++ return;
++ } else
++ count += sbi->s_cluster_ratio - overflow;
++ }
++
++ if (!bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
++ int i;
++ int is_metadata = flags & EXT4_FREE_BLOCKS_METADATA;
++
++ for (i = 0; i < count; i++) {
++ cond_resched();
++ if (is_metadata)
++ bh = sb_find_get_block(inode->i_sb, block + i);
++ ext4_forget(handle, is_metadata, inode, bh, block + i);
++ }
++ }
++
++ ext4_mb_clear_bb(handle, inode, block, count, flags);
++ return;
++}
++
+ /**
+ * ext4_group_add_blocks() -- Add given blocks to an existing group
+ * @handle: handle to this transaction