Commit b367e47f authored by Li Zefan's avatar Li Zefan

Btrfs: fix possible deadlock when opening a seed device

The correct lock order is uuid_mutex -> volume_mutex -> chunk_mutex,
but when we mount a filesystem which has backing seed devices, we have
this lock chain:

    open_ctree()
        lock(chunk_mutex);
        read_chunk_tree();
            read_one_dev();
                open_seed_devices();
                    lock(uuid_mutex);

and then we hit a lockdep splat.
Signed-off-by: default avatarLi Zefan <lizf@cn.fujitsu.com>
parent c7c144db
...@@ -2270,9 +2270,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -2270,9 +2270,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
(unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node), (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node),
BTRFS_UUID_SIZE); BTRFS_UUID_SIZE);
mutex_lock(&fs_info->chunk_mutex);
ret = btrfs_read_chunk_tree(chunk_root); ret = btrfs_read_chunk_tree(chunk_root);
mutex_unlock(&fs_info->chunk_mutex);
if (ret) { if (ret) {
printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n", printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n",
sb->s_id); sb->s_id);
......
...@@ -3506,7 +3506,7 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid) ...@@ -3506,7 +3506,7 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
struct btrfs_fs_devices *fs_devices; struct btrfs_fs_devices *fs_devices;
int ret; int ret;
mutex_lock(&uuid_mutex); BUG_ON(!mutex_is_locked(&uuid_mutex));
fs_devices = root->fs_info->fs_devices->seed; fs_devices = root->fs_info->fs_devices->seed;
while (fs_devices) { while (fs_devices) {
...@@ -3544,7 +3544,6 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid) ...@@ -3544,7 +3544,6 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
fs_devices->seed = root->fs_info->fs_devices->seed; fs_devices->seed = root->fs_info->fs_devices->seed;
root->fs_info->fs_devices->seed = fs_devices; root->fs_info->fs_devices->seed = fs_devices;
out: out:
mutex_unlock(&uuid_mutex);
return ret; return ret;
} }
...@@ -3687,6 +3686,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) ...@@ -3687,6 +3686,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
mutex_lock(&uuid_mutex);
lock_chunks(root);
/* first we search for all of the device items, and then we /* first we search for all of the device items, and then we
* read in all of the chunk items. This way we can create chunk * read in all of the chunk items. This way we can create chunk
* mappings that reference all of the devices that are afound * mappings that reference all of the devices that are afound
...@@ -3737,6 +3739,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) ...@@ -3737,6 +3739,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
} }
ret = 0; ret = 0;
error: error:
unlock_chunks(root);
mutex_unlock(&uuid_mutex);
btrfs_free_path(path); btrfs_free_path(path);
return ret; return ret;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment