aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLi Zefan <lizf@cn.fujitsu.com>2011-12-06 22:38:24 -0500
committerLi Zefan <lizf@cn.fujitsu.com>2012-01-10 21:26:54 -0500
commitb367e47fb3a70f5d24ebd6faf7d42436d485fb2d (patch)
tree5acc05bae14070f2dad3433a1482fe3a7bab0744 /fs
parentc7c144db531fda414e532adac56e965ce332e2a5 (diff)
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: Li Zefan <lizf@cn.fujitsu.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/disk-io.c2
-rw-r--r--fs/btrfs/volumes.c9
2 files changed, 7 insertions, 4 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 3f9d5551e582..858ab347413e 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2270,9 +2270,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
2270 (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node), 2270 (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node),
2271 BTRFS_UUID_SIZE); 2271 BTRFS_UUID_SIZE);
2272 2272
2273 mutex_lock(&fs_info->chunk_mutex);
2274 ret = btrfs_read_chunk_tree(chunk_root); 2273 ret = btrfs_read_chunk_tree(chunk_root);
2275 mutex_unlock(&fs_info->chunk_mutex);
2276 if (ret) { 2274 if (ret) {
2277 printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n", 2275 printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n",
2278 sb->s_id); 2276 sb->s_id);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 563ef650850e..fbb493b28d5a 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3506,7 +3506,7 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
3506 struct btrfs_fs_devices *fs_devices; 3506 struct btrfs_fs_devices *fs_devices;
3507 int ret; 3507 int ret;
3508 3508
3509 mutex_lock(&uuid_mutex); 3509 BUG_ON(!mutex_is_locked(&uuid_mutex));
3510 3510
3511 fs_devices = root->fs_info->fs_devices->seed; 3511 fs_devices = root->fs_info->fs_devices->seed;
3512 while (fs_devices) { 3512 while (fs_devices) {
@@ -3544,7 +3544,6 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
3544 fs_devices->seed = root->fs_info->fs_devices->seed; 3544 fs_devices->seed = root->fs_info->fs_devices->seed;
3545 root->fs_info->fs_devices->seed = fs_devices; 3545 root->fs_info->fs_devices->seed = fs_devices;
3546out: 3546out:
3547 mutex_unlock(&uuid_mutex);
3548 return ret; 3547 return ret;
3549} 3548}
3550 3549
@@ -3687,6 +3686,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
3687 if (!path) 3686 if (!path)
3688 return -ENOMEM; 3687 return -ENOMEM;
3689 3688
3689 mutex_lock(&uuid_mutex);
3690 lock_chunks(root);
3691
3690 /* first we search for all of the device items, and then we 3692 /* first we search for all of the device items, and then we
3691 * read in all of the chunk items. This way we can create chunk 3693 * read in all of the chunk items. This way we can create chunk
3692 * mappings that reference all of the devices that are afound 3694 * mappings that reference all of the devices that are afound
@@ -3737,6 +3739,9 @@ again:
3737 } 3739 }
3738 ret = 0; 3740 ret = 0;
3739error: 3741error:
3742 unlock_chunks(root);
3743 mutex_unlock(&uuid_mutex);
3744
3740 btrfs_free_path(path); 3745 btrfs_free_path(path);
3741 return ret; 3746 return ret;
3742} 3747}