forked from mirrors/linux
		
	quota: Convert quota statistics to generic percpu_counter
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 dde9588853.
[Jan Kara: Fixed patch to work on 32-bit archs as well]
Reported-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
Signed-off-by: Jan Kara <jack@suse.cz>
			
			
This commit is contained in:
		
							parent
							
								
									1513b02c8b
								
							
						
					
					
						commit
						f32764bd2b
					
				
					 2 changed files with 17 additions and 45 deletions
				
			
		|  | @ -228,10 +228,6 @@ static struct hlist_head *dquot_hash; | ||||||
| 
 | 
 | ||||||
| struct dqstats dqstats; | struct dqstats dqstats; | ||||||
| EXPORT_SYMBOL(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 qsize_t inode_get_rsv_space(struct inode *inode); | ||||||
| static void __dquot_initialize(struct inode *inode, int type); | 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 |  * This is called from kswapd when we think we need some | ||||||
|  * more memory |  * more memory | ||||||
|  */ |  */ | ||||||
| 
 |  | ||||||
| static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) | static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) | ||||||
| { | { | ||||||
| 	if (nr) { | 	if (nr) { | ||||||
|  | @ -704,7 +683,9 @@ static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) | ||||||
| 		prune_dqcache(nr); | 		prune_dqcache(nr); | ||||||
| 		spin_unlock(&dq_list_lock); | 		spin_unlock(&dq_list_lock); | ||||||
| 	} | 	} | ||||||
| 	return (dqstats_read(DQST_FREE_DQUOTS)/100) * sysctl_vfs_cache_pressure; | 	return ((unsigned) | ||||||
|  | 		percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS]) | ||||||
|  | 		/100) * sysctl_vfs_cache_pressure; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct shrinker dqcache_shrinker = { | static struct shrinker dqcache_shrinker = { | ||||||
|  | @ -2497,11 +2478,11 @@ EXPORT_SYMBOL(dquot_quotactl_ops); | ||||||
| static int do_proc_dqstats(struct ctl_table *table, int write, | static int do_proc_dqstats(struct ctl_table *table, int write, | ||||||
| 		     void __user *buffer, size_t *lenp, loff_t *ppos) | 		     void __user *buffer, size_t *lenp, loff_t *ppos) | ||||||
| { | { | ||||||
| #ifdef CONFIG_SMP |  | ||||||
| 	/* Update global table */ |  | ||||||
| 	unsigned int type = (int *)table->data - dqstats.stat; | 	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); | 	return proc_dointvec(table, write, buffer, lenp, ppos); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -2594,7 +2575,7 @@ static ctl_table sys_table[] = { | ||||||
| 
 | 
 | ||||||
| static int __init dquot_init(void) | static int __init dquot_init(void) | ||||||
| { | { | ||||||
| 	int i; | 	int i, ret; | ||||||
| 	unsigned long nr_hash, order; | 	unsigned long nr_hash, order; | ||||||
| 
 | 
 | ||||||
| 	printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__); | 	printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__); | ||||||
|  | @ -2612,12 +2593,11 @@ static int __init dquot_init(void) | ||||||
| 	if (!dquot_hash) | 	if (!dquot_hash) | ||||||
| 		panic("Cannot create dquot hash table"); | 		panic("Cannot create dquot hash table"); | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_SMP | 	for (i = 0; i < _DQST_DQSTAT_LAST; i++) { | ||||||
| 	dqstats_pcpu = alloc_percpu(struct dqstats); | 		ret = percpu_counter_init(&dqstats.counter[i], 0); | ||||||
| 	if (!dqstats_pcpu) | 		if (ret) | ||||||
| 		panic("Cannot create dquot stats table"); | 			panic("Cannot create dquot stat counters"); | ||||||
| #endif | 	} | ||||||
| 	memset(&dqstats, 0, sizeof(struct dqstats)); |  | ||||||
| 
 | 
 | ||||||
| 	/* Find power-of-two hlist_heads which can fit into allocation */ | 	/* Find power-of-two hlist_heads which can fit into allocation */ | ||||||
| 	nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct hlist_head); | 	nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct hlist_head); | ||||||
|  |  | ||||||
|  | @ -174,8 +174,7 @@ enum { | ||||||
| #include <linux/rwsem.h> | #include <linux/rwsem.h> | ||||||
| #include <linux/spinlock.h> | #include <linux/spinlock.h> | ||||||
| #include <linux/wait.h> | #include <linux/wait.h> | ||||||
| #include <linux/percpu.h> | #include <linux/percpu_counter.h> | ||||||
| #include <linux/smp.h> |  | ||||||
| 
 | 
 | ||||||
| #include <linux/dqblk_xfs.h> | #include <linux/dqblk_xfs.h> | ||||||
| #include <linux/dqblk_v1.h> | #include <linux/dqblk_v1.h> | ||||||
|  | @ -254,6 +253,7 @@ enum { | ||||||
| 
 | 
 | ||||||
| struct dqstats { | struct dqstats { | ||||||
| 	int stat[_DQST_DQSTAT_LAST]; | 	int stat[_DQST_DQSTAT_LAST]; | ||||||
|  | 	struct percpu_counter counter[_DQST_DQSTAT_LAST]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| extern struct dqstats *dqstats_pcpu; | extern struct dqstats *dqstats_pcpu; | ||||||
|  | @ -261,20 +261,12 @@ extern struct dqstats dqstats; | ||||||
| 
 | 
 | ||||||
| static inline void dqstats_inc(unsigned int type) | static inline void dqstats_inc(unsigned int type) | ||||||
| { | { | ||||||
| #ifdef CONFIG_SMP | 	percpu_counter_inc(&dqstats.counter[type]); | ||||||
| 	per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]++; |  | ||||||
| #else |  | ||||||
| 	dqstats.stat[type]++; |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void dqstats_dec(unsigned int type) | static inline void dqstats_dec(unsigned int type) | ||||||
| { | { | ||||||
| #ifdef CONFIG_SMP | 	percpu_counter_dec(&dqstats.counter[type]); | ||||||
| 	per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]--; |  | ||||||
| #else |  | ||||||
| 	dqstats.stat[type]--; |  | ||||||
| #endif |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #define DQ_MOD_B	0	/* dquot modified since read */ | #define DQ_MOD_B	0	/* dquot modified since read */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Dmitry Monakhov
						Dmitry Monakhov