diff options
author | Alexey Khoroshilov <khoroshilov@ispras.ru> | 2014-09-02 03:40:17 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-09-07 13:26:39 -0400 |
commit | 9ef7db7f38d0472dd9c444e42d5c5175ccbe5451 (patch) | |
tree | 38098751b8e07a868788fda862f96763b55d0763 /fs/ufs | |
parent | 81b6b06197606b4bef4e427a197aeb808e8d89e1 (diff) |
ufs: fix deadlocks introduced by sb mutex merge
Commit 0244756edc4b ("ufs: sb mutex merge + mutex_destroy") introduces
deadlocks in ufs_new_inode() and ufs_free_inode().
Most callers of that functions acqure the mutex by themselves and
ufs_{new,free}_inode() do that via lock_ufs(),
i.e we have an unavoidable double lock.
The patch proposes to resolve the issue by making sure that
ufs_{new,free}_inode() are not called with the mutex held.
Found by Linux Driver Verification project (linuxtesting.org).
Cc: stable@vger.kernel.org # 3.16
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ufs')
-rw-r--r-- | fs/ufs/inode.c | 7 | ||||
-rw-r--r-- | fs/ufs/namei.c | 14 |
2 files changed, 8 insertions, 13 deletions
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 7c580c97990e..be7d42c7d938 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c | |||
@@ -902,9 +902,6 @@ void ufs_evict_inode(struct inode * inode) | |||
902 | invalidate_inode_buffers(inode); | 902 | invalidate_inode_buffers(inode); |
903 | clear_inode(inode); | 903 | clear_inode(inode); |
904 | 904 | ||
905 | if (want_delete) { | 905 | if (want_delete) |
906 | lock_ufs(inode->i_sb); | 906 | ufs_free_inode(inode); |
907 | ufs_free_inode (inode); | ||
908 | unlock_ufs(inode->i_sb); | ||
909 | } | ||
910 | } | 907 | } |
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 90d74b8f8eba..2df62a73f20c 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c | |||
@@ -126,12 +126,12 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry, | |||
126 | if (l > sb->s_blocksize) | 126 | if (l > sb->s_blocksize) |
127 | goto out_notlocked; | 127 | goto out_notlocked; |
128 | 128 | ||
129 | lock_ufs(dir->i_sb); | ||
130 | inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO); | 129 | inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO); |
131 | err = PTR_ERR(inode); | 130 | err = PTR_ERR(inode); |
132 | if (IS_ERR(inode)) | 131 | if (IS_ERR(inode)) |
133 | goto out; | 132 | goto out_notlocked; |
134 | 133 | ||
134 | lock_ufs(dir->i_sb); | ||
135 | if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) { | 135 | if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) { |
136 | /* slow symlink */ | 136 | /* slow symlink */ |
137 | inode->i_op = &ufs_symlink_inode_operations; | 137 | inode->i_op = &ufs_symlink_inode_operations; |
@@ -181,13 +181,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) | |||
181 | struct inode * inode; | 181 | struct inode * inode; |
182 | int err; | 182 | int err; |
183 | 183 | ||
184 | lock_ufs(dir->i_sb); | ||
185 | inode_inc_link_count(dir); | ||
186 | |||
187 | inode = ufs_new_inode(dir, S_IFDIR|mode); | 184 | inode = ufs_new_inode(dir, S_IFDIR|mode); |
188 | err = PTR_ERR(inode); | ||
189 | if (IS_ERR(inode)) | 185 | if (IS_ERR(inode)) |
190 | goto out_dir; | 186 | return PTR_ERR(inode); |
191 | 187 | ||
192 | inode->i_op = &ufs_dir_inode_operations; | 188 | inode->i_op = &ufs_dir_inode_operations; |
193 | inode->i_fop = &ufs_dir_operations; | 189 | inode->i_fop = &ufs_dir_operations; |
@@ -195,6 +191,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) | |||
195 | 191 | ||
196 | inode_inc_link_count(inode); | 192 | inode_inc_link_count(inode); |
197 | 193 | ||
194 | lock_ufs(dir->i_sb); | ||
195 | inode_inc_link_count(dir); | ||
196 | |||
198 | err = ufs_make_empty(inode, dir); | 197 | err = ufs_make_empty(inode, dir); |
199 | if (err) | 198 | if (err) |
200 | goto out_fail; | 199 | goto out_fail; |
@@ -212,7 +211,6 @@ out_fail: | |||
212 | inode_dec_link_count(inode); | 211 | inode_dec_link_count(inode); |
213 | inode_dec_link_count(inode); | 212 | inode_dec_link_count(inode); |
214 | iput (inode); | 213 | iput (inode); |
215 | out_dir: | ||
216 | inode_dec_link_count(dir); | 214 | inode_dec_link_count(dir); |
217 | unlock_ufs(dir->i_sb); | 215 | unlock_ufs(dir->i_sb); |
218 | goto out; | 216 | goto out; |