btrfs: zoned: advance allocation pointer after tree log node
authorNaohiro Aota <naohiro.aota@wdc.com>
Thu, 4 Feb 2021 10:21:55 +0000 (19:21 +0900)
committerDavid Sterba <dsterba@suse.com>
Tue, 9 Feb 2021 01:46:04 +0000 (02:46 +0100)
Since the allocation info of a tree log node is not recorded in the extent
tree, calculate_alloc_pointer() cannot detect this node, so the pointer
can be over a tree node.

Replaying the log calls btrfs_remove_free_space() for each node in the
log tree.

So, advance the pointer after the node to not allocate over it.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/free-space-cache.c

index d2a4318..5400294 100644 (file)
@@ -2628,8 +2628,22 @@ int btrfs_remove_free_space(struct btrfs_block_group *block_group,
        int ret;
        bool re_search = false;
 
-       if (btrfs_is_zoned(block_group->fs_info))
+       if (btrfs_is_zoned(block_group->fs_info)) {
+               /*
+                * This can happen with conventional zones when replaying log.
+                * Since the allocation info of tree-log nodes are not recorded
+                * to the extent-tree, calculate_alloc_pointer() failed to
+                * advance the allocation pointer after last allocated tree log
+                * node blocks.
+                *
+                * This function is called from
+                * btrfs_pin_extent_for_log_replay() when replaying the log.
+                * Advance the pointer not to overwrite the tree-log nodes.
+                */
+               if (block_group->alloc_offset < offset + bytes)
+                       block_group->alloc_offset = offset + bytes;
                return 0;
+       }
 
        spin_lock(&ctl->tree_lock);