btrfs: clear free space tree on ro->rw remount
authorBoris Burkov <boris@bur.io>
Wed, 18 Nov 2020 23:06:21 +0000 (15:06 -0800)
committerDavid Sterba <dsterba@suse.com>
Wed, 9 Dec 2020 18:16:08 +0000 (19:16 +0100)
A user might want to revert to v1 or nospace_cache on a root filesystem,
and much like turning on the free space tree, that can only be done
remounting from ro->rw. Support clearing the free space tree on such
mounts by moving it into the shared remount logic.

Since the CLEAR_CACHE option sticks around across remounts, this change
would result in clearing the tree for ever on every remount, which is
not desirable. To fix that, add CLEAR_CACHE to the oneshot options we
clear at mount end, which has the other bonus of not cluttering the
/proc/mounts output with clear_cache.

Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Boris Burkov <boris@bur.io>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/disk-io.c

index 292ea49..77c7013 100644 (file)
@@ -2878,6 +2878,7 @@ static int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info)
 void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info)
 {
        btrfs_clear_opt(fs_info->mount_opt, USEBACKUPROOT);
+       btrfs_clear_opt(fs_info->mount_opt, CLEAR_CACHE);
 }
 
 /*
@@ -2887,6 +2888,26 @@ void btrfs_clear_oneshot_options(struct btrfs_fs_info *fs_info)
 int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
 {
        int ret;
+       bool clear_free_space_tree = false;
+
+       if (btrfs_test_opt(fs_info, CLEAR_CACHE) &&
+           btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
+               clear_free_space_tree = true;
+       } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
+                  !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
+               btrfs_warn(fs_info, "free space tree is invalid");
+               clear_free_space_tree = true;
+       }
+
+       if (clear_free_space_tree) {
+               btrfs_info(fs_info, "clearing free space tree");
+               ret = btrfs_clear_free_space_tree(fs_info);
+               if (ret) {
+                       btrfs_warn(fs_info,
+                                  "failed to clear free space tree: %d", ret);
+                       goto out;
+               }
+       }
 
        ret = btrfs_cleanup_fs_roots(fs_info);
        if (ret)
@@ -2960,7 +2981,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
        struct btrfs_root *chunk_root;
        int ret;
        int err = -EINVAL;
-       int clear_free_space_tree = 0;
        int level;
 
        ret = init_mount_fs_info(fs_info, sb);
@@ -3371,26 +3391,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
        if (sb_rdonly(sb))
                goto clear_oneshot;
 
-       if (btrfs_test_opt(fs_info, CLEAR_CACHE) &&
-           btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
-               clear_free_space_tree = 1;
-       } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) &&
-                  !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) {
-               btrfs_warn(fs_info, "free space tree is invalid");
-               clear_free_space_tree = 1;
-       }
-
-       if (clear_free_space_tree) {
-               btrfs_info(fs_info, "clearing free space tree");
-               ret = btrfs_clear_free_space_tree(fs_info);
-               if (ret) {
-                       btrfs_warn(fs_info,
-                                  "failed to clear free space tree: %d", ret);
-                       close_ctree(fs_info);
-                       return ret;
-               }
-       }
-
        ret = btrfs_start_pre_rw_mount(fs_info);
        if (ret) {
                close_ctree(fs_info);