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/btrfs/volumes.c | |
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/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 9 |
1 files changed, 7 insertions, 2 deletions
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 | } |