Jan Kara <jack@xxxxxxx> writes: > From: Dmitry Monakhov <dmonakhov@xxxxxxxxxx> > > 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 <rjw@xxxxxxx> > Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx> > Signed-off-by: Jan Kara <jack@xxxxxxx> > --- > 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 <linux/rwsem.h> > #include <linux/spinlock.h> > #include <linux/wait.h> > -#include <linux/percpu.h> > -#include <linux/smp.h> > +#include <linux/percpu_counter.h> > > #include <linux/dqblk_xfs.h> > #include <linux/dqblk_v1.h> > @@ -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 */ -- 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