diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2009-11-11 10:13:32 -0500 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2009-11-12 20:33:24 -0500 |
commit | c1ea985c710f41e97f1c72c29bbf367375370f0b (patch) | |
tree | 7345a5041a7ea432dcdebe664b7e57066d968e9f | |
parent | 156171c71a0dc4bce12b4408bb1591f8fe32dc1a (diff) |
nilfs2: fix lock order reversal in chcp operation
Will fix the following lock order reversal lockdep detected:
=======================================================
[ INFO: possible circular locking dependency detected ]
2.6.32-rc6 #7
-------------------------------------------------------
chcp/30157 is trying to acquire lock:
(&nilfs->ns_mount_mutex){+.+.+.}, at: [<fed7cfcc>] nilfs_cpfile_change_cpmode+0x46/0x752 [nilfs2]
but task is already holding lock:
(&nilfs->ns_segctor_sem){++++.+}, at: [<fed7ca32>] nilfs_transaction_begin+0xba/0x110 [nilfs2]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (&nilfs->ns_segctor_sem){++++.+}:
[<c105799c>] __lock_acquire+0x109c/0x139d
[<c1057d26>] lock_acquire+0x89/0xa0
[<c14151e2>] down_read+0x31/0x45
[<fed6d77b>] nilfs_attach_checkpoint+0x8f/0x16b [nilfs2]
[<fed6e393>] nilfs_get_sb+0x3e7/0x653 [nilfs2]
[<c10c0ccb>] vfs_kern_mount+0x8b/0x124
[<c10c0db2>] do_kern_mount+0x37/0xc3
[<c10d7517>] do_mount+0x64d/0x69d
[<c10d75cd>] sys_mount+0x66/0x95
[<c1002a14>] sysenter_do_call+0x12/0x32
-> #1 (&type->s_umount_key#31/1){+.+.+.}:
[<c105799c>] __lock_acquire+0x109c/0x139d
[<c1057d26>] lock_acquire+0x89/0xa0
[<c104c0f3>] down_write_nested+0x34/0x52
[<c10c08fe>] sget+0x22e/0x389
[<fed6e133>] nilfs_get_sb+0x187/0x653 [nilfs2]
[<c10c0ccb>] vfs_kern_mount+0x8b/0x124
[<c10c0db2>] do_kern_mount+0x37/0xc3
[<c10d7517>] do_mount+0x64d/0x69d
[<c10d75cd>] sys_mount+0x66/0x95
[<c1002a14>] sysenter_do_call+0x12/0x32
-> #0 (&nilfs->ns_mount_mutex){+.+.+.}:
[<c1057727>] __lock_acquire+0xe27/0x139d
[<c1057d26>] lock_acquire+0x89/0xa0
[<c1414d63>] mutex_lock_nested+0x41/0x23e
[<fed7cfcc>] nilfs_cpfile_change_cpmode+0x46/0x752 [nilfs2]
[<fed801b2>] nilfs_ioctl+0x11a/0x7da [nilfs2]
[<c10cca12>] vfs_ioctl+0x27/0x6e
[<c10ccf93>] do_vfs_ioctl+0x491/0x4db
[<c10cd022>] sys_ioctl+0x45/0x5f
[<c1002a14>] sysenter_do_call+0x12/0x32
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
-rw-r--r-- | fs/nilfs2/cpfile.c | 2 | ||||
-rw-r--r-- | fs/nilfs2/ioctl.c | 6 |
2 files changed, 5 insertions, 3 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 1c6cfb59128d..3f5d5d06f53c 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c | |||
@@ -871,7 +871,6 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) | |||
871 | * exclusive with a new mount job. Though it doesn't cover | 871 | * exclusive with a new mount job. Though it doesn't cover |
872 | * umount, it's enough for the purpose. | 872 | * umount, it's enough for the purpose. |
873 | */ | 873 | */ |
874 | mutex_lock(&nilfs->ns_mount_mutex); | ||
875 | if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) { | 874 | if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) { |
876 | /* Current implementation does not have to protect | 875 | /* Current implementation does not have to protect |
877 | plain read-only mounts since they are exclusive | 876 | plain read-only mounts since they are exclusive |
@@ -880,7 +879,6 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) | |||
880 | ret = -EBUSY; | 879 | ret = -EBUSY; |
881 | } else | 880 | } else |
882 | ret = nilfs_cpfile_clear_snapshot(cpfile, cno); | 881 | ret = nilfs_cpfile_clear_snapshot(cpfile, cno); |
883 | mutex_unlock(&nilfs->ns_mount_mutex); | ||
884 | return ret; | 882 | return ret; |
885 | case NILFS_SNAPSHOT: | 883 | case NILFS_SNAPSHOT: |
886 | return nilfs_cpfile_set_snapshot(cpfile, cno); | 884 | return nilfs_cpfile_set_snapshot(cpfile, cno); |
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index d24057d58f17..f6af76042d80 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
@@ -99,7 +99,8 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, | |||
99 | static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, | 99 | static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, |
100 | unsigned int cmd, void __user *argp) | 100 | unsigned int cmd, void __user *argp) |
101 | { | 101 | { |
102 | struct inode *cpfile = NILFS_SB(inode->i_sb)->s_nilfs->ns_cpfile; | 102 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; |
103 | struct inode *cpfile = nilfs->ns_cpfile; | ||
103 | struct nilfs_transaction_info ti; | 104 | struct nilfs_transaction_info ti; |
104 | struct nilfs_cpmode cpmode; | 105 | struct nilfs_cpmode cpmode; |
105 | int ret; | 106 | int ret; |
@@ -109,14 +110,17 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, | |||
109 | if (copy_from_user(&cpmode, argp, sizeof(cpmode))) | 110 | if (copy_from_user(&cpmode, argp, sizeof(cpmode))) |
110 | return -EFAULT; | 111 | return -EFAULT; |
111 | 112 | ||
113 | mutex_lock(&nilfs->ns_mount_mutex); | ||
112 | nilfs_transaction_begin(inode->i_sb, &ti, 0); | 114 | nilfs_transaction_begin(inode->i_sb, &ti, 0); |
113 | ret = nilfs_cpfile_change_cpmode( | 115 | ret = nilfs_cpfile_change_cpmode( |
114 | cpfile, cpmode.cm_cno, cpmode.cm_mode); | 116 | cpfile, cpmode.cm_cno, cpmode.cm_mode); |
115 | if (unlikely(ret < 0)) { | 117 | if (unlikely(ret < 0)) { |
116 | nilfs_transaction_abort(inode->i_sb); | 118 | nilfs_transaction_abort(inode->i_sb); |
119 | mutex_unlock(&nilfs->ns_mount_mutex); | ||
117 | return ret; | 120 | return ret; |
118 | } | 121 | } |
119 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | 122 | nilfs_transaction_commit(inode->i_sb); /* never fails */ |
123 | mutex_unlock(&nilfs->ns_mount_mutex); | ||
120 | return ret; | 124 | return ret; |
121 | } | 125 | } |
122 | 126 | ||