summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-02-04 15:31:28 +0100
committerChris Mason <chris.mason@oracle.com>2009-02-04 15:31:28 +0100
commit4d081c41a4f98aecb5e86ef7d3e644cc7b52131f (patch)
tree441e557a52e85a71e60da81d578bcb22fd4760d7
parentBtrfs: Change btrfs_truncate_inode_items to stop when it hits the inode (diff)
downloadlinux-4d081c41a4f98aecb5e86ef7d3e644cc7b52131f.tar.xz
linux-4d081c41a4f98aecb5e86ef7d3e644cc7b52131f.zip
Btrfs: change btrfs_del_leaf to drop locks earlier
btrfs_del_leaf does two things. First it removes the pointer in the parent, and then it frees the block that has the leaf. It has the parent node locked for both operations. But, it only needs the parent locked while it is deleting the pointer. After that it can safely free the block without the parent locked. Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/ctree.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index 3af777357acb..f6916ceb3920 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -3630,15 +3630,22 @@ noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
{
int ret;
u64 root_gen = btrfs_header_generation(path->nodes[1]);
+ u64 parent_start = path->nodes[1]->start;
+ u64 parent_owner = btrfs_header_owner(path->nodes[1]);
ret = del_ptr(trans, root, path, 1, path->slots[1]);
if (ret)
return ret;
+ /*
+ * btrfs_free_extent is expensive, we want to make sure we
+ * aren't holding any locks when we call it
+ */
+ btrfs_unlock_up_safe(path, 0);
+
ret = btrfs_free_extent(trans, root, bytenr,
btrfs_level_size(root, 0),
- path->nodes[1]->start,
- btrfs_header_owner(path->nodes[1]),
+ parent_start, parent_owner,
root_gen, 0, 1);
return ret;
}