From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dmitry Monakhov Subject: Re: [PATCH] quota: Convert quota statistics to generic percpu_counter Date: Thu, 27 May 2010 19:45:56 +0400 Message-ID: <87vda99wlm.fsf@openvz.org> References: <1274966859-18289-1-git-send-email-jack@suse.cz> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Cc: linux-fsdevel@vger.kernel.org To: Jan Kara Return-path: Received: from fg-out-1718.google.com ([72.14.220.159]:41743 "EHLO fg-out-1718.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932496Ab0E0PqB (ORCPT ); Thu, 27 May 2010 11:46:01 -0400 Received: by fg-out-1718.google.com with SMTP id d23so75686fga.1 for ; Thu, 27 May 2010 08:46:00 -0700 (PDT) In-Reply-To: <1274966859-18289-1-git-send-email-jack@suse.cz> (Jan Kara's message of "Thu, 27 May 2010 15:27:39 +0200") Sender: linux-fsdevel-owner@vger.kernel.org List-ID: Jan Kara writes: > From: Dmitry Monakhov > > Generic per-cpu counter has some memory overhead but it is negligible for > modern systems and embedded systems compile without quota support. And code > reuse is a good thing. This patch should fix complain from preemptive kernels > which was introduced by dde9588853b1bde. > > [Jan Kara: Fixed patch to work on 32-bit archs as well] Ohh. Thanks for fixing that. > > Reported-by: Rafael J. Wysocki > Signed-off-by: Dmitry Monakhov > Signed-off-by: Jan Kara > --- > Dmitry, I have fixed the patch to use 'int' as quota stats used to instead > of s64 you used. Now I plan to push it to Linus to fix the reported bug... > > fs/quota/dquot.c | 45 ++++++++++++--------------------------------- > include/linux/quota.h | 16 ++++------------ > 2 files changed, 16 insertions(+), 45 deletions(-) > > diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c > index 1ff9131..36e2af8 100644 > --- a/fs/quota/dquot.c > +++ b/fs/quota/dquot.c > @@ -228,10 +228,6 @@ static struct hlist_head *dquot_hash; > > struct dqstats dqstats; > EXPORT_SYMBOL(dqstats); > -#ifdef CONFIG_SMP > -struct dqstats *dqstats_pcpu; > -EXPORT_SYMBOL(dqstats_pcpu); > -#endif > > static qsize_t inode_get_rsv_space(struct inode *inode); > static void __dquot_initialize(struct inode *inode, int type); > @@ -676,27 +672,10 @@ static void prune_dqcache(int count) > } > } > > -static int dqstats_read(unsigned int type) > -{ > - int count = 0; > -#ifdef CONFIG_SMP > - int cpu; > - for_each_possible_cpu(cpu) > - count += per_cpu_ptr(dqstats_pcpu, cpu)->stat[type]; > - /* Statistics reading is racy, but absolute accuracy isn't required */ > - if (count < 0) > - count = 0; > -#else > - count = dqstats.stat[type]; > -#endif > - return count; > -} > - > /* > * This is called from kswapd when we think we need some > * more memory > */ > - > static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) > { > if (nr) { > @@ -704,7 +683,8 @@ static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) > prune_dqcache(nr); > spin_unlock(&dq_list_lock); > } > - return (dqstats_read(DQST_FREE_DQUOTS)/100) * sysctl_vfs_cache_pressure; > + return (percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS]) > + /100) * sysctl_vfs_cache_pressure; > } > > static struct shrinker dqcache_shrinker = { > @@ -2497,11 +2477,11 @@ EXPORT_SYMBOL(dquot_quotactl_ops); > static int do_proc_dqstats(struct ctl_table *table, int write, > void __user *buffer, size_t *lenp, loff_t *ppos) > { > -#ifdef CONFIG_SMP > - /* Update global table */ > unsigned int type = (int *)table->data - dqstats.stat; > - dqstats.stat[type] = dqstats_read(type); > -#endif > + > + /* Update global table */ > + dqstats.stat[type] = > + percpu_counter_sum_positive(&dqstats.counter[type]); > return proc_dointvec(table, write, buffer, lenp, ppos); > } > > @@ -2594,7 +2574,7 @@ static ctl_table sys_table[] = { > > static int __init dquot_init(void) > { > - int i; > + int i, ret; > unsigned long nr_hash, order; > > printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__); > @@ -2612,12 +2592,11 @@ static int __init dquot_init(void) > if (!dquot_hash) > panic("Cannot create dquot hash table"); > > -#ifdef CONFIG_SMP > - dqstats_pcpu = alloc_percpu(struct dqstats); > - if (!dqstats_pcpu) > - panic("Cannot create dquot stats table"); > -#endif > - memset(&dqstats, 0, sizeof(struct dqstats)); > + for (i = 0; i < _DQST_DQSTAT_LAST; i++) { > + ret = percpu_counter_init(&dqstats.counter[i], 0); > + if (ret) > + panic("Cannot create dquot stat counters"); > + } > > /* Find power-of-two hlist_heads which can fit into allocation */ > nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct hlist_head); > diff --git a/include/linux/quota.h b/include/linux/quota.h > index 2789d07..94c1f03 100644 > --- a/include/linux/quota.h > +++ b/include/linux/quota.h > @@ -174,8 +174,7 @@ enum { > #include > #include > #include > -#include > -#include > +#include > > #include > #include > @@ -254,6 +253,7 @@ enum { > > struct dqstats { > int stat[_DQST_DQSTAT_LAST]; > + struct percpu_counter counter[_DQST_DQSTAT_LAST]; > }; > > extern struct dqstats *dqstats_pcpu; > @@ -261,20 +261,12 @@ extern struct dqstats dqstats; > > static inline void dqstats_inc(unsigned int type) > { > -#ifdef CONFIG_SMP > - per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]++; > -#else > - dqstats.stat[type]++; > -#endif > + percpu_counter_inc(&dqstats.counter[type]); > } > > static inline void dqstats_dec(unsigned int type) > { > -#ifdef CONFIG_SMP > - per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]--; > -#else > - dqstats.stat[type]--; > -#endif > + percpu_counter_dec(&dqstats.counter[type]); > } > > #define DQ_MOD_B 0 /* dquot modified since read */