Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b367e47f authored by Li Zefan's avatar Li Zefan
Browse files

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
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -2270,9 +2270,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
	   (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node),
	   BTRFS_UUID_SIZE);

	mutex_lock(&fs_info->chunk_mutex);
	ret = btrfs_read_chunk_tree(chunk_root);
	mutex_unlock(&fs_info->chunk_mutex);
	if (ret) {
		printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n",
		       sb->s_id);
+7 −2
Original line number Diff line number Diff line
@@ -3506,7 +3506,7 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
	struct btrfs_fs_devices *fs_devices;
	int ret;

	mutex_lock(&uuid_mutex);
	BUG_ON(!mutex_is_locked(&uuid_mutex));

	fs_devices = root->fs_info->fs_devices->seed;
	while (fs_devices) {
@@ -3544,7 +3544,6 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
	fs_devices->seed = root->fs_info->fs_devices->seed;
	root->fs_info->fs_devices->seed = fs_devices;
out:
	mutex_unlock(&uuid_mutex);
	return ret;
}

@@ -3687,6 +3686,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
	if (!path)
		return -ENOMEM;

	mutex_lock(&uuid_mutex);
	lock_chunks(root);

	/* 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
	 * mappings that reference all of the devices that are afound
@@ -3737,6 +3739,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
	}
	ret = 0;
error:
	unlock_chunks(root);
	mutex_unlock(&uuid_mutex);

	btrfs_free_path(path);
	return ret;
}