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/ctree.c b/fs/btrfs/ctree.c
index 75625c6..dff4da0 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -63,6 +63,9 @@
 void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
 {
 	int i;
+	int skip = p->skip_locking;
+	int keep = p->keep_locks;
+
 	for (i = 0; i < BTRFS_MAX_LEVEL; i++) {
 		if (!p->nodes[i])
 			continue;
@@ -73,6 +76,8 @@
 		free_extent_buffer(p->nodes[i]);
 	}
 	memset(p, 0, sizeof(*p));
+	p->skip_locking = skip;
+	p->keep_locks = keep;
 }
 
 struct extent_buffer *btrfs_root_node(struct btrfs_root *root)
@@ -1202,13 +1207,19 @@
 			u32 nritems;
 			t = path->nodes[i];
 			nritems = btrfs_header_nritems(t);
-			if (path->slots[i] >= nritems - 1) {
+			if (nritems < 2 || path->slots[i] >= nritems - 2) {
+if (path->keep_locks) {
+//printk("path %p skip level now %d\n", path, skip_level);
+}
 				skip_level = i + 1;
 				continue;
 			}
 		}
 		t = path->nodes[i];
 		if (i >= lowest_unlock && i > skip_level && path->locks[i]) {
+if (path->keep_locks) {
+//printk("path %p unlocking level %d slot %d nritems %d skip_level %d\n", path, i, path->slots[i], btrfs_header_nritems(t), skip_level);
+}
 			btrfs_tree_unlock(t);
 			path->locks[i] = 0;
 		}
@@ -1243,7 +1254,6 @@
 	lowest_level = p->lowest_level;
 	WARN_ON(lowest_level && ins_len);
 	WARN_ON(p->nodes[0] != NULL);
-	// WARN_ON(!mutex_is_locked(&root->fs_info->fs_mutex));
 	WARN_ON(root == root->fs_info->extent_root &&
 		!mutex_is_locked(&root->fs_info->alloc_mutex));
 	WARN_ON(root == root->fs_info->chunk_root &&
@@ -1321,7 +1331,7 @@
 			b = read_node_slot(root, b, slot);
 			if (!p->skip_locking)
 				btrfs_tree_lock(b);
-			unlock_up(p, level, lowest_unlock);
+			unlock_up(p, level + 1, lowest_unlock);
 		} else {
 			p->slots[level] = slot;
 			if (ins_len > 0 && btrfs_leaf_free_space(root, b) <
@@ -1804,6 +1814,8 @@
 	if (slot >= btrfs_header_nritems(upper) - 1)
 		return 1;
 
+	WARN_ON(!btrfs_tree_locked(path->nodes[1]));
+
 	right = read_node_slot(root, upper, slot + 1);
 	btrfs_tree_lock(right);
 	free_space = btrfs_leaf_free_space(root, right);
@@ -1981,6 +1993,8 @@
 		return 1;
 	}
 
+	WARN_ON(!btrfs_tree_locked(path->nodes[1]));
+
 	left = read_node_slot(root, path->nodes[1], slot - 1);
 	btrfs_tree_lock(left);
 	free_space = btrfs_leaf_free_space(root, left);
@@ -2957,15 +2971,16 @@
 
 	btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
 
-	path->keep_locks = 1;
 	btrfs_release_path(root, path);
+	path->keep_locks = 1;
 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 	path->keep_locks = 0;
 
 	if (ret < 0)
 		return ret;
 
-	if (path->slots[0] < nritems - 1) {
+	nritems = btrfs_header_nritems(path->nodes[0]);
+	if (nritems > 0 && path->slots[0] < nritems - 1) {
 		goto done;
 	}
 
@@ -2992,8 +3007,17 @@
 			reada_for_search(root, path, level, slot, 0);
 
 		next = read_node_slot(root, c, slot);
-		if (!path->skip_locking)
+		if (!path->skip_locking) {
+			if (!btrfs_tree_locked(c)) {
+				int i;
+				WARN_ON(1);
+printk("path %p no lock on level %d\n", path, level);
+for (i = 0; i < BTRFS_MAX_LEVEL; i++) {
+printk("path %p level %d slot %d nritems %d\n", path, i, path->slots[i], btrfs_header_nritems(path->nodes[i]));
+}
+			}
 			btrfs_tree_lock(next);
+		}
 		break;
 	}
 	path->slots[level] = slot;
@@ -3011,8 +3035,10 @@
 		if (level == 1 && path->locks[1] && path->reada)
 			reada_for_search(root, path, level, slot, 0);
 		next = read_node_slot(root, next, 0);
-		if (!path->skip_locking)
+		if (!path->skip_locking) {
+			WARN_ON(!btrfs_tree_locked(path->nodes[level]));
 			btrfs_tree_lock(next);
+		}
 	}
 done:
 	unlock_up(path, 0, 1);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 50891b3..692b8ea 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -519,9 +519,9 @@
 	struct backing_dev_info bdi;
 	spinlock_t hash_lock;
 	struct mutex trans_mutex;
-	struct mutex fs_mutex;
 	struct mutex alloc_mutex;
 	struct mutex chunk_mutex;
+	struct mutex drop_mutex;
 	struct list_head trans_list;
 	struct list_head hashers;
 	struct list_head dead_roots;
@@ -554,7 +554,7 @@
 	struct completion kobj_unregister;
 	int do_barriers;
 	int closing;
-	unsigned long throttles;
+	atomic_t throttles;
 
 	u64 total_pinned;
 	struct list_head dirty_cowonly_roots;
@@ -594,6 +594,7 @@
 	struct inode *inode;
 	struct kobject root_kobj;
 	struct completion kobj_unregister;
+	struct mutex objectid_mutex;
 	u64 objectid;
 	u64 last_trans;
 
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index fe40bdd..f638803 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -724,6 +724,7 @@
 
 	INIT_LIST_HEAD(&root->dirty_list);
 	spin_lock_init(&root->node_lock);
+	mutex_init(&root->objectid_mutex);
 	memset(&root->root_key, 0, sizeof(root->root_key));
 	memset(&root->root_item, 0, sizeof(root->root_item));
 	memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
@@ -1146,6 +1147,7 @@
 	INIT_LIST_HEAD(&fs_info->space_info);
 	btrfs_mapping_init(&fs_info->mapping_tree);
 	atomic_set(&fs_info->nr_async_submits, 0);
+	atomic_set(&fs_info->throttles, 0);
 	fs_info->sb = sb;
 	fs_info->max_extent = (u64)-1;
 	fs_info->max_inline = 8192 * 1024;
@@ -1199,7 +1201,7 @@
 	mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
 
 	mutex_init(&fs_info->trans_mutex);
-	mutex_init(&fs_info->fs_mutex);
+	mutex_init(&fs_info->drop_mutex);
 	mutex_init(&fs_info->alloc_mutex);
 	mutex_init(&fs_info->chunk_mutex);
 
@@ -1278,8 +1280,6 @@
 		goto fail_sb_buffer;
 	}
 
-	mutex_lock(&fs_info->fs_mutex);
-
 	mutex_lock(&fs_info->chunk_mutex);
 	ret = btrfs_read_sys_array(tree_root);
 	mutex_unlock(&fs_info->chunk_mutex);
@@ -1342,7 +1342,6 @@
 	fs_info->metadata_alloc_profile = (u64)-1;
 	fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
 
-	mutex_unlock(&fs_info->fs_mutex);
 	return tree_root;
 
 fail_extent_root:
@@ -1350,7 +1349,6 @@
 fail_tree_root:
 	free_extent_buffer(tree_root->node);
 fail_sys_array:
-	mutex_unlock(&fs_info->fs_mutex);
 fail_sb_buffer:
 	extent_io_tree_empty_lru(&BTRFS_I(fs_info->btree_inode)->io_tree);
 	btrfs_stop_workers(&fs_info->workers);
@@ -1562,8 +1560,9 @@
 	struct btrfs_fs_info *fs_info = root->fs_info;
 
 	fs_info->closing = 1;
+	smp_mb();
+
 	btrfs_transaction_flush_work(root);
-	mutex_lock(&fs_info->fs_mutex);
 	btrfs_defrag_dirty_roots(root->fs_info);
 	trans = btrfs_start_transaction(root, 1);
 	ret = btrfs_commit_transaction(trans, root);
@@ -1574,7 +1573,6 @@
 	BUG_ON(ret);
 
 	write_ctree_super(NULL, root);
-	mutex_unlock(&fs_info->fs_mutex);
 
 	btrfs_transaction_flush_work(root);
 
@@ -1679,7 +1677,8 @@
 	struct backing_dev_info *bdi;
 
 	bdi = &root->fs_info->bdi;
-	if (root->fs_info->throttles && bdi_write_congested(bdi)) {
+	if (atomic_read(&root->fs_info->throttles) &&
+	    bdi_write_congested(bdi)) {
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
 		congestion_wait(WRITE, HZ/20);
 #else
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 7e40c51..890b9e9 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1577,9 +1577,11 @@
 		}
 
 		/* block accounting for super block */
+		spin_lock_irq(&info->delalloc_lock);
 		super_used = btrfs_super_bytes_used(&info->super_copy);
 		btrfs_set_super_bytes_used(&info->super_copy,
 					   super_used - num_bytes);
+		spin_unlock_irq(&info->delalloc_lock);
 
 		/* block accounting for root item */
 		root_used = btrfs_root_used(&root->root_item);
@@ -1968,8 +1970,10 @@
 	}
 
 	/* block accounting for super block */
+	spin_lock_irq(&info->delalloc_lock);
 	super_used = btrfs_super_bytes_used(&info->super_copy);
 	btrfs_set_super_bytes_used(&info->super_copy, super_used + num_bytes);
+	spin_unlock_irq(&info->delalloc_lock);
 
 	/* block accounting for root item */
 	root_used = btrfs_root_used(&root->root_item);
@@ -2172,12 +2176,12 @@
 				continue;
 			}
 		}
-		mutex_unlock(&root->fs_info->fs_mutex);
+		mutex_unlock(&root->fs_info->alloc_mutex);
 		ret = readahead_tree_block(root, bytenr, blocksize,
 					   btrfs_node_ptr_generation(node, i));
 		last = bytenr + blocksize;
 		cond_resched();
-		mutex_lock(&root->fs_info->fs_mutex);
+		mutex_lock(&root->fs_info->alloc_mutex);
 		if (ret)
 			break;
 	}
@@ -2254,11 +2258,9 @@
 			free_extent_buffer(next);
 			reada_walk_down(root, cur, path->slots[*level]);
 
-			mutex_unlock(&root->fs_info->fs_mutex);
 			mutex_unlock(&root->fs_info->alloc_mutex);
 			next = read_tree_block(root, bytenr, blocksize,
 					       ptr_gen);
-			mutex_lock(&root->fs_info->fs_mutex);
 			mutex_lock(&root->fs_info->alloc_mutex);
 
 			/* we've dropped the lock, double check */
@@ -2381,6 +2383,7 @@
 	int orig_level;
 	struct btrfs_root_item *root_item = &root->root_item;
 
+	WARN_ON(!mutex_is_locked(&root->fs_info->drop_mutex));
 	path = btrfs_alloc_path();
 	BUG_ON(!path);
 
@@ -2710,7 +2713,6 @@
 		    *last_file_root == ref_root)
 			goto out;
 
-		mutex_unlock(&extent_root->fs_info->fs_mutex);
 		inode = btrfs_iget_locked(extent_root->fs_info->sb,
 					  ref_objectid, found_root);
 		if (inode->i_state & I_NEW) {
@@ -2727,7 +2729,6 @@
 		 * the latest version of the tree root
 		 */
 		if (is_bad_inode(inode)) {
-			mutex_lock(&extent_root->fs_info->fs_mutex);
 			goto out;
 		}
 		*last_file_objectid = inode->i_ino;
@@ -2736,7 +2737,6 @@
 
 		relocate_inode_pages(inode, ref_offset, extent_key->offset);
 		iput(inode);
-		mutex_lock(&extent_root->fs_info->fs_mutex);
 	} else {
 		struct btrfs_trans_handle *trans;
 		struct extent_buffer *eb;
@@ -3033,9 +3033,7 @@
 
 		if (progress && need_resched()) {
 			memcpy(&key, &found_key, sizeof(key));
-			mutex_unlock(&root->fs_info->fs_mutex);
 			cond_resched();
-			mutex_lock(&root->fs_info->fs_mutex);
 			btrfs_release_path(root, path);
 			btrfs_search_slot(NULL, root, &key, path, 0, 0);
 			progress = 0;
@@ -3068,9 +3066,7 @@
 		trans = btrfs_start_transaction(tree_root, 1);
 		btrfs_commit_transaction(trans, tree_root);
 
-		mutex_unlock(&root->fs_info->fs_mutex);
 		btrfs_clean_old_snapshots(tree_root);
-		mutex_lock(&root->fs_info->fs_mutex);
 
 		trans = btrfs_start_transaction(tree_root, 1);
 		btrfs_commit_transaction(trans, tree_root);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 73c6d08..18bbe10 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -252,7 +252,6 @@
 	end_of_last_block = start_pos + num_bytes - 1;
 
 	lock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
-	mutex_lock(&root->fs_info->fs_mutex);
 	trans = btrfs_start_transaction(root, 1);
 	if (!trans) {
 		err = -ENOMEM;
@@ -341,7 +340,6 @@
 failed:
 	err = btrfs_end_transaction(trans, root);
 out_unlock:
-	mutex_unlock(&root->fs_info->fs_mutex);
 	unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
 	return err;
 }
@@ -905,9 +903,7 @@
 		WARN_ON(num_pages > nrptrs);
 		memset(pages, 0, sizeof(pages));
 
-		mutex_lock(&root->fs_info->fs_mutex);
 		ret = btrfs_check_free_space(root, write_bytes, 0);
-		mutex_unlock(&root->fs_info->fs_mutex);
 		if (ret)
 			goto out;
 
@@ -998,9 +994,9 @@
 	 * check the transaction that last modified this inode
 	 * and see if its already been committed
 	 */
-	mutex_lock(&root->fs_info->fs_mutex);
 	if (!BTRFS_I(inode)->last_trans)
 		goto out;
+
 	mutex_lock(&root->fs_info->trans_mutex);
 	if (BTRFS_I(inode)->last_trans <=
 	    root->fs_info->last_trans_committed) {
@@ -1023,7 +1019,6 @@
 	}
 	ret = btrfs_commit_transaction(trans, root);
 out:
-	mutex_unlock(&root->fs_info->fs_mutex);
 	return ret > 0 ? EIO : ret;
 }
 
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c
index a0925ea..298346a 100644
--- a/fs/btrfs/inode-map.c
+++ b/fs/btrfs/inode-map.c
@@ -69,6 +69,12 @@
 	struct btrfs_key search_key;
 	u64 search_start = dirid;
 
+	mutex_lock(&root->objectid_mutex);
+	if (root->last_inode_alloc) {
+		*objectid = ++root->last_inode_alloc;
+		mutex_unlock(&root->objectid_mutex);
+		return 0;
+	}
 	path = btrfs_alloc_path();
 	BUG_ON(!path);
 	search_start = root->last_inode_alloc;
@@ -124,9 +130,11 @@
 	btrfs_release_path(root, path);
 	btrfs_free_path(path);
 	BUG_ON(*objectid < search_start);
+	mutex_unlock(&root->objectid_mutex);
 	return 0;
 error:
 	btrfs_release_path(root, path);
 	btrfs_free_path(path);
+	mutex_unlock(&root->objectid_mutex);
 	return ret;
 }
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);
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 3fbf74e..6002eb6 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -63,7 +63,6 @@
 	u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
 	unsigned long nr = 1;
 
-	mutex_lock(&root->fs_info->fs_mutex);
 	ret = btrfs_check_free_space(root, 1, 0);
 	if (ret)
 		goto fail_commit;
@@ -164,7 +163,6 @@
 	if (err && !ret)
 		ret = err;
 fail_commit:
-	mutex_unlock(&root->fs_info->fs_mutex);
 	btrfs_btree_balance_dirty(root, nr);
 	btrfs_throttle(root);
 	return ret;
@@ -181,7 +179,6 @@
 	if (!root->ref_cows)
 		return -EINVAL;
 
-	mutex_lock(&root->fs_info->fs_mutex);
 	ret = btrfs_check_free_space(root, 1, 0);
 	if (ret)
 		goto fail_unlock;
@@ -208,7 +205,6 @@
 	err = btrfs_commit_transaction(trans, root);
 
 fail_unlock:
-	mutex_unlock(&root->fs_info->fs_mutex);
 	btrfs_btree_balance_dirty(root, nr);
 	btrfs_throttle(root);
 	return ret;
@@ -228,9 +224,7 @@
 	unsigned long i;
 	int ret;
 
-	mutex_lock(&root->fs_info->fs_mutex);
 	ret = btrfs_check_free_space(root, inode->i_size, 0);
-	mutex_unlock(&root->fs_info->fs_mutex);
 	if (ret)
 		return -ENOSPC;
 
@@ -315,7 +309,8 @@
 		goto out;
 	}
 
-	mutex_lock(&root->fs_info->fs_mutex);
+	mutex_lock(&root->fs_info->alloc_mutex);
+	mutex_lock(&root->fs_info->chunk_mutex);
 	sizestr = vol_args->name;
 	devstr = strchr(sizestr, ':');
 	if (devstr) {
@@ -385,7 +380,8 @@
 	}
 
 out_unlock:
-	mutex_unlock(&root->fs_info->fs_mutex);
+	mutex_lock(&root->fs_info->alloc_mutex);
+	mutex_lock(&root->fs_info->chunk_mutex);
 out:
 	kfree(vol_args);
 	return ret;
@@ -428,11 +424,9 @@
 	}
 
 	root_dirid = root->fs_info->sb->s_root->d_inode->i_ino,
-	mutex_lock(&root->fs_info->fs_mutex);
 	di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root,
 			    path, root_dirid,
 			    vol_args->name, namelen, 0);
-	mutex_unlock(&root->fs_info->fs_mutex);
 	btrfs_free_path(path);
 
 	if (di && !IS_ERR(di)) {
@@ -445,10 +439,12 @@
 		goto out;
 	}
 
+	mutex_lock(&root->fs_info->drop_mutex);
 	if (root == root->fs_info->tree_root)
 		ret = create_subvol(root, vol_args->name, namelen);
 	else
 		ret = create_snapshot(root, vol_args->name, namelen);
+	mutex_unlock(&root->fs_info->drop_mutex);
 out:
 	kfree(vol_args);
 	return ret;
@@ -461,10 +457,8 @@
 
 	switch (inode->i_mode & S_IFMT) {
 	case S_IFDIR:
-		mutex_lock(&root->fs_info->fs_mutex);
 		btrfs_defrag_root(root, 0);
 		btrfs_defrag_root(root->fs_info->extent_root, 0);
-		mutex_unlock(&root->fs_info->fs_mutex);
 		break;
 	case S_IFREG:
 		btrfs_defrag_file(file);
@@ -588,7 +582,6 @@
 		unlock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS);
 	}
 
-	mutex_lock(&root->fs_info->fs_mutex);
 	trans = btrfs_start_transaction(root, 0);
 	path = btrfs_alloc_path();
 	if (!path) {
@@ -685,7 +678,6 @@
 	unlock_extent(&BTRFS_I(src)->io_tree, 0, (u64)-1, GFP_NOFS);
 
 	btrfs_end_transaction(trans, root);
-	mutex_unlock(&root->fs_info->fs_mutex);
 
 out_unlock:
 	mutex_unlock(&src->i_mutex);
@@ -711,7 +703,6 @@
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
-	mutex_lock(&root->fs_info->fs_mutex);
 	if (file->private_data) {
 		ret = -EINPROGRESS;
 		goto out;
@@ -723,7 +714,6 @@
 		ret = -ENOMEM;
 	/*printk(KERN_INFO "btrfs_ioctl_trans_start on %p\n", file);*/
 out:
-	mutex_unlock(&root->fs_info->fs_mutex);
 	return ret;
 }
 
@@ -740,7 +730,6 @@
 	struct btrfs_trans_handle *trans;
 	int ret = 0;
 
-	mutex_lock(&root->fs_info->fs_mutex);
 	trans = file->private_data;
 	if (!trans) {
 		ret = -EINVAL;
@@ -749,7 +738,6 @@
 	btrfs_end_transaction(trans, root);
 	file->private_data = 0;
 out:
-	mutex_unlock(&root->fs_info->fs_mutex);
 	return ret;
 }
 
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 196d0e2..b61ded7 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -366,12 +366,10 @@
 		return 0;
 	}
 	btrfs_clean_old_snapshots(root);
