]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
btrfs: add do_remap parameter to btrfs_discard_extent()
authorMark Harmstone <mark@harmstone.com>
Wed, 7 Jan 2026 14:09:14 +0000 (14:09 +0000)
committerDavid Sterba <dsterba@suse.com>
Tue, 3 Feb 2026 06:54:35 +0000 (07:54 +0100)
btrfs_discard_extent() can be called either when an extent is removed
or from walking the free-space tree. With a remapped block group these
two things are no longer equivalent: the extent's addresses are
remapped, while the free-space tree exclusively uses underlying
addresses.

Add a do_remap parameter to btrfs_discard_extent() and
btrfs_map_discard(), saying whether or not the address needs to be run
through the remap tree first.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Mark Harmstone <mark@harmstone.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/extent-tree.c
fs/btrfs/extent-tree.h
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h

index ebff087b4e89f09d067a5a2d56c83512a20d5fc2..c063c5b6c433a138b5dd1305278dd5ab76e4fab1 100644 (file)
@@ -1381,7 +1381,7 @@ out:
 }
 
 int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
-                        u64 num_bytes, u64 *actual_bytes)
+                        u64 num_bytes, u64 *actual_bytes, bool do_remap)
 {
        int ret = 0;
        u64 discarded_bytes = 0;
@@ -1399,7 +1399,8 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
                int i;
 
                num_bytes = end - cur;
-               stripes = btrfs_map_discard(fs_info, cur, &num_bytes, &num_stripes);
+               stripes = btrfs_map_discard(fs_info, cur, &num_bytes, &num_stripes,
+                                           do_remap);
                if (IS_ERR(stripes)) {
                        ret = PTR_ERR(stripes);
                        if (ret == -EOPNOTSUPP)
@@ -2936,7 +2937,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
 
                if (btrfs_test_opt(fs_info, DISCARD_SYNC))
                        ret = btrfs_discard_extent(fs_info, start,
-                                                  end + 1 - start, NULL);
+                                                  end + 1 - start, NULL, true);
 
                next_state = btrfs_next_extent_state(unpin, cached_state);
                btrfs_clear_extent_dirty(unpin, start, end, &cached_state);
@@ -2994,7 +2995,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
                ret = -EROFS;
                if (!TRANS_ABORTED(trans))
                        ret = btrfs_discard_extent(fs_info, block_group->start,
-                                                  block_group->length, NULL);
+                                                  block_group->length, NULL, true);
 
                /*
                 * Not strictly necessary to lock, as the block_group should be
index d7b6aeb636563d3e4f7fb52d580c7ca1923434a6..ff330d4896d6686d02121d2779ed9c9d17180ffa 100644 (file)
@@ -161,7 +161,7 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
                        struct extent_buffer *parent);
 void btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info, u64 start, u64 end);
 int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
-                        u64 num_bytes, u64 *actual_bytes);
+                        u64 num_bytes, u64 *actual_bytes, bool do_remap);
 int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range);
 void btrfs_handle_fully_remapped_bgs(struct btrfs_fs_info *fs_info);
 int btrfs_complete_bg_remapping(struct btrfs_block_group *bg);
index 8d4db3d57cf74784e2bcdecb99a670f1b0956de1..17e79ee3e021603c50af56989dd21c55b8d4f5c7 100644 (file)
@@ -3677,7 +3677,7 @@ static int do_trimming(struct btrfs_block_group *block_group,
        }
        spin_unlock(&space_info->lock);
 
-       ret = btrfs_discard_extent(fs_info, start, bytes, &trimmed);
+       ret = btrfs_discard_extent(fs_info, start, bytes, &trimmed, false);
        if (!ret) {
                *total_trimmed += trimmed;
                trim_state = BTRFS_TRIM_STATE_TRIMMED;
index be47aa58e944ee2e83375484e6dcd877583331f2..691aa5119c0bde3391ee549a184e7b4d383b98f0 100644 (file)
@@ -3366,7 +3366,7 @@ out:
                                btrfs_discard_extent(fs_info,
                                                ordered_extent->disk_bytenr,
                                                ordered_extent->disk_num_bytes,
-                                               NULL);
+                                               NULL, true);
                        btrfs_free_reserved_extent(fs_info,
                                        ordered_extent->disk_bytenr,
                                        ordered_extent->disk_num_bytes, true);
index e85ffeda006d6915ca89fb0e221ad82be805d738..d42b8d50aea2356b65b142f10b443833701ccdf3 100644 (file)
@@ -3419,7 +3419,7 @@ static int btrfs_relocate_chunk_finish(struct btrfs_fs_info *fs_info,
         * filesystem's point of view.
         */
        if (btrfs_is_zoned(fs_info)) {
-               ret = btrfs_discard_extent(fs_info, bg->start, length, NULL);
+               ret = btrfs_discard_extent(fs_info, bg->start, length, NULL, true);
                if (ret)
                        btrfs_info(fs_info, "failed to reset zone %llu after relocation",
                                   bg->start);
@@ -6101,7 +6101,7 @@ void btrfs_put_bioc(struct btrfs_io_context *bioc)
  */
 struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
                                               u64 logical, u64 *length_ret,
-                                              u32 *num_stripes)
+                                              u32 *num_stripes, bool do_remap)
 {
        struct btrfs_chunk_map *map;
        struct btrfs_discard_stripe *stripes;
@@ -6125,6 +6125,24 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
        if (IS_ERR(map))
                return ERR_CAST(map);
 
+       if (do_remap && (map->type & BTRFS_BLOCK_GROUP_REMAPPED)) {
+               u64 new_logical = logical;
+
+               ret = btrfs_translate_remap(fs_info, &new_logical, &length);
+               if (ret)
+                       goto out_free_map;
+
+               if (new_logical != logical) {
+                       btrfs_free_chunk_map(map);
+
+                       map = btrfs_get_chunk_map(fs_info, new_logical, length);
+                       if (IS_ERR(map))
+                               return ERR_CAST(map);
+
+                       logical = new_logical;
+               }
+       }
+
        /* we don't discard raid56 yet */
        if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
                ret = -EOPNOTSUPP;
index ed1f8fd95fff3fc3c1113ad5a17548b194998846..e4644352314ad909383e0f2da17d131979bcd587 100644 (file)
@@ -714,7 +714,7 @@ int btrfs_map_repair_block(struct btrfs_fs_info *fs_info,
                           u32 length, int mirror_num);
 struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
                                               u64 logical, u64 *length_ret,
-                                              u32 *num_stripes);
+                                              u32 *num_stripes, bool do_remap);
 int btrfs_read_sys_array(struct btrfs_fs_info *fs_info);
 int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info);
 struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans,