Btrfs: Replace the big fs_mutex with a collection of other locks
Extent alloctions are still protected by a large alloc_mutex.
Objectid allocations are covered by a objectid mutex
Other btree operations are protected by a lock on individual btree nodes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 61bd895..b2251e2 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -79,12 +79,15 @@
int btrfs_check_free_space(struct btrfs_root *root, u64 num_required,
int for_del)
{
- u64 total = btrfs_super_total_bytes(&root->fs_info->super_copy);
- u64 used = btrfs_super_bytes_used(&root->fs_info->super_copy);
+ u64 total;
+ u64 used;
u64 thresh;
unsigned long flags;
int ret = 0;
+ spin_lock_irqsave(&root->fs_info->delalloc_lock, flags);
+ total = btrfs_super_total_bytes(&root->fs_info->super_copy);
+ used = btrfs_super_bytes_used(&root->fs_info->super_copy);
if (for_del)
thresh = total * 90;
else
@@ -92,7 +95,6 @@
do_div(thresh, 100);
- spin_lock_irqsave(&root->fs_info->delalloc_lock, flags);
if (used + root->fs_info->delalloc_bytes + num_required > thresh)
ret = -ENOSPC;
spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags);
@@ -115,7 +117,6 @@
trans = btrfs_start_transaction(root, 1);
BUG_ON(!trans);
btrfs_set_trans_block_group(trans, inode);
- mutex_unlock(&root->fs_info->fs_mutex);
num_bytes = (end - start + blocksize) & ~(blocksize - 1);
num_bytes = max(blocksize, num_bytes);
@@ -160,7 +161,6 @@
btrfs_add_ordered_inode(inode);
btrfs_update_inode(trans, root, inode);
out:
- mutex_lock(&root->fs_info->fs_mutex);
btrfs_end_transaction(trans, root);
return ret;
}
@@ -269,14 +269,13 @@
{
struct btrfs_root *root = BTRFS_I(inode)->root;
int ret;
- mutex_lock(&root->fs_info->fs_mutex);
+
if (btrfs_test_opt(root, NODATACOW) ||
btrfs_test_flag(inode, NODATACOW))
ret = run_delalloc_nocow(inode, start, end);
else
ret = cow_file_range(inode, start, end);
- mutex_unlock(&root->fs_info->fs_mutex);
return ret;
}
@@ -349,17 +348,13 @@
ret = btrfs_csum_one_bio(root, bio, &sums);
BUG_ON(ret);
- mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
- mutex_unlock(&root->fs_info->fs_mutex);
btrfs_set_trans_block_group(trans, inode);
btrfs_csum_file_blocks(trans, root, inode, bio, sums);
- mutex_lock(&root->fs_info->fs_mutex);
ret = btrfs_end_transaction(trans, root);
BUG_ON(ret);
- mutex_unlock(&root->fs_info->fs_mutex);
kfree(sums);
@@ -404,7 +399,6 @@
btrfs_test_flag(inode, NODATASUM))
return 0;
- mutex_lock(&root->fs_info->fs_mutex);
path = btrfs_alloc_path();
item = btrfs_lookup_csum(NULL, root, path, inode->i_ino, start, 0);
if (IS_ERR(item)) {
@@ -422,7 +416,6 @@
out:
if (path)
btrfs_free_path(path);
- mutex_unlock(&root->fs_info->fs_mutex);
return ret;
}
@@ -616,7 +609,6 @@
path = btrfs_alloc_path();
BUG_ON(!path);
- mutex_lock(&root->fs_info->fs_mutex);
memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
@@ -662,8 +654,6 @@
btrfs_free_path(path);
inode_item = NULL;
- mutex_unlock(&root->fs_info->fs_mutex);
-
switch (inode->i_mode & S_IFMT) {
case S_IFREG:
inode->i_mapping->a_ops = &btrfs_aops;
@@ -691,9 +681,7 @@
return;
make_bad:
- btrfs_release_path(root, path);
btrfs_free_path(path);
- mutex_unlock(&root->fs_info->fs_mutex);
make_bad_inode(inode);
}
@@ -758,7 +746,6 @@
btrfs_set_inode_last_trans(trans, inode);
ret = 0;
failed:
- btrfs_release_path(root, path);
btrfs_free_path(path);
return ret;
}
@@ -849,7 +836,6 @@
unsigned long nr = 0;
root = BTRFS_I(dir)->root;
- mutex_lock(&root->fs_info->fs_mutex);
ret = btrfs_check_free_space(root, 1, 1);
if (ret)
@@ -871,7 +857,6 @@
btrfs_end_transaction(trans, root);
fail:
- mutex_unlock(&root->fs_info->fs_mutex);
btrfs_btree_balance_dirty(root, nr);
btrfs_throttle(root);
return ret;
@@ -890,7 +875,6 @@
return -ENOTEMPTY;
}
- mutex_lock(&root->fs_info->fs_mutex);
ret = btrfs_check_free_space(root, 1, 1);
if (ret)
goto fail;
@@ -907,7 +891,6 @@
nr = trans->blocks_used;
ret = btrfs_end_transaction(trans, root);
fail:
- mutex_unlock(&root->fs_info->fs_mutex);
btrfs_btree_balance_dirty(root, nr);
btrfs_throttle(root);
@@ -1129,7 +1112,6 @@
ret = btrfs_del_items(trans, root, path, pending_del_slot,
pending_del_nr);
}
- btrfs_release_path(root, path);
btrfs_free_path(path);
inode->i_sb->s_dirt = 1;
return ret;
@@ -1234,9 +1216,7 @@
if (attr->ia_size <= hole_start)
goto out;
- mutex_lock(&root->fs_info->fs_mutex);
err = btrfs_check_free_space(root, 1, 0);
- mutex_unlock(&root->fs_info->fs_mutex);
if (err)
goto fail;
@@ -1245,7 +1225,6 @@
lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
hole_size = block_end - hole_start;
- mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode);
err = btrfs_drop_extents(trans, root, inode,
@@ -1262,7 +1241,6 @@
btrfs_check_file(root, inode);
}
btrfs_end_transaction(trans, root);
- mutex_unlock(&root->fs_info->fs_mutex);
unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
if (err)
return err;
@@ -1286,7 +1264,6 @@
}
inode->i_size = 0;
- mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode);
@@ -1298,7 +1275,6 @@
clear_inode(inode);
btrfs_end_transaction(trans, root);
- mutex_unlock(&root->fs_info->fs_mutex);
btrfs_btree_balance_dirty(root, nr);
btrfs_throttle(root);
return;
@@ -1306,7 +1282,6 @@
no_delete_lock:
nr = trans->blocks_used;
btrfs_end_transaction(trans, root);
- mutex_unlock(&root->fs_info->fs_mutex);
btrfs_btree_balance_dirty(root, nr);
btrfs_throttle(root);
no_delete:
@@ -1402,7 +1377,6 @@
path = btrfs_alloc_path();
BUG_ON(!path);
- mutex_lock(&root->fs_info->fs_mutex);
*sub_root = btrfs_read_fs_root(root->fs_info, location,
dentry->d_name.name,
@@ -1416,7 +1390,6 @@
location->offset = 0;
btrfs_free_path(path);
- mutex_unlock(&root->fs_info->fs_mutex);
return 0;
}
@@ -1482,9 +1455,7 @@
if (dentry->d_name.len > BTRFS_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
- mutex_lock(&root->fs_info->fs_mutex);
ret = btrfs_inode_by_name(dir, dentry, &location);
- mutex_unlock(&root->fs_info->fs_mutex);
if (ret < 0)
return ERR_PTR(ret);
@@ -1559,7 +1530,6 @@
filp->f_pos = 1;
}
- mutex_lock(&root->fs_info->fs_mutex);
key.objectid = inode->i_ino;
path = btrfs_alloc_path();
path->reada = 2;
@@ -1668,9 +1638,7 @@
nopos:
ret = 0;
err:
- btrfs_release_path(root, path);
btrfs_free_path(path);
- mutex_unlock(&root->fs_info->fs_mutex);
return ret;
}
@@ -1681,11 +1649,9 @@
int ret = 0;
if (wait) {
- mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode);
ret = btrfs_commit_transaction(trans, root);
- mutex_unlock(&root->fs_info->fs_mutex);
}
return ret;
}
@@ -1701,12 +1667,10 @@
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans;
- mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode);
btrfs_update_inode(trans, root, inode);
btrfs_end_transaction(trans, root);
- mutex_unlock(&root->fs_info->fs_mutex);
}
static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
@@ -1874,7 +1838,6 @@
if (!new_valid_dev(rdev))
return -EINVAL;
- mutex_lock(&root->fs_info->fs_mutex);
err = btrfs_check_free_space(root, 1, 0);
if (err)
goto fail;
@@ -1912,8 +1875,6 @@
nr = trans->blocks_used;
btrfs_end_transaction(trans, root);
fail:
- mutex_unlock(&root->fs_info->fs_mutex);
-
if (drop_inode) {
inode_dec_link_count(inode);
iput(inode);
@@ -1934,7 +1895,6 @@
unsigned long nr = 0;
u64 objectid;
- mutex_lock(&root->fs_info->fs_mutex);
err = btrfs_check_free_space(root, 1, 0);
if (err)
goto fail;
@@ -1980,8 +1940,6 @@
nr = trans->blocks_used;
btrfs_end_transaction(trans, root);
fail:
- mutex_unlock(&root->fs_info->fs_mutex);
-
if (drop_inode) {
inode_dec_link_count(inode);
iput(inode);
@@ -2009,7 +1967,6 @@
#else
inc_nlink(inode);
#endif
- mutex_lock(&root->fs_info->fs_mutex);
err = btrfs_check_free_space(root, 1, 0);
if (err)
goto fail;
@@ -2032,8 +1989,6 @@
nr = trans->blocks_used;
btrfs_end_transaction(trans, root);
fail:
- mutex_unlock(&root->fs_info->fs_mutex);
-
if (drop_inode) {
inode_dec_link_count(inode);
iput(inode);
@@ -2053,7 +2008,6 @@
u64 objectid = 0;
unsigned long nr = 1;
- mutex_lock(&root->fs_info->fs_mutex);
err = btrfs_check_free_space(root, 1, 0);
if (err)
goto out_unlock;
@@ -2106,7 +2060,6 @@
btrfs_end_transaction(trans, root);
out_unlock:
- mutex_unlock(&root->fs_info->fs_mutex);
if (drop_on_err)
iput(inode);
btrfs_btree_balance_dirty(root, nr);
@@ -2199,7 +2152,6 @@
path = btrfs_alloc_path();
BUG_ON(!path);
- mutex_lock(&root->fs_info->fs_mutex);
again:
spin_lock(&em_tree->lock);
@@ -2402,7 +2354,6 @@
if (!err)
err = ret;
}
- mutex_unlock(&root->fs_info->fs_mutex);
if (err) {
free_extent_map(em);
WARN_ON(1);
@@ -2584,9 +2535,7 @@
int ret;
u64 page_start;
- mutex_lock(&root->fs_info->fs_mutex);
ret = btrfs_check_free_space(root, PAGE_CACHE_SIZE, 0);
- mutex_unlock(&root->fs_info->fs_mutex);
if (ret)
goto out;
@@ -2631,7 +2580,6 @@
btrfs_truncate_page(inode->i_mapping, inode->i_size);
- mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, inode);
@@ -2643,7 +2591,6 @@
ret = btrfs_end_transaction(trans, root);
BUG_ON(ret);
- mutex_unlock(&root->fs_info->fs_mutex);
btrfs_btree_balance_dirty(root, nr);
btrfs_throttle(root);
}
@@ -2827,7 +2774,6 @@
struct inode *new_inode = new_dentry->d_inode;
struct inode *old_inode = old_dentry->d_inode;
struct timespec ctime = CURRENT_TIME;
- struct btrfs_path *path;
int ret;
if (S_ISDIR(old_inode->i_mode) && new_inode &&
@@ -2835,7 +2781,6 @@
return -ENOTEMPTY;
}
- mutex_lock(&root->fs_info->fs_mutex);
ret = btrfs_check_free_space(root, 1, 0);
if (ret)
goto out_unlock;
@@ -2843,11 +2788,6 @@
trans = btrfs_start_transaction(root, 1);
btrfs_set_trans_block_group(trans, new_dir);
- path = btrfs_alloc_path();
- if (!path) {
- ret = -ENOMEM;
- goto out_fail;
- }
old_dentry->d_inode->i_nlink++;
old_dir->i_ctime = old_dir->i_mtime = ctime;
@@ -2869,10 +2809,8 @@
goto out_fail;
out_fail:
- btrfs_free_path(path);
btrfs_end_transaction(trans, root);
out_unlock:
- mutex_unlock(&root->fs_info->fs_mutex);
return ret;
}
@@ -2898,7 +2836,6 @@
if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
return -ENAMETOOLONG;
- mutex_lock(&root->fs_info->fs_mutex);
err = btrfs_check_free_space(root, 1, 0);
if (err)
goto out_fail;
@@ -2979,7 +2916,6 @@
nr = trans->blocks_used;
btrfs_end_transaction(trans, root);
out_fail:
- mutex_unlock(&root->fs_info->fs_mutex);
if (drop_inode) {
inode_dec_link_count(inode);
iput(inode);