On 2019/1/17 上午12:00, Josef Bacik wrote:
> qgroups will do the old roots lookup at delayed ref time, which could be
> while walking down the extent root while running a delayed ref. This
> should be fine, except we specifically lock eb's in the backref walking
> code irrespective of path->skip_locking, which deadlocks the system.
> Fix up the backref code to honor path->skip_locking, nobody will be
> modifying the commit_root when we're searching so it's completely safe
> to do. Thanks,
>
> Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
> ---
> fs/btrfs/backref.c | 16 ++++++++++------
> 1 file changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
> index 78556447e1d5..973e8251b1bf 100644
> --- a/fs/btrfs/backref.c
> +++ b/fs/btrfs/backref.c
> @@ -712,7 +712,7 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
> * read tree blocks and add keys where required.
> */
> static int add_missing_keys(struct btrfs_fs_info *fs_info,
> - struct preftrees *preftrees)
> + struct preftrees *preftrees, bool lock)
> {
> struct prelim_ref *ref;
> struct extent_buffer *eb;
> @@ -737,12 +737,14 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info,
> free_extent_buffer(eb);
> return -EIO;
> }
> - btrfs_tree_read_lock(eb);
> + if (lock)
> + btrfs_tree_read_lock(eb);
> if (btrfs_header_level(eb) == 0)
> btrfs_item_key_to_cpu(eb, &ref->key_for_search, 0);
> else
> btrfs_node_key_to_cpu(eb, &ref->key_for_search, 0);
> - btrfs_tree_read_unlock(eb);
> + if (lock)
> + btrfs_tree_read_unlock(eb);
> free_extent_buffer(eb);
> prelim_ref_insert(fs_info, &preftrees->indirect, ref, NULL);
> cond_resched();
> @@ -1227,7 +1229,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
>
> btrfs_release_path(path);
>
> - ret = add_missing_keys(fs_info, &preftrees);
> + ret = add_missing_keys(fs_info, &preftrees, path->skip_locking == 0);
> if (ret)
> goto out;
>
> @@ -1288,11 +1290,13 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
> ret = -EIO;
> goto out;
> }
> - btrfs_tree_read_lock(eb);
> + if (!path->skip_locking)
> + btrfs_tree_read_lock(eb);
> btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
This btrfs_set_lock_blocking_rw() or the btrfs_set_lock_blocking_read()
in latest misc-next call need @eb to be read locked first.
So this line should also be in the (!path->skip_locking) branch, and
such modification solves the BUG_ON() caused by btrfs/007.
Thanks,
Qu
> ret = find_extent_in_eb(eb, bytenr,
> *extent_item_pos, &eie, ignore_offset);
> - btrfs_tree_read_unlock_blocking(eb);
> + if (!path->skip_locking)
> + btrfs_tree_read_unlock_blocking(eb);
> free_extent_buffer(eb);
> if (ret < 0)
> goto out;
>
Attachment:
signature.asc
Description: OpenPGP digital signature
