diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2011-12-06 22:38:24 -0500 |
---|---|---|
committer | Li Zefan <lizf@cn.fujitsu.com> | 2012-01-10 21:26:54 -0500 |
commit | b367e47fb3a70f5d24ebd6faf7d42436d485fb2d (patch) | |
tree | 5acc05bae14070f2dad3433a1482fe3a7bab0744 /fs | |
parent | c7c144db531fda414e532adac56e965ce332e2a5 (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.c | 2 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 9 |
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; |
3546 | out: | 3546 | out: |
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; |
3739 | error: | 3741 | error: |
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 | } |