Commit 511711af authored by Chris Mason's avatar Chris Mason

btrfs: don't run delayed references while we are creating the free space tree

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: default avatarChris Mason <clm@fb.com>
parent b4570aa9
...@@ -1856,6 +1856,8 @@ struct btrfs_fs_info { ...@@ -1856,6 +1856,8 @@ struct btrfs_fs_info {
* and will be latter freed. Protected by fs_info->chunk_mutex. * and will be latter freed. Protected by fs_info->chunk_mutex.
*/ */
struct list_head pinned_chunks; struct list_head pinned_chunks;
int creating_free_space_tree;
}; };
struct btrfs_subvolume_writers { struct btrfs_subvolume_writers {
......
...@@ -3065,6 +3065,18 @@ int open_ctree(struct super_block *sb, ...@@ -3065,6 +3065,18 @@ int open_ctree(struct super_block *sb,
if (sb->s_flags & MS_RDONLY) if (sb->s_flags & MS_RDONLY)
return 0; 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); down_read(&fs_info->cleanup_work_sem);
if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) || if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) ||
(ret = btrfs_orphan_cleanup(fs_info->tree_root))) { (ret = btrfs_orphan_cleanup(fs_info->tree_root))) {
...@@ -3102,18 +3114,6 @@ int open_ctree(struct super_block *sb, ...@@ -3102,18 +3114,6 @@ int open_ctree(struct super_block *sb,
} }
} }
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) { if (!fs_info->uuid_root) {
pr_info("BTRFS: creating UUID tree\n"); pr_info("BTRFS: creating UUID tree\n");
ret = btrfs_create_uuid_tree(fs_info); ret = btrfs_create_uuid_tree(fs_info);
......
...@@ -2926,6 +2926,9 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, ...@@ -2926,6 +2926,9 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
if (trans->aborted) if (trans->aborted)
return 0; return 0;
if (root->fs_info->creating_free_space_tree)
return 0;
if (root == root->fs_info->extent_root) if (root == root->fs_info->extent_root)
root = root->fs_info->tree_root; root = root->fs_info->tree_root;
......
...@@ -1067,6 +1067,8 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans, ...@@ -1067,6 +1067,8 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
if (ret) if (ret)
goto out; goto out;
mutex_lock(&block_group->free_space_lock);
/* /*
* Iterate through all of the extent and metadata items in this block * 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 * 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, ...@@ -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); ret = btrfs_search_slot_for_read(extent_root, &key, path, 1, 0);
if (ret < 0) if (ret < 0)
goto out; goto out_locked;
ASSERT(ret == 0); ASSERT(ret == 0);
start = block_group->key.objectid; start = block_group->key.objectid;
...@@ -1100,7 +1102,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans, ...@@ -1100,7 +1102,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
key.objectid - key.objectid -
start); start);
if (ret) if (ret)
goto out; goto out_locked;
} }
start = key.objectid; start = key.objectid;
if (key.type == BTRFS_METADATA_ITEM_KEY) if (key.type == BTRFS_METADATA_ITEM_KEY)
...@@ -1114,7 +1116,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans, ...@@ -1114,7 +1116,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
ret = btrfs_next_item(extent_root, path); ret = btrfs_next_item(extent_root, path);
if (ret < 0) if (ret < 0)
goto out; goto out_locked;
if (ret) if (ret)
break; break;
} }
...@@ -1122,10 +1124,12 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans, ...@@ -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, ret = __add_to_free_space_tree(trans, fs_info, block_group,
path2, start, end - start); path2, start, end - start);
if (ret) if (ret)
goto out; goto out_locked;
} }
ret = 0; ret = 0;
out_locked:
mutex_unlock(&block_group->free_space_lock);
out: out:
btrfs_free_path(path2); btrfs_free_path(path2);
btrfs_free_path(path); btrfs_free_path(path);
...@@ -1145,6 +1149,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) ...@@ -1145,6 +1149,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
if (IS_ERR(trans)) if (IS_ERR(trans))
return PTR_ERR(trans); return PTR_ERR(trans);
fs_info->creating_free_space_tree = 1;
free_space_root = btrfs_create_tree(trans, fs_info, free_space_root = btrfs_create_tree(trans, fs_info,
BTRFS_FREE_SPACE_TREE_OBJECTID); BTRFS_FREE_SPACE_TREE_OBJECTID);
if (IS_ERR(free_space_root)) { if (IS_ERR(free_space_root)) {
...@@ -1164,6 +1169,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) ...@@ -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); btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE);
fs_info->creating_free_space_tree = 0;
ret = btrfs_commit_transaction(trans, tree_root); ret = btrfs_commit_transaction(trans, tree_root);
if (ret) if (ret)
...@@ -1172,6 +1178,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) ...@@ -1172,6 +1178,7 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
return 0; return 0;
abort: abort:
fs_info->creating_free_space_tree = 0;
btrfs_abort_transaction(trans, tree_root, ret); btrfs_abort_transaction(trans, tree_root, ret);
btrfs_end_transaction(trans, tree_root); btrfs_end_transaction(trans, tree_root);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment