Skip to content

Commit

Permalink
Btrfs: fix protection between walking backrefs and root deletion
Browse files Browse the repository at this point in the history
There is a race condition between resolving indirect ref and root deletion,
and we should gurantee that root can not be destroyed to avoid accessing
broken tree here.

Here we fix it by holding @subvol_srcu, and we will release it as soon
as we have held root node lock.

Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Chris Mason <clm@fb.com>
  • Loading branch information
Wang Shilong authored and Chris Mason committed Jan 29, 2014
1 parent 3c9665d commit 538f72c
Showing 1 changed file with 12 additions and 1 deletion.
13 changes: 12 additions & 1 deletion fs/btrfs/backref.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,23 +301,34 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
int ret = 0;
int root_level;
int level = ref->level;
int index;

root_key.objectid = ref->root_id;
root_key.type = BTRFS_ROOT_ITEM_KEY;
root_key.offset = (u64)-1;

index = srcu_read_lock(&fs_info->subvol_srcu);

root = btrfs_read_fs_root_no_name(fs_info, &root_key);
if (IS_ERR(root)) {
srcu_read_unlock(&fs_info->subvol_srcu, index);
ret = PTR_ERR(root);
goto out;
}

root_level = btrfs_old_root_level(root, time_seq);

if (root_level + 1 == level)
if (root_level + 1 == level) {
srcu_read_unlock(&fs_info->subvol_srcu, index);
goto out;
}

path->lowest_level = level;
ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq);

/* root node has been locked, we can release @subvol_srcu safely here */
srcu_read_unlock(&fs_info->subvol_srcu, index);

pr_debug("search slot in root %llu (level %d, ref count %d) returned "
"%d for key (%llu %u %llu)\n",
ref->root_id, level, ref->count, ret,
Expand Down

0 comments on commit 538f72c

Please sign in to comment.