]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
btrfs: zoned: count fresh BG region as zone unusable
authorNaohiro Aota <naohiro.aota@wdc.com>
Mon, 13 Mar 2023 07:06:13 +0000 (16:06 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 6 Apr 2023 10:10:35 +0000 (12:10 +0200)
[ Upstream commit fa2068d7e922b434eba5bfb0131e6d39febfdb48 ]

The naming of space_info->active_total_bytes is misleading. It counts
not only active block groups but also full ones which are previously
active but now inactive. That confusion results in a bug not counting
the full BGs into active_total_bytes on mount time.

For a background, there are three kinds of block groups in terms of
activation.

  1. Block groups never activated
  2. Block groups currently active
  3. Block groups previously active and currently inactive (due to fully
     written or zone finish)

What we really wanted to exclude from "total_bytes" is the total size of
BGs #1. They seem empty and allocatable but since they are not activated,
we cannot rely on them to do the space reservation.

And, since BGs #1 never get activated, they should have no "used",
"reserved" and "pinned" bytes.

OTOH, BGs #3 can be counted in the "total", since they are already full
we cannot allocate from them anyway. For them, "total_bytes == used +
reserved + pinned + zone_unusable" should hold.

Tracking #2 and #3 as "active_total_bytes" (current implementation) is
confusing. And, tracking #1 and subtract that properly from "total_bytes"
every time you need space reservation is cumbersome.

Instead, we can count the whole region of a newly allocated block group as
zone_unusable. Then, once that block group is activated, release
[0 ..  zone_capacity] from the zone_unusable counters. With this, we can
eliminate the confusing ->active_total_bytes and the code will be common
among regular and the zoned mode. Also, no additional counter is needed
with this approach.

Fixes: 6a921de58992 ("btrfs: zoned: introduce space_info->active_total_bytes")
CC: stable@vger.kernel.org # 6.1+
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/btrfs/free-space-cache.c
fs/btrfs/zoned.c

index f4023651dd68bd704a8efceb893649919573eb28..6a8f2bd350f4bd2df3694e188e244879caf6ec81 100644 (file)
@@ -2684,8 +2684,13 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group,
                bg_reclaim_threshold = READ_ONCE(sinfo->bg_reclaim_threshold);
 
        spin_lock(&ctl->tree_lock);
+       /* Count initial region as zone_unusable until it gets activated. */
        if (!used)
                to_free = size;
+       else if (initial &&
+                test_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &block_group->fs_info->flags) &&
+                (block_group->flags & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM)))
+               to_free = 0;
        else if (initial)
                to_free = block_group->zone_capacity;
        else if (offset >= block_group->alloc_offset)
@@ -2713,7 +2718,8 @@ static int __btrfs_add_free_space_zoned(struct btrfs_block_group *block_group,
        reclaimable_unusable = block_group->zone_unusable -
                               (block_group->length - block_group->zone_capacity);
        /* All the region is now unusable. Mark it as unused and reclaim */
-       if (block_group->zone_unusable == block_group->length) {
+       if (block_group->zone_unusable == block_group->length &&
+           block_group->alloc_offset) {
                btrfs_mark_bg_unused(block_group);
        } else if (bg_reclaim_threshold &&
                   reclaimable_unusable >=
index 0d88cc46ac5db5cf19b16b851473eb98d830ec2c..e97c5a1ac95d6978ad6c225a8f32e986fc8addbc 100644 (file)
@@ -1575,9 +1575,19 @@ void btrfs_calc_zone_unusable(struct btrfs_block_group *cache)
                return;
 
        WARN_ON(cache->bytes_super != 0);
-       unusable = (cache->alloc_offset - cache->used) +
-                  (cache->length - cache->zone_capacity);
-       free = cache->zone_capacity - cache->alloc_offset;
+
+       /* Check for block groups never get activated */
+       if (test_bit(BTRFS_FS_ACTIVE_ZONE_TRACKING, &cache->fs_info->flags) &&
+           cache->flags & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM) &&
+           !test_bit(BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE, &cache->runtime_flags) &&
+           cache->alloc_offset == 0) {
+               unusable = cache->length;
+               free = 0;
+       } else {
+               unusable = (cache->alloc_offset - cache->used) +
+                          (cache->length - cache->zone_capacity);
+               free = cache->zone_capacity - cache->alloc_offset;
+       }
 
        /* We only need ->free_space in ALLOC_SEQ block groups */
        cache->cached = BTRFS_CACHE_FINISHED;
@@ -1914,7 +1924,11 @@ bool btrfs_zone_activate(struct btrfs_block_group *block_group)
 
        /* Successfully activated all the zones */
        set_bit(BLOCK_GROUP_FLAG_ZONE_IS_ACTIVE, &block_group->runtime_flags);
-       space_info->active_total_bytes += block_group->length;
+       WARN_ON(block_group->alloc_offset != 0);
+       if (block_group->zone_unusable == block_group->length) {
+               block_group->zone_unusable = block_group->length - block_group->zone_capacity;
+               space_info->bytes_zone_unusable -= block_group->zone_capacity;
+       }
        spin_unlock(&block_group->lock);
        btrfs_try_granting_tickets(fs_info, space_info);
        spin_unlock(&space_info->lock);
@@ -2277,7 +2291,7 @@ int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)
                u64 avail;
 
                spin_lock(&block_group->lock);
-               if (block_group->reserved ||
+               if (block_group->reserved || block_group->alloc_offset == 0 ||
                    (block_group->flags & BTRFS_BLOCK_GROUP_SYSTEM)) {
                        spin_unlock(&block_group->lock);
                        continue;