summaryrefslogtreecommitdiff
path: root/fs/quota
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-06-08 16:16:41 +0300
committerJan Kara <jack@suse.cz>2017-08-17 20:00:50 +0300
commit5e8cb9b6249de3ac036ef4cf4b7babc2f4b95d90 (patch)
treed1c594afe05bb850be832c423934486324939994 /fs/quota
parentd6ab3661020cbf8a8909b49a8e1408d5ae434001 (diff)
downloadlinux-5e8cb9b6249de3ac036ef4cf4b7babc2f4b95d90.tar.xz
quota: Protect dquot writeout with dq_lock
Currently dquot writeout is only protected by dqio_sem held for writing. As we transition to a finer grained locking we will use dquot->dq_lock instead. So acquire it in dquot_commit() and move dqio_sem just around ->commit_dqblk() call as it is still needed to serialize quota file changes. Reviewed-by: Andreas Dilger <adilger@dilger.ca> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/quota')
-rw-r--r--fs/quota/dquot.c28
1 files changed, 14 insertions, 14 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 3852a3c79ac9..8b52e852eba2 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -110,14 +110,11 @@
* sure they cannot race with quotaon which first sets S_NOQUOTA flag and
* then drops all pointers to dquots from an inode.
*
- * Each dquot has its dq_lock mutex. Locked dquots might not be referenced
- * from inodes (dquot_alloc_space() and such don't check the dq_lock).
- * Currently dquot is locked only when it is being read to memory (or space for
- * it is being allocated) on the first dqget() and when it is being released on
- * the last dqput(). The allocation and release oparations are serialized by
- * the dq_lock and by checking the use count in dquot_release(). Write
- * operations on dquots don't hold dq_lock as they copy data under dq_data_lock
- * spinlock to internal buffers before writing.
+ * Each dquot has its dq_lock mutex. Dquot is locked when it is being read to
+ * memory (or space for it is being allocated) on the first dqget(), when it is
+ * being written out, and when it is being released on the last dqput(). The
+ * allocation and release operations are serialized by the dq_lock and by
+ * checking the use count in dquot_release().
*
* Lock ordering (including related VFS locks) is the following:
* s_umount > i_mutex > journal_lock > dquot->dq_lock > dqio_sem
@@ -453,21 +450,24 @@ int dquot_commit(struct dquot *dquot)
int ret = 0;
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
- down_write(&dqopt->dqio_sem);
+ mutex_lock(&dquot->dq_lock);
spin_lock(&dq_list_lock);
if (!clear_dquot_dirty(dquot)) {
spin_unlock(&dq_list_lock);
- goto out_sem;
+ goto out_lock;
}
spin_unlock(&dq_list_lock);
/* Inactive dquot can be only if there was error during read/init
* => we have better not writing it */
- if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
+ if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
+ down_write(&dqopt->dqio_sem);
ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot);
- else
+ up_write(&dqopt->dqio_sem);
+ } else {
ret = -EIO;
-out_sem:
- up_write(&dqopt->dqio_sem);
+ }
+out_lock:
+ mutex_unlock(&dquot->dq_lock);
return ret;
}
EXPORT_SYMBOL(dquot_commit);