-	mutex_lock(&root->fs_info->fs_mutex);
 	btrfs_defrag_dirty_roots(root->fs_info);
 	trans = btrfs_start_transaction(root, 1);
 	ret = btrfs_commit_transaction(trans, root);
 	sb->s_dirt = 0;
-	mutex_unlock(&root->fs_info->fs_mutex);
 	return ret;
 }
 
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 1ed433a..5a1ee06 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -370,6 +370,7 @@
 	struct btrfs_trans_handle *trans;
 	unsigned long nr;
 
+	smp_mb();
 	if (root->defrag_running)
 		return 0;
 	trans = btrfs_start_transaction(root, 1);
@@ -378,16 +379,15 @@
 		ret = btrfs_defrag_leaves(trans, root, cacheonly);
 		nr = trans->blocks_used;
 		btrfs_end_transaction(trans, root);
-		mutex_unlock(&info->fs_mutex);
 		btrfs_btree_balance_dirty(info->tree_root, nr);
 		cond_resched();
 
-		mutex_lock(&info->fs_mutex);
 		trans = btrfs_start_transaction(root, 1);
 		if (ret != -EAGAIN)
 			break;
 	}
 	root->defrag_running = 0;
+	smp_mb();
 	radix_tree_tag_clear(&info->fs_roots_radix,
 		     (unsigned long)root->root_key.objectid,
 		     BTRFS_ROOT_DEFRAG_TAG);
@@ -435,14 +435,14 @@
 	while(!list_empty(list)) {
 		struct btrfs_root *root;
 
-		mutex_lock(&tree_root->fs_info->fs_mutex);
 		dirty = list_entry(list->next, struct dirty_root, list);
 		list_del_init(&dirty->list);
 
 		num_bytes = btrfs_root_used(&dirty->root->root_item);
 		root = dirty->latest_root;
-		root->fs_info->throttles++;
+		atomic_inc(&root->fs_info->throttles);
 
+		mutex_lock(&root->fs_info->drop_mutex);
 		while(1) {
 			trans = btrfs_start_transaction(tree_root, 1);
 			ret = btrfs_drop_snapshot(trans, dirty->root);
@@ -459,14 +459,16 @@
 			nr = trans->blocks_used;
 			ret = btrfs_end_transaction(trans, tree_root);
 			BUG_ON(ret);
-			mutex_unlock(&tree_root->fs_info->fs_mutex);
+
+			mutex_unlock(&root->fs_info->drop_mutex);
 			btrfs_btree_balance_dirty(tree_root, nr);
 			cond_resched();
-			mutex_lock(&tree_root->fs_info->fs_mutex);
+			mutex_lock(&root->fs_info->drop_mutex);
 		}
 		BUG_ON(ret);
-		root->fs_info->throttles--;
+		atomic_dec(&root->fs_info->throttles);
 
+		mutex_lock(&root->fs_info->alloc_mutex);
 		num_bytes -= btrfs_root_used(&dirty->root->root_item);
 		bytes_used = btrfs_root_used(&root->root_item);
 		if (num_bytes) {
@@ -474,11 +476,15 @@
 			btrfs_set_root_used(&root->root_item,
 					    bytes_used - num_bytes);
 		}
+		mutex_unlock(&root->fs_info->alloc_mutex);
+
 		ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key);
 		if (ret) {
 			BUG();
 			break;
 		}
+		mutex_unlock(&root->fs_info->drop_mutex);
+
 		nr = trans->blocks_used;
 		ret = btrfs_end_transaction(trans, tree_root);
 		BUG_ON(ret);
@@ -486,7 +492,6 @@
 		free_extent_buffer(dirty->root->node);
 		kfree(dirty->root);
 		kfree(dirty);
-		mutex_unlock(&tree_root->fs_info->fs_mutex);
 
 		btrfs_btree_balance_dirty(tree_root, nr);
 		cond_resched();
@@ -503,7 +508,7 @@
 	u64 objectid = 0;
 	int ret;
 
