btrfs: balance btree dirty pages and delayed items after clone and dedupe
authorFilipe Manana <fdmanana@suse.com>
Tue, 31 May 2022 15:06:34 +0000 (16:06 +0100)
committerDavid Sterba <dsterba@suse.com>
Mon, 25 Jul 2022 15:44:35 +0000 (17:44 +0200)
When reflinking extents (clone and deduplication), we need to touch the
btree of the destination inode's subvolume, as well as potentially
create a delayed inode for the destination inode (if it was not created
before). However we are neither balancing the btree dirty pages nor the
delayed items after such operations, so if we have a task that is doing
a long series of clone or deduplication operations, it can result in
accumulation of too many btree dirty pages and delayed items.

So just call btrfs_btree_balance_dirty() after clone and deduplication,
just like we do for every other system call that results on modifying a
btree and adding delayed items.

Reviewed-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/reflink.c

index e30f53bd4e558170fa8bc78d84f2e873623449ef..8a6cabdb8f93288cc56511df575fc9d8324b5642 100644 (file)
@@ -5,6 +5,7 @@
 #include "compression.h"
 #include "ctree.h"
 #include "delalloc-space.h"
+#include "disk-io.h"
 #include "reflink.h"
 #include "transaction.h"
 #include "subpage.h"
@@ -655,7 +656,8 @@ static void btrfs_double_mmap_unlock(struct inode *inode1, struct inode *inode2)
 static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 len,
                                   struct inode *dst, u64 dst_loff)
 {
-       const u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
+       struct btrfs_fs_info *fs_info = BTRFS_I(src)->root->fs_info;
+       const u64 bs = fs_info->sb->s_blocksize;
        int ret;
 
        /*
@@ -666,6 +668,8 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 len,
        ret = btrfs_clone(src, dst, loff, len, ALIGN(len, bs), dst_loff, 1);
        btrfs_double_extent_unlock(src, loff, dst, dst_loff, len);
 
+       btrfs_btree_balance_dirty(fs_info);
+
        return ret;
 }
 
@@ -775,6 +779,8 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
                                round_down(destoff, PAGE_SIZE),
                                round_up(destoff + len, PAGE_SIZE) - 1);
 
+       btrfs_btree_balance_dirty(fs_info);
+
        return ret;
 }