btrfs: don't run delayed references while we are creating the free space tree
authorChris Mason <clm@fb.com>
Wed, 30 Dec 2015 15:52:35 +0000 (07:52 -0800)
committerChris Mason <clm@fb.com>
Wed, 30 Dec 2015 15:52:35 +0000 (07:52 -0800)
This is a short term solution to make sure btrfs_run_delayed_refs()
doesn't change the extent tree while we are scanning it to create the
free space tree.

Longer term we need to synchronize scanning the block groups one by one,
similar to what happens during a balance.

Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/free-space-tree.c

index d79ba0570c55dfed0f6307f17b7843f0650b096c..9a88d0c69be4c0106912f2645e2dce7267e9c145 100644 (file)
@@ -1856,6 +1856,8 @@ struct btrfs_fs_info {
         * and will be latter freed. Protected by fs_info->chunk_mutex.
         */
        struct list_head pinned_chunks;
+
+       int creating_free_space_tree;
 };
 
 struct btrfs_subvolume_writers {
index 823c1ce87e2eb4443f63756fa6aff32582b299ea..dc6b73a953426285365c8a32ea1a98eed2bc803f 100644 (file)
@@ -3065,6 +3065,18 @@ retry_root_backup:
        if (sb->s_flags & MS_RDONLY)
                return 0;
 
+       if (btrfs_test_opt(tree_root, FREE_SPACE_TREE) &&
+           !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
+               pr_info("BTRFS: creating free space tree\n");
+               ret = btrfs_create_free_space_tree(fs_info);
+               if (ret) {
+                       pr_warn("BTRFS: failed to create free space tree %d\n",
+                               ret);
+                       close_ctree(tree_root);
+                       return ret;
+               }
+       }
+
        down_read(&fs_info->cleanup_work_sem);
        if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) ||
            (ret = btrfs_orphan_cleanup(fs_info->tree_root))) {
@@ -3102,18 +3114,6 @@ retry_root_backup:
                }
        }
 
-       if (btrfs_test_opt(tree_root, FREE_SPACE_TREE) &&
-           !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
-               pr_info("BTRFS: creating free space tree\n");
-               ret = btrfs_create_free_space_tree(fs_info);
-               if (ret) {
-                       pr_warn("BTRFS: failed to create free space tree %d\n",
-                               ret);
-                       close_ctree(tree_root);
-                       return ret;
-               }
-       }
-
        if (!fs_info->uuid_root) {
                pr_info("BTRFS: creating UUID tree\n");
                ret = btrfs_create_uuid_tree(fs_info);
index 83fc61db0e4522b2453791e689d30a85e1ea33b5..add4af641cfa1d56201b1322d4f6871777135ed0 100644 (file)
@@ -2926,6 +2926,9 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
        if (trans->aborted)
                return 0;
 
+       if (root->fs_info->creating_free_space_tree)
+               return 0;
+
        if (root == root->fs_info->extent_root)
                root = root->fs_info->tree_root;
 
index cbe36dd0d97b84eaf071faa9a5d632a7fd5e8dac..393e36bd5845d996d216e14ef2c6ac6866fce746 100644 (file)
@@ -1067,6 +1067,8 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
        if (ret)
                goto out;
 
+       mutex_lock(&block_group->free_space_lock);
+
        /*
         * Iterate through all of the extent and metadata items in this block
         * group, adding the free space between them and the free space at the
@@ -1080,7 +1082,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
 
        ret = btrfs_search_slot_for_read(extent_root, &key, path, 1, 0);
        if (ret < 0)
-               goto out;
+               goto out_locked;
        ASSERT(ret == 0);
 
        start = block_group->key.objectid;
@@ -1100,7 +1102,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
                                                               key.objectid -
                                                               start);
                                if (ret)
-                                       goto out;
+                                       goto out_locked;
                        }
                        start = key.objectid;
                        if (key.type == BTRFS_METADATA_ITEM_KEY)
@@ -1114,7 +1116,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
 
                ret = btrfs_next_item(extent_root, path);
                if (ret < 0)
-                       goto out;
+                       goto out_locked;
                if (ret)
                        break;
        }
@@ -1122,10 +1124,12 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
                ret = __add_to_free_space_tree(trans, fs_info, block_group,
                                               path2, start, end - start);
                if (ret)
-                       goto out;
+                       goto out_locked;
        }
 
        ret = 0;
+out_locked:
+       mutex_unlock(&block_group->free_space_lock);
 out:
        btrfs_free_path(path2);
        btrfs_free_path(path);
@@ -1145,6 +1149,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
        if (IS_ERR(trans))
                return PTR_ERR(trans);
 
+       fs_info->creating_free_space_tree = 1;
        free_space_root = btrfs_create_tree(trans, fs_info,
                                            BTRFS_FREE_SPACE_TREE_OBJECTID);
        if (IS_ERR(free_space_root)) {
@@ -1164,6 +1169,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
        }
 
        btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE);
+       fs_info->creating_free_space_tree = 0;
 
        ret = btrfs_commit_transaction(trans, tree_root);
        if (ret)
@@ -1172,6 +1178,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
        return 0;
 
 abort:
+       fs_info->creating_free_space_tree = 0;
        btrfs_abort_transaction(trans, tree_root, ret);
        btrfs_end_transaction(trans, tree_root);
        return ret;