diff options
author | Jiaying Zhang <jiayingz@google.com> | 2009-07-07 18:15:21 +0200 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2009-07-07 18:15:21 +0200 |
commit | d01730d74d2b0155da50d44555001706294014f7 (patch) | |
tree | a6de6075c054b6f253be19062d7f8efc973d55dc | |
parent | faf80d62e44dc627efb741f48db50c1858d1667c (diff) | |
download | op-kernel-dev-d01730d74d2b0155da50d44555001706294014f7.zip op-kernel-dev-d01730d74d2b0155da50d44555001706294014f7.tar.gz |
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>
-rw-r--r-- | fs/quota/dquot.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 607c579..70f36c0 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -2042,8 +2042,8 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, * changes */ invalidate_bdev(sb->s_bdev); } - mutex_lock(&inode->i_mutex); mutex_lock(&dqopt->dqonoff_mutex); + mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); if (sb_has_quota_loaded(sb, type)) { error = -EBUSY; goto out_lock; @@ -2094,7 +2094,6 @@ out_file_init: dqopt->files[type] = NULL; iput(inode); out_lock: - mutex_unlock(&dqopt->dqonoff_mutex); if (oldflags != -1) { down_write(&dqopt->dqptr_sem); /* Set the flags back (in the case of accidental quotaon() @@ -2104,6 +2103,7 @@ out_lock: up_write(&dqopt->dqptr_sem); } mutex_unlock(&inode->i_mutex); + mutex_unlock(&dqopt->dqonoff_mutex); out_fmt: put_quota_format(fmt); |