Currently dq_state_lock is global, which is bad for scalability. In fact different super_blocks has no shared quota's data. So we may simply convert global lock to per-sb lock. Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxx> --- fs/quota/dquot.c | 31 +++++++++++++++---------------- fs/super.c | 1 + include/linux/quota.h | 1 + 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index ce542e2..eddf5cf 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -128,7 +128,6 @@ */ static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_list_lock); -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_state_lock); __cacheline_aligned_in_smp DEFINE_SPINLOCK(dq_data_lock); EXPORT_SYMBOL(dq_data_lock); @@ -819,13 +818,13 @@ struct dquot *dqget(struct super_block *sb, unsigned int id, int type) return NULL; we_slept: spin_lock(&dq_list_lock); - spin_lock(&dq_state_lock); + spin_lock(&sb_dqopt(sb)->dq_state_lock); if (!sb_has_quota_active(sb, type)) { - spin_unlock(&dq_state_lock); + spin_unlock(&sb_dqopt(sb)->dq_state_lock); spin_unlock(&dq_list_lock); goto out; } - spin_unlock(&dq_state_lock); + spin_unlock(&sb_dqopt(sb)->dq_state_lock); dquot = find_dquot(hashent, sb, id, type); if (!dquot) { @@ -1918,24 +1917,24 @@ int dquot_disable(struct super_block *sb, int type, unsigned int flags) continue; if (flags & DQUOT_SUSPENDED) { - spin_lock(&dq_state_lock); + spin_lock(&dqopt->dq_state_lock); dqopt->flags |= dquot_state_flag(DQUOT_SUSPENDED, cnt); - spin_unlock(&dq_state_lock); + spin_unlock(&dqopt->dq_state_lock); } else { - spin_lock(&dq_state_lock); + spin_lock(&dqopt->dq_state_lock); dqopt->flags &= ~dquot_state_flag(flags, cnt); /* Turning off suspended quotas? */ if (!sb_has_quota_loaded(sb, cnt) && sb_has_quota_suspended(sb, cnt)) { dqopt->flags &= ~dquot_state_flag( DQUOT_SUSPENDED, cnt); - spin_unlock(&dq_state_lock); + spin_unlock(&dqopt->dq_state_lock); iput(dqopt->files[cnt]); dqopt->files[cnt] = NULL; continue; } - spin_unlock(&dq_state_lock); + spin_unlock(&dqopt->dq_state_lock); } /* We still have to keep quota loaded? */ @@ -2112,9 +2111,9 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, goto out_file_init; } mutex_unlock(&dqopt->dqio_mutex); - spin_lock(&dq_state_lock); + spin_lock(&dqopt->dq_state_lock); dqopt->flags |= dquot_state_flag(flags, type); - spin_unlock(&dq_state_lock); + spin_unlock(&dqopt->dq_state_lock); add_dquot_ref(sb, type); mutex_unlock(&dqopt->dqonoff_mutex); @@ -2159,12 +2158,12 @@ int dquot_resume(struct super_block *sb, int type) } inode = dqopt->files[cnt]; dqopt->files[cnt] = NULL; - spin_lock(&dq_state_lock); + spin_lock(&dqopt->dq_state_lock); flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED, cnt); dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, cnt); - spin_unlock(&dq_state_lock); + spin_unlock(&dqopt->dq_state_lock); mutex_unlock(&dqopt->dqonoff_mutex); flags = dquot_generic_flag(flags, cnt); @@ -2228,9 +2227,9 @@ int dquot_enable(struct inode *inode, int type, int format_id, ret = -EBUSY; goto out_lock; } - spin_lock(&dq_state_lock); - sb_dqopt(sb)->flags |= dquot_state_flag(flags, type); - spin_unlock(&dq_state_lock); + spin_lock(&dqopt->dq_state_lock); + dqopt->flags |= dquot_state_flag(flags, type); + spin_unlock(&dqopt->dq_state_lock); out_lock: mutex_unlock(&dqopt->dqonoff_mutex); return ret; diff --git a/fs/super.c b/fs/super.c index 8819e3a..b54cb8b 100644 --- a/fs/super.c +++ b/fs/super.c @@ -105,6 +105,7 @@ static struct super_block *alloc_super(struct file_system_type *type) lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key); mutex_init(&s->s_dquot.dqio_mutex); mutex_init(&s->s_dquot.dqonoff_mutex); + spin_lock_init(&s->s_dquot.dq_state_lock); init_rwsem(&s->s_dquot.dqptr_sem); init_waitqueue_head(&s->s_wait_unfrozen); s->s_maxbytes = MAX_NON_LFS; diff --git a/include/linux/quota.h b/include/linux/quota.h index 00e1b3d..e39b01c 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h @@ -398,6 +398,7 @@ struct quota_info { struct mutex dqio_mutex; /* lock device while I/O in progress */ struct mutex dqonoff_mutex; /* Serialize quotaon & quotaoff */ struct rw_semaphore dqptr_sem; /* serialize ops using quota_info struct, pointers from inode to dquots */ + spinlock_t dq_state_lock; /* serialize quota state changes*/ struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */ struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ const struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ -- 1.6.6.1 -- 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