]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
btrfs: zoned: activate metadata block group on flush_space
authorNaohiro Aota <naohiro.aota@wdc.com>
Fri, 8 Jul 2022 23:18:47 +0000 (08:18 +0900)
committerDavid Sterba <dsterba@suse.com>
Mon, 25 Jul 2022 15:45:42 +0000 (17:45 +0200)
For metadata space on zoned filesystem, reaching ALLOC_CHUNK{,_FORCE}
means we don't have enough space left in the active_total_bytes. Before
allocating a new chunk, we can try to activate an existing block group
in this case.

Also, allocating a chunk is not enough to grant a ticket for metadata
space on zoned filesystem we need to activate the block group to
increase the active_total_bytes.

btrfs_zoned_activate_one_bg() implements the activation feature. It will
activate a block group by (maybe) finishing a block group. It will give up
activating a block group if it cannot finish any block group.

CC: stable@vger.kernel.org # 5.16+
Fixes: afba2bc036b0 ("btrfs: zoned: implement active zone tracking")
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/space-info.c
fs/btrfs/zoned.c
fs/btrfs/zoned.h

index 5284312aad042c4d82d9355c9b8a7fd795536ccd..d0cbeb7ae81c12ba4bf69fe9cb5c1669b56b3890 100644 (file)
@@ -9,6 +9,7 @@
 #include "ordered-data.h"
 #include "transaction.h"
 #include "block-group.h"
+#include "zoned.h"
 
 /*
  * HOW DOES SPACE RESERVATION WORK
@@ -724,6 +725,18 @@ static void flush_space(struct btrfs_fs_info *fs_info,
                break;
        case ALLOC_CHUNK:
        case ALLOC_CHUNK_FORCE:
+               /*
+                * For metadata space on zoned filesystem, reaching here means we
+                * don't have enough space left in active_total_bytes. Try to
+                * activate a block group first, because we may have inactive
+                * block group already allocated.
+                */
+               ret = btrfs_zoned_activate_one_bg(fs_info, space_info, false);
+               if (ret < 0)
+                       break;
+               else if (ret == 1)
+                       break;
+
                trans = btrfs_join_transaction(root);
                if (IS_ERR(trans)) {
                        ret = PTR_ERR(trans);
@@ -734,6 +747,23 @@ static void flush_space(struct btrfs_fs_info *fs_info,
                                (state == ALLOC_CHUNK) ? CHUNK_ALLOC_NO_FORCE :
                                        CHUNK_ALLOC_FORCE);
                btrfs_end_transaction(trans);
+
+               /*
+                * For metadata space on zoned filesystem, allocating a new chunk
+                * is not enough. We still need to activate the block * group.
+                * Active the newly allocated block group by (maybe) finishing
+                * a block group.
+                */
+               if (ret == 1) {
+                       ret = btrfs_zoned_activate_one_bg(fs_info, space_info, true);
+                       /*
+                        * Revert to the original ret regardless we could finish
+                        * one block group or not.
+                        */
+                       if (ret >= 0)
+                               ret = 1;
+               }
+
                if (ret > 0 || ret == -ENOSPC)
                        ret = 0;
                break;
index d0a0d62c527881fda387e0666346de47eb660e73..6c391b5b417284c523e903e822355836fe24cd06 100644 (file)
@@ -2226,3 +2226,56 @@ int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)
 
        return ret < 0 ? ret : 1;
 }
+
+int btrfs_zoned_activate_one_bg(struct btrfs_fs_info *fs_info,
+                               struct btrfs_space_info *space_info,
+                               bool do_finish)
+{
+       struct btrfs_block_group *bg;
+       int index;
+
+       if (!btrfs_is_zoned(fs_info) || (space_info->flags & BTRFS_BLOCK_GROUP_DATA))
+               return 0;
+
+       /* No more block groups to activate */
+       if (space_info->active_total_bytes == space_info->total_bytes)
+               return 0;
+
+       for (;;) {
+               int ret;
+               bool need_finish = false;
+
+               down_read(&space_info->groups_sem);
+               for (index = 0; index < BTRFS_NR_RAID_TYPES; index++) {
+                       list_for_each_entry(bg, &space_info->block_groups[index],
+                                           list) {
+                               if (!spin_trylock(&bg->lock))
+                                       continue;
+                               if (btrfs_zoned_bg_is_full(bg) || bg->zone_is_active) {
+                                       spin_unlock(&bg->lock);
+                                       continue;
+                               }
+                               spin_unlock(&bg->lock);
+
+                               if (btrfs_zone_activate(bg)) {
+                                       up_read(&space_info->groups_sem);
+                                       return 1;
+                               }
+
+                               need_finish = true;
+                       }
+               }
+               up_read(&space_info->groups_sem);
+
+               if (!do_finish || !need_finish)
+                       break;
+
+               ret = btrfs_zone_finish_one_bg(fs_info);
+               if (ret == 0)
+                       break;
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
index 329d28e2fd8d6722069651ac03fc20e43a6e533f..e17462db3a842c632e8ec5b08d82fe3ad458ee96 100644 (file)
@@ -81,6 +81,8 @@ bool btrfs_zoned_should_reclaim(struct btrfs_fs_info *fs_info);
 void btrfs_zoned_release_data_reloc_bg(struct btrfs_fs_info *fs_info, u64 logical,
                                       u64 length);
 int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info);
+int btrfs_zoned_activate_one_bg(struct btrfs_fs_info *fs_info,
+                               struct btrfs_space_info *space_info, bool do_finish);
 #else /* CONFIG_BLK_DEV_ZONED */
 static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
                                     struct blk_zone *zone)
@@ -256,6 +258,14 @@ static inline int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)
        return 1;
 }
 
+static inline int btrfs_zoned_activate_one_bg(struct btrfs_fs_info *fs_info,
+                                             struct btrfs_space_info *space_info,
+                                             bool do_finish)
+{
+       /* Consider all the block groups are active */
+       return 0;
+}
+
 #endif
 
 static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)