quota: Fix possible deadlock during parallel quotaon and quotaoff
The following test script triggers a deadlock on ext2 filesystem: while true; do quotaon /dev/hda >&/dev/null; usleep $RANDOM; done & while true; do quotaoff /dev/hda >&/dev/null; usleep $RANDOM; done & I found there is a potential deadlock between quotaon and quotaoff (or quotasync). Basically, all of quotactl operations need to be protected by dqonoff_mutex. vfs_quota_off and vfs_quota_sync also call sb->s_op->quota_write that needs to grab the i_mutex of the quota file. But in vfs_quota_on_inode (called from quotaon operation), the current code tries to grab the i_mutex of the quota file first before getting quonoff_mutex. Reverse the order in which we take locks in vfs_quota_on_inode(). Jan Kara: Changed changelog to be more readable, made lockdep happy with I_MUTEX_QUOTA. Signed-off-by: Jiaying Zhang <jiayingz@google.com> Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
parent
faf80d62e4
commit
d01730d74d
1 changed files with 2 additions and 2 deletions
|
@ -2042,8 +2042,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
|
||||||
* changes */
|
* changes */
|
||||||
invalidate_bdev(sb->s_bdev);
|
invalidate_bdev(sb->s_bdev);
|
||||||
}
|
}
|
||||||
mutex_lock(&inode->i_mutex);
|
|
||||||
mutex_lock(&dqopt->dqonoff_mutex);
|
mutex_lock(&dqopt->dqonoff_mutex);
|
||||||
|
mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
|
||||||
if (sb_has_quota_loaded(sb, type)) {
|
if (sb_has_quota_loaded(sb, type)) {
|
||||||
error = -EBUSY;
|
error = -EBUSY;
|
||||||
goto out_lock;
|
goto out_lock;
|
||||||
|
@ -2094,7 +2094,6 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
|
||||||
dqopt->files[type] = NULL;
|
dqopt->files[type] = NULL;
|
||||||
iput(inode);
|
iput(inode);
|
||||||
out_lock:
|
out_lock:
|
||||||
mutex_unlock(&dqopt->dqonoff_mutex);
|
|
||||||
if (oldflags != -1) {
|
if (oldflags != -1) {
|
||||||
down_write(&dqopt->dqptr_sem);
|
down_write(&dqopt->dqptr_sem);
|
||||||
/* Set the flags back (in the case of accidental quotaon()
|
/* Set the flags back (in the case of accidental quotaon()
|
||||||
|
@ -2104,6 +2103,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
|
||||||
up_write(&dqopt->dqptr_sem);
|
up_write(&dqopt->dqptr_sem);
|
||||||
}
|
}
|
||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
mutex_unlock(&dqopt->dqonoff_mutex);
|
||||||
out_fmt:
|
out_fmt:
|
||||||
put_quota_format(fmt);
|
put_quota_format(fmt);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue