mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-07 13:43:51 +00:00
ufs: fix deadlocks introduced by sb mutex merge
Commit 0244756edc
("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>
This commit is contained in:
parent
81b6b06197
commit
9ef7db7f38
@ -902,9 +902,6 @@ void ufs_evict_inode(struct inode * inode)
|
|||||||
invalidate_inode_buffers(inode);
|
invalidate_inode_buffers(inode);
|
||||||
clear_inode(inode);
|
clear_inode(inode);
|
||||||
|
|
||||||
if (want_delete) {
|
if (want_delete)
|
||||||
lock_ufs(inode->i_sb);
|
ufs_free_inode(inode);
|
||||||
ufs_free_inode (inode);
|
|
||||||
unlock_ufs(inode->i_sb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -126,12 +126,12 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
|
|||||||
if (l > sb->s_blocksize)
|
if (l > sb->s_blocksize)
|
||||||
goto out_notlocked;
|
goto out_notlocked;
|
||||||
|
|
||||||
lock_ufs(dir->i_sb);
|
|
||||||
inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
|
inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
if (IS_ERR(inode))
|
if (IS_ERR(inode))
|
||||||
goto out;
|
goto out_notlocked;
|
||||||
|
|
||||||
|
lock_ufs(dir->i_sb);
|
||||||
if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
|
if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
|
||||||
/* slow symlink */
|
/* slow symlink */
|
||||||
inode->i_op = &ufs_symlink_inode_operations;
|
inode->i_op = &ufs_symlink_inode_operations;
|
||||||
@ -181,13 +181,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
|
|||||||
struct inode * inode;
|
struct inode * inode;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
lock_ufs(dir->i_sb);
|
|
||||||
inode_inc_link_count(dir);
|
|
||||||
|
|
||||||
inode = ufs_new_inode(dir, S_IFDIR|mode);
|
inode = ufs_new_inode(dir, S_IFDIR|mode);
|
||||||
err = PTR_ERR(inode);
|
|
||||||
if (IS_ERR(inode))
|
if (IS_ERR(inode))
|
||||||
goto out_dir;
|
return PTR_ERR(inode);
|
||||||
|
|
||||||
inode->i_op = &ufs_dir_inode_operations;
|
inode->i_op = &ufs_dir_inode_operations;
|
||||||
inode->i_fop = &ufs_dir_operations;
|
inode->i_fop = &ufs_dir_operations;
|
||||||
@ -195,6 +191,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
|
|||||||
|
|
||||||
inode_inc_link_count(inode);
|
inode_inc_link_count(inode);
|
||||||
|
|
||||||
|
lock_ufs(dir->i_sb);
|
||||||
|
inode_inc_link_count(dir);
|
||||||
|
|
||||||
err = ufs_make_empty(inode, dir);
|
err = ufs_make_empty(inode, dir);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_fail;
|
goto out_fail;
|
||||||
@ -212,7 +211,6 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
|
|||||||
inode_dec_link_count(inode);
|
inode_dec_link_count(inode);
|
||||||
inode_dec_link_count(inode);
|
inode_dec_link_count(inode);
|
||||||
iput (inode);
|
iput (inode);
|
||||||
out_dir:
|
|
||||||
inode_dec_link_count(dir);
|
inode_dec_link_count(dir);
|
||||||
unlock_ufs(dir->i_sb);
|
unlock_ufs(dir->i_sb);
|
||||||
goto out;
|
goto out;
|
||||||
|
Loading…
Reference in New Issue
Block a user