This allow us to remove dq_state_lock from dqget quota state test. synchronize_rcu() in dquot_disable() is a bit strage usage for RCU, but rcu_read_lock will be used in dqget() more properly later to get make lookup lock-less. Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx> --- fs/quota/dquot.c | 32 ++++++++++++++++++++++---------- 1 files changed, 22 insertions(+), 10 deletions(-) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 771aaab..0d755ef 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -878,7 +878,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) /* * Get reference to dquot * - * Locking is slightly tricky here. We are guarded from parallel quotaoff() + * We are guarded from parallel quotaoff() by holding rcu_read_lock * destroying our dquot by: * a) checking for quota flags under dq_list_lock and * b) getting a reference to dquot before we release dq_list_lock @@ -888,17 +888,15 @@ struct dquot *dqget(struct super_block *sb, unsigned int id, int type) struct dquot *dquot = NULL, *empty = NULL; struct quota_info *dqopt = dqopts(sb); - if (!sb_has_quota_active(sb, type)) - return NULL; we_slept: - spin_lock(&dqopt->dq_list_lock); - spin_lock(&dqopt->dq_state_lock); + rcu_read_lock(); if (!sb_has_quota_active(sb, type)) { - spin_unlock(&dqopt->dq_state_lock); - spin_unlock(&dqopt->dq_list_lock); - goto out; + rcu_read_unlock(); + return NULL; } - spin_unlock(&dqopt->dq_state_lock); + spin_lock(&dqopt->dq_list_lock); + /* XXX: Currently RCU used only for synchronization with quotaoff */ + rcu_read_unlock(); dquot = find_dquot(sb, id, type); if (!dquot) { @@ -2113,6 +2111,21 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags) if (sb_has_quota_loaded(sb, cnt) && !(flags & DQUOT_SUSPENDED)) continue; + toputinode[cnt] = dqopt->files[cnt]; + } + /* + * Wait for all dqget() callers to finish. + */ + synchronize_rcu(); + + /* + * At this moment all quota functions disabled, is is now safe to + * perform final cleanup. + */ + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + + if (!toputinode[cnt]) + continue; /* Note: these are blocking operations */ drop_dquot_ref(sb, cnt); invalidate_dquots(sb, cnt); @@ -2126,7 +2139,6 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags) dqopt->fmt_ops[cnt]->free_file_info(sb, cnt); put_quota_format(dqopt->info[cnt].dqi_format); - toputinode[cnt] = dqopt->files[cnt]; if (!sb_has_quota_loaded(sb, cnt)) dqopt->files[cnt] = NULL; dqopt->info[cnt].dqi_flags = 0; -- 1.6.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html