btrfs: zoned: use greedy gc for auto reclaim
authorJohannes Thumshirn <johannes.thumshirn@wdc.com>
Thu, 14 Oct 2021 09:39:02 +0000 (18:39 +0900)
committerDavid Sterba <dsterba@suse.com>
Tue, 26 Oct 2021 17:08:07 +0000 (19:08 +0200)
Currently auto reclaim of unusable zones reclaims the block-groups in
the order they have been added to the reclaim list.

Change this to a greedy algorithm by sorting the list so we have the
block-groups with the least amount of valid bytes reclaimed first.

Note: we can't splice the block groups from reclaim_bgs to let the sort
happen outside of the lock. The block groups can be still in use by
other parts eg. via bg_list and we must hold unused_bgs_lock while
processing them.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: David Sterba <dsterba@suse.com>
[ write note and comment why we can't splice the list ]
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/block-group.c

index 7dba9028c80c0fe26df9a3c5e241161e95167e34..de9aeb3733cfbb38bd1fa0547ccab190844941f6 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 
+#include <linux/list_sort.h>
 #include "misc.h"
 #include "ctree.h"
 #include "block-group.h"
@@ -1486,6 +1487,21 @@ void btrfs_mark_bg_unused(struct btrfs_block_group *bg)
        spin_unlock(&fs_info->unused_bgs_lock);
 }
 
+/*
+ * We want block groups with a low number of used bytes to be in the beginning
+ * of the list, so they will get reclaimed first.
+ */
+static int reclaim_bgs_cmp(void *unused, const struct list_head *a,
+                          const struct list_head *b)
+{
+       const struct btrfs_block_group *bg1, *bg2;
+
+       bg1 = list_entry(a, struct btrfs_block_group, bg_list);
+       bg2 = list_entry(b, struct btrfs_block_group, bg_list);
+
+       return bg1->used > bg2->used;
+}
+
 void btrfs_reclaim_bgs_work(struct work_struct *work)
 {
        struct btrfs_fs_info *fs_info =
@@ -1510,6 +1526,12 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
        }
 
        spin_lock(&fs_info->unused_bgs_lock);
+       /*
+        * Sort happens under lock because we can't simply splice it and sort.
+        * The block groups might still be in use and reachable via bg_list,
+        * and their presence in the reclaim_bgs list must be preserved.
+        */
+       list_sort(NULL, &fs_info->reclaim_bgs, reclaim_bgs_cmp);
        while (!list_empty(&fs_info->reclaim_bgs)) {
                u64 zone_unusable;
                int ret = 0;