Skip to content

Commit 1d6a4fc

Browse files
adam900710kdave
authored andcommitted
btrfs: make clear_cache mount option to rebuild FST without disabling it
Previously clear_cache mount option would simply disable free-space-tree feature temporarily then re-enable it to rebuild the whole free space tree. But this is problematic for block-group-tree feature, as we have an artificial dependency on free-space-tree feature. If we go the existing method, after clearing the free-space-tree feature, we would flip the filesystem to read-only mode, as we detect a super block write with block-group-tree but no free-space-tree feature. This patch would change the behavior by properly rebuilding the free space tree without disabling this feature, thus allowing clear_cache mount option to work with block group tree. Now we can mount a filesystem with block-group-tree feature and clear_mount option: $ mkfs.btrfs -O block-group-tree /dev/test/scratch1 -f $ sudo mount /dev/test/scratch1 /mnt/btrfs -o clear_cache $ sudo dmesg -t | head -n 5 BTRFS info (device dm-1): force clearing of disk cache BTRFS info (device dm-1): using free space tree BTRFS info (device dm-1): auto enabling async discard BTRFS info (device dm-1): rebuilding free space tree BTRFS info (device dm-1): checking UUID tree CC: stable@vger.kernel.org # 6.1+ Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent c83b56d commit 1d6a4fc

File tree

4 files changed

+70
-11
lines changed

4 files changed

+70
-11
lines changed

fs/btrfs/disk-io.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3121,23 +3121,34 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
31213121
{
31223122
int ret;
31233123
const bool cache_opt = btrfs_test_opt(fs_info, SPACE_CACHE);
3124-
bool clear_free_space_tree = false;
3124+
bool rebuild_free_space_tree = false;
31253125

31263126
if (btrfs_test_opt(fs_info, CLEAR_CACHE) &&
31273127
btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
3128-
clear_free_space_tree = true;
3128+
rebuild_free_space_tree = true;
31293129
} else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
31303130
!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
31313131
btrfs_warn(fs_info, "free space tree is invalid");
3132-
clear_free_space_tree = true;
3132+
rebuild_free_space_tree = true;
31333133
}
31343134

3135-
if (clear_free_space_tree) {
3136-
btrfs_info(fs_info, "clearing free space tree");
3137-
ret = btrfs_clear_free_space_tree(fs_info);
3135+
if (rebuild_free_space_tree) {
3136+
btrfs_info(fs_info, "rebuilding free space tree");
3137+
ret = btrfs_rebuild_free_space_tree(fs_info);
31383138
if (ret) {
31393139
btrfs_warn(fs_info,
3140-
"failed to clear free space tree: %d", ret);
3140+
"failed to rebuild free space tree: %d", ret);
3141+
goto out;
3142+
}
3143+
}
3144+
3145+
if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
3146+
!btrfs_test_opt(fs_info, FREE_SPACE_TREE)) {
3147+
btrfs_info(fs_info, "disabling free space tree");
3148+
ret = btrfs_delete_free_space_tree(fs_info);
3149+
if (ret) {
3150+
btrfs_warn(fs_info,
3151+
"failed to disable free space tree: %d", ret);
31413152
goto out;
31423153
}
31433154
}

fs/btrfs/free-space-tree.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,7 @@ static int clear_free_space_tree(struct btrfs_trans_handle *trans,
12521252
return ret;
12531253
}
12541254

1255-
int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
1255+
int btrfs_delete_free_space_tree(struct btrfs_fs_info *fs_info)
12561256
{
12571257
struct btrfs_trans_handle *trans;
12581258
struct btrfs_root *tree_root = fs_info->tree_root;
@@ -1298,6 +1298,54 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
12981298
return ret;
12991299
}
13001300

1301+
int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
1302+
{
1303+
struct btrfs_trans_handle *trans;
1304+
struct btrfs_key key = {
1305+
.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID,
1306+
.type = BTRFS_ROOT_ITEM_KEY,
1307+
.offset = 0,
1308+
};
1309+
struct btrfs_root *free_space_root = btrfs_global_root(fs_info, &key);
1310+
struct rb_node *node;
1311+
int ret;
1312+
1313+
trans = btrfs_start_transaction(free_space_root, 1);
1314+
if (IS_ERR(trans))
1315+
return PTR_ERR(trans);
1316+
1317+
set_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
1318+
set_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
1319+
1320+
ret = clear_free_space_tree(trans, free_space_root);
1321+
if (ret)
1322+
goto abort;
1323+
1324+
node = rb_first_cached(&fs_info->block_group_cache_tree);
1325+
while (node) {
1326+
struct btrfs_block_group *block_group;
1327+
1328+
block_group = rb_entry(node, struct btrfs_block_group,
1329+
cache_node);
1330+
ret = populate_free_space_tree(trans, block_group);
1331+
if (ret)
1332+
goto abort;
1333+
node = rb_next(node);
1334+
}
1335+
1336+
btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE);
1337+
btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
1338+
clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
1339+
1340+
ret = btrfs_commit_transaction(trans);
1341+
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
1342+
return ret;
1343+
abort:
1344+
btrfs_abort_transaction(trans, ret);
1345+
btrfs_end_transaction(trans);
1346+
return ret;
1347+
}
1348+
13011349
static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
13021350
struct btrfs_block_group *block_group,
13031351
struct btrfs_path *path)

fs/btrfs/free-space-tree.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ struct btrfs_caching_control;
1818

1919
void set_free_space_tree_thresholds(struct btrfs_block_group *block_group);
2020
int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info);
21-
int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info);
21+
int btrfs_delete_free_space_tree(struct btrfs_fs_info *fs_info);
22+
int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info);
2223
int load_free_space_tree(struct btrfs_caching_control *caching_ctl);
2324
int add_block_group_free_space(struct btrfs_trans_handle *trans,
2425
struct btrfs_block_group *block_group);

fs/btrfs/super.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -828,8 +828,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
828828
ret = -EINVAL;
829829
}
830830
if (btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE) &&
831-
(btrfs_test_opt(info, CLEAR_CACHE) ||
832-
!btrfs_test_opt(info, FREE_SPACE_TREE))) {
831+
!btrfs_test_opt(info, FREE_SPACE_TREE)) {
833832
btrfs_err(info, "cannot disable free space tree with block-group-tree feature");
834833
ret = -EINVAL;
835834
}

0 commit comments

Comments
 (0)