From 5e8cb9b6249de3ac036ef4cf4b7babc2f4b95d90 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 8 Jun 2017 15:16:41 +0200 Subject: [PATCH] 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 Signed-off-by: Jan Kara --- fs/quota/dquot.c | 28 ++++++++++++++-------------- 1 file 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); -- 2.20.1