-	root->fs_info->throttles++;
+	atomic_inc(&root->fs_info->throttles);
 	while(1) {
 		ret = btrfs_find_first_ordered_inode(
 				&cur_trans->ordered_inode_tree,
@@ -512,7 +517,6 @@
 			break;
 
 		mutex_unlock(&root->fs_info->trans_mutex);
-		mutex_unlock(&root->fs_info->fs_mutex);
 
 		if (S_ISREG(inode->i_mode)) {
 			atomic_inc(&BTRFS_I(inode)->ordered_writeback);
@@ -521,7 +525,6 @@
 		}
 		iput(inode);
 
-		mutex_lock(&root->fs_info->fs_mutex);
 		mutex_lock(&root->fs_info->trans_mutex);
 	}
 	while(1) {
@@ -533,7 +536,6 @@
 		if (!ret)
 			break;
 		mutex_unlock(&root->fs_info->trans_mutex);
-		mutex_unlock(&root->fs_info->fs_mutex);
 
 		if (S_ISREG(inode->i_mode)) {
 			atomic_inc(&BTRFS_I(inode)->ordered_writeback);
@@ -543,10 +545,9 @@
 		atomic_dec(&inode->i_count);
 		iput(inode);
 
-		mutex_lock(&root->fs_info->fs_mutex);
 		mutex_lock(&root->fs_info->trans_mutex);
 	}
-	root->fs_info->throttles--;
+	atomic_dec(&root->fs_info->throttles);
 	return 0;
 }
 
@@ -661,7 +662,6 @@
 		mutex_unlock(&root->fs_info->trans_mutex);
 		btrfs_end_transaction(trans, root);
 
-		mutex_unlock(&root->fs_info->fs_mutex);
 		ret = wait_for_commit(root, cur_trans);
 		BUG_ON(ret);
 
@@ -669,7 +669,6 @@
 		put_transaction(cur_trans);
 		mutex_unlock(&root->fs_info->trans_mutex);
 
-		mutex_lock(&root->fs_info->fs_mutex);
 		return 0;
 	}
 
@@ -687,12 +686,10 @@
 					struct btrfs_transaction, list);
 		if (!prev_trans->commit_done) {
 			prev_trans->use_count++;
-			mutex_unlock(&root->fs_info->fs_mutex);
 			mutex_unlock(&root->fs_info->trans_mutex);
 
 			wait_for_commit(root, prev_trans);
 
-			mutex_lock(&root->fs_info->fs_mutex);
 			mutex_lock(&root->fs_info->trans_mutex);
 			put_transaction(prev_trans);
 		}
@@ -709,12 +706,10 @@
 		else
 			timeout = 1;
 
-		mutex_unlock(&root->fs_info->fs_mutex);
 		mutex_unlock(&root->fs_info->trans_mutex);
 
 		schedule_timeout(timeout);
 
-		mutex_lock(&root->fs_info->fs_mutex);
 		mutex_lock(&root->fs_info->trans_mutex);
 		finish_wait(&cur_trans->writer_wait, &wait);
 		ret = btrfs_write_ordered_inodes(trans, root);
@@ -755,12 +750,10 @@
 	btrfs_copy_pinned(root, pinned_copy);
 
 	mutex_unlock(&root->fs_info->trans_mutex);
-	mutex_unlock(&root->fs_info->fs_mutex);
 	ret = btrfs_write_and_wait_transaction(trans, root);
 	BUG_ON(ret);
 	write_ctree_super(trans, root);
 
-	mutex_lock(&root->fs_info->fs_mutex);
 	btrfs_finish_extent_commit(trans, root, pinned_copy);
 	mutex_lock(&root->fs_info->trans_mutex);
 
@@ -781,9 +774,7 @@
 	kmem_cache_free(btrfs_trans_handle_cachep, trans);
 
 	if (root->fs_info->closing) {
-		mutex_unlock(&root->fs_info->fs_mutex);
 		drop_dirty_roots(root->fs_info->tree_root, &dirty_fs_roots);
-		mutex_lock(&root->fs_info->fs_mutex);
 	}
 	return ret;
 }
@@ -823,7 +814,7 @@
 	unsigned long delay = HZ * 30;
 	int ret;
 
-	mutex_lock(&root->fs_info->fs_mutex);
+	smp_mb();
 	if (root->fs_info->closing)
 		goto out;
 
@@ -844,7 +835,6 @@
 	trans = btrfs_start_transaction(root, 1);
 	ret = btrfs_commit_transaction(trans, root);
 out:
-	mutex_unlock(&root->fs_info->fs_mutex);
 	btrfs_clean_old_snapshots(root);
 	btrfs_transaction_queue_work(root, delay);
 }
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index ba39685..869864d 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -866,7 +866,8 @@
 	u64 devid;
 	int ret = 0;
 
-	mutex_lock(&root->fs_info->fs_mutex);
+	mutex_lock(&root->fs_info->alloc_mutex);
+	mutex_lock(&root->fs_info->chunk_mutex);
 	mutex_lock(&uuid_mutex);
 
 	all_avail = root->fs_info->avail_data_alloc_bits |
@@ -984,7 +985,8 @@
 		close_bdev_excl(bdev);
 out:
 	mutex_unlock(&uuid_mutex);
-	mutex_unlock(&root->fs_info->fs_mutex);
+	mutex_unlock(&root->fs_info->chunk_mutex);
+	mutex_unlock(&root->fs_info->alloc_mutex);
 	return ret;
 }
 
@@ -1003,7 +1005,10 @@
 	if (!bdev) {
 		return -EIO;
 	}
-	mutex_lock(&root->fs_info->fs_mutex);
+
+	mutex_lock(&root->fs_info->alloc_mutex);
+	mutex_lock(&root->fs_info->chunk_mutex);
+
 	trans = btrfs_start_transaction(root, 1);
 	devices = &root->fs_info->fs_devices->devices;
 	list_for_each(cur, devices) {
@@ -1057,7 +1062,9 @@
 	root->fs_info->fs_devices->open_devices++;
 out:
 	btrfs_end_transaction(trans, root);
-	mutex_unlock(&root->fs_info->fs_mutex);
+	mutex_unlock(&root->fs_info->chunk_mutex);
+	mutex_unlock(&root->fs_info->alloc_mutex);
+
 	return ret;
 
 out_close_bdev:
@@ -1297,9 +1304,10 @@
 	struct btrfs_key found_key;
 
 
+	BUG(); /* FIXME, needs locking */
+
 	dev_root = dev_root->fs_info->dev_root;
 
-	mutex_lock(&dev_root->fs_info->fs_mutex);
 	/* step one make some room on all the devices */
 	list_for_each(cur, devices) {
 		device = list_entry(cur, struct btrfs_device, dev_list);
@@ -1368,7 +1376,6 @@
 	ret = 0;
 error:
 	btrfs_free_path(path);
-	mutex_unlock(&dev_root->fs_info->fs_mutex);
 	return ret;
 }
 
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index f63488d..3e9eb91 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -153,7 +153,6 @@
 		return -ENOMEM;
 	}
 
-	mutex_lock(&root->fs_info->fs_mutex);
 	/* lookup the xattr by name */
 	di = btrfs_lookup_xattr(NULL, root, path, inode->i_ino, name,
 				strlen(name), 0);
@@ -181,7 +180,6 @@
 	ret = btrfs_dir_data_len(leaf, di);
 
 out:
-	mutex_unlock(&root->fs_info->fs_mutex);
 	kfree(name);
 	btrfs_free_path(path);
 	return ret;
@@ -210,7 +208,6 @@
 		return -ENOMEM;
 	}
 
-	mutex_lock(&root->fs_info->fs_mutex);
 	trans = btrfs_start_transaction(root, 1);
 	btrfs_set_trans_block_group(trans, inode);
 
@@ -260,7 +257,6 @@
 	}
 
 	btrfs_end_transaction(trans, root);
-	mutex_unlock(&root->fs_info->fs_mutex);
 	kfree(name);
 	btrfs_free_path(path);
 
@@ -297,8 +293,6 @@
 		return -ENOMEM;
 	path->reada = 2;
 
-	mutex_lock(&root->fs_info->fs_mutex);
-
 	/* search for our xattrs */
 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 	if (ret < 0)
@@ -379,15 +373,13 @@
 	ret = total_size;
 
 err:
-	mutex_unlock(&root->fs_info->fs_mutex);
 	btrfs_free_path(path);
 
 	return ret;
 }
 
 /*
- * delete all the xattrs associated with the inode.  fs_mutex should be
- * held when we come into here
+ * delete all the xattrs associated with the inode.
  */
 int btrfs_delete_xattrs(struct btrfs_trans_handle *trans,
 			struct btrfs_root *root, struct inode *inode)