diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index a4cb4b642987..1967462e2021 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -2089,7 +2089,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, int ins_len, int cow) { struct btrfs_fs_info *fs_info = root->fs_info; - struct extent_buffer *b; + struct extent_buffer *b, *rb; int slot; int ret; int err; @@ -2100,6 +2100,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, u8 lowest_level = 0; int min_write_lock_level; int prev_cmp; + int root_level; might_sleep(); @@ -2157,6 +2158,8 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, goto done; } + root_level = btrfs_header_level(b); + rb = b; while (b) { int dec = 0; @@ -2299,6 +2302,12 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root, goto done; } } else { + if (p->locks[root_level] && + down_read_trylock(&rb->lock)) { + up_read(&rb->lock); + p->locks[root_level] = 0; + goto again; + } btrfs_tree_read_lock(b); } p->locks[level] = BTRFS_READ_LOCK;