From: Mark Harmstone <mark@harmstone.com>
To: linux-btrfs@vger.kernel.org
Cc: Mark Harmstone <mark@harmstone.com>, Boris Burkov <boris@bur.io>
Subject: [PATCH v6 16/16] btrfs: populate fully_remapped_bgs_list on mount
Date: Fri, 14 Nov 2025 18:47:21 +0000 [thread overview]
Message-ID: <20251114184745.9304-17-mark@harmstone.com> (raw)
In-Reply-To: <20251114184745.9304-1-mark@harmstone.com>
Add a function btrfs_populate_fully_remapped_bgs_list() which gets
called on mount, which looks for fully remapped block groups
(i.e. identity_remap_count == 0) which haven't yet had their chunk
stripes and device extents removed.
This happens when a filesystem is unmounted while async discard has not
yet finished, as otherwise the data range occupied by the chunk stripes
would be permanently unusable.
Signed-off-by: Mark Harmstone <mark@harmstone.com>
Reviewed-by: Boris Burkov <boris@bur.io>
---
fs/btrfs/block-group.c | 79 +++++++++++++++++++++++++++++++++++++
fs/btrfs/block-group.h | 2 +
fs/btrfs/disk-io.c | 9 +++++
fs/btrfs/free-space-cache.c | 7 ++++
fs/btrfs/relocation.c | 4 ++
5 files changed, 101 insertions(+)
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index 965ae904ec2e..de10c02d1852 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -4824,6 +4824,11 @@ void btrfs_mark_bg_fully_remapped(struct btrfs_block_group *bg,
struct btrfs_fs_info *fs_info = trans->fs_info;
if (btrfs_test_opt(fs_info, DISCARD_ASYNC)) {
+ spin_lock(&bg->lock);
+ set_bit(BLOCK_GROUP_FLAG_STRIPE_REMOVAL_PENDING,
+ &bg->runtime_flags);
+ spin_unlock(&bg->lock);
+
btrfs_discard_queue_work(&fs_info->discard_ctl, bg);
} else {
spin_lock(&fs_info->unused_bgs_lock);
@@ -4843,3 +4848,77 @@ void btrfs_mark_bg_fully_remapped(struct btrfs_block_group *bg,
spin_unlock(&fs_info->unused_bgs_lock);
}
}
+
+/*
+ * Compare the block group and chunk trees, and find any fully-remapped block
+ * groups which haven't yet had their chunk stripes and device extents removed,
+ * and put them on the fully_remapped_bgs list so this gets done.
+ *
+ * This happens when a block group becomes fully remapped, i.e. its last
+ * identity mapping is removed, and the volume is unmounted before async
+ * discard has finished. It's important this gets done as until it is the
+ * chunk's stripes are dead space.
+ */
+int btrfs_populate_fully_remapped_bgs_list(struct btrfs_fs_info *fs_info)
+{
+ struct rb_node *node_bg, *node_chunk;
+
+ node_bg = rb_first_cached(&fs_info->block_group_cache_tree);
+ node_chunk = rb_first_cached(&fs_info->mapping_tree);
+
+ while (node_bg && node_chunk) {
+ struct btrfs_block_group *bg;
+ struct btrfs_chunk_map *map;
+
+ bg = rb_entry(node_bg, struct btrfs_block_group, cache_node);
+ map = rb_entry(node_chunk, struct btrfs_chunk_map, rb_node);
+
+ ASSERT(bg->start == map->start);
+
+ if (!(bg->flags & BTRFS_BLOCK_GROUP_REMAPPED))
+ goto next;
+
+ if (bg->identity_remap_count != 0)
+ goto next;
+
+ if (map->num_stripes == 0)
+ goto next;
+
+ spin_lock(&fs_info->unused_bgs_lock);
+
+ if (list_empty(&bg->bg_list)) {
+ btrfs_get_block_group(bg);
+ list_add_tail(&bg->bg_list,
+ &fs_info->fully_remapped_bgs);
+ } else {
+ list_move_tail(&bg->bg_list,
+ &fs_info->fully_remapped_bgs);
+ }
+
+ spin_unlock(&fs_info->unused_bgs_lock);
+
+ /*
+ * Ideally we'd want to call btrfs_discard_queue_work() here,
+ * but it'd do nothing as the discard worker hasn't been
+ * started yet.
+ *
+ * The block group will get added to the discard list when
+ * btrfs_handle_fully_remapped_bgs() gets called, when we
+ * commit the first transaction.
+ */
+ if (btrfs_test_opt(fs_info, DISCARD_ASYNC)) {
+ spin_lock(&bg->lock);
+ set_bit(BLOCK_GROUP_FLAG_STRIPE_REMOVAL_PENDING,
+ &bg->runtime_flags);
+ spin_unlock(&bg->lock);
+ }
+
+next:
+ node_bg = rb_next(node_bg);
+ node_chunk = rb_next(node_chunk);
+ }
+
+ ASSERT(!node_bg && !node_chunk);
+
+ return 0;
+}
diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h
index b0b16efea19a..03e8ad8a2ec7 100644
--- a/fs/btrfs/block-group.h
+++ b/fs/btrfs/block-group.h
@@ -93,6 +93,7 @@ enum btrfs_block_group_flags {
* transaction.
*/
BLOCK_GROUP_FLAG_NEW,
+ BLOCK_GROUP_FLAG_STRIPE_REMOVAL_PENDING,
};
enum btrfs_caching_type {
@@ -416,5 +417,6 @@ int btrfs_use_block_group_size_class(struct btrfs_block_group *bg,
bool btrfs_block_group_should_use_size_class(const struct btrfs_block_group *bg);
void btrfs_mark_bg_fully_remapped(struct btrfs_block_group *bg,
struct btrfs_trans_handle *trans);
+int btrfs_populate_fully_remapped_bgs_list(struct btrfs_fs_info *fs_info);
#endif /* BTRFS_BLOCK_GROUP_H */
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 53221a0131fb..177a33cd9815 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3656,6 +3656,15 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
goto fail_sysfs;
}
+ if (btrfs_fs_incompat(fs_info, REMAP_TREE)) {
+ ret = btrfs_populate_fully_remapped_bgs_list(fs_info);
+ if (ret) {
+ btrfs_err(fs_info,
+ "failed to populate fully_remapped_bgs list: %d", ret);
+ goto fail_sysfs;
+ }
+ }
+
btrfs_zoned_reserve_data_reloc_bg(fs_info);
btrfs_free_zone_cache(fs_info);
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 1b8716b17031..ce853a9c0a4c 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -3068,6 +3068,7 @@ bool btrfs_is_free_space_trimmed(struct btrfs_block_group *block_group)
bool ret = true;
if (block_group->flags & BTRFS_BLOCK_GROUP_REMAPPED &&
+ !test_bit(BLOCK_GROUP_FLAG_STRIPE_REMOVAL_PENDING, &block_group->runtime_flags) &&
block_group->identity_remap_count == 0) {
return true;
}
@@ -3850,6 +3851,11 @@ void btrfs_trim_fully_remapped_block_group(struct btrfs_block_group *bg)
u64 end = btrfs_block_group_end(bg);
struct btrfs_chunk_map *map;
+ if (!test_bit(BLOCK_GROUP_FLAG_STRIPE_REMOVAL_PENDING, &bg->runtime_flags)) {
+ bg->discard_cursor = end;
+ goto skip_discard;
+ }
+
bytes = end - bg->discard_cursor;
if (max_discard_size &&
@@ -3888,6 +3894,7 @@ void btrfs_trim_fully_remapped_block_group(struct btrfs_block_group *bg)
btrfs_free_chunk_map(map);
+skip_discard:
if (bg->used == 0) {
spin_lock(&fs_info->unused_bgs_lock);
if (!list_empty(&bg->bg_list)) {
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 15c4a7c6b1ef..276201fe8f2d 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -4788,6 +4788,10 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk,
btrfs_remove_bg_from_sinfo(bg);
+ spin_lock(&bg->lock);
+ clear_bit(BLOCK_GROUP_FLAG_STRIPE_REMOVAL_PENDING, &bg->runtime_flags);
+ spin_unlock(&bg->lock);
+
ret = remove_chunk_stripes(trans, chunk, path);
if (ret) {
btrfs_abort_transaction(trans, ret);
--
2.51.0
prev parent reply other threads:[~2025-11-14 18:48 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-14 18:47 [PATCH v6 00/16] Remap tree Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 01/16] btrfs: add definitions and constants for remap-tree Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 02/16] btrfs: add REMAP chunk type Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 03/16] btrfs: allow remapped chunks to have zero stripes Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 04/16] btrfs: remove remapped block groups from the free-space tree Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 05/16] btrfs: don't add metadata items for the remap tree to the extent tree Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 06/16] btrfs: add extended version of struct block_group_item Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 07/16] btrfs: allow mounting filesystems with remap-tree incompat flag Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 08/16] btrfs: redirect I/O for remapped block groups Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 09/16] btrfs: handle deletions from remapped block group Mark Harmstone
2025-11-20 0:17 ` Boris Burkov
2025-11-24 12:40 ` Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 10/16] btrfs: handle setting up relocation of block group with remap-tree Mark Harmstone
2025-11-15 14:52 ` Sun Yangkai
2025-11-24 18:01 ` Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 11/16] btrfs: move existing remaps before relocating block group Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 12/16] btrfs: replace identity remaps with actual remaps when doing relocations Mark Harmstone
2025-11-20 0:21 ` Boris Burkov
2025-11-14 18:47 ` [PATCH v6 13/16] btrfs: add do_remap param to btrfs_discard_extent() Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 14/16] btrfs: allow balancing remap tree Mark Harmstone
2025-11-14 18:47 ` [PATCH v6 15/16] btrfs: handle discarding fully-remapped block groups Mark Harmstone
2025-11-20 0:19 ` Boris Burkov
2025-11-14 18:47 ` Mark Harmstone [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251114184745.9304-17-mark@harmstone.com \
--to=mark@harmstone.com \
--cc=boris@bur.io \
--cc=linux-btrfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox