diff options
author | Jan Kara <jack@suse.cz> | 2017-06-08 15:16:41 +0200 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2017-08-17 19:00:50 +0200 |
commit | 5e8cb9b6249de3ac036ef4cf4b7babc2f4b95d90 (patch) | |
tree | d1c594afe05bb850be832c423934486324939994 /fs/quota | |
parent | d6ab3661020cbf8a8909b49a8e1408d5ae434001 (diff) | |
download | lwn-5e8cb9b6249de3ac036ef4cf4b7babc2f4b95d90.tar.gz lwn-5e8cb9b6249de3ac036ef4cf4b7babc2f4b95d90.zip |
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.c | 28 |
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); |