diff options
author | Dmitry Monakhov <dmonakhov@openvz.org> | 2010-05-26 17:21:58 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2010-05-27 12:56:27 -0400 |
commit | f32764bd2bbb6ea003c158b1d276b4dc9f900348 (patch) | |
tree | 7fbabde3796a97b8b121349ea76b22b23238230a | |
parent | 1513b02c8b537af275ea74fdfb380c618b9e6778 (diff) |
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 dde9588853b1bde.
[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>
-rw-r--r-- | fs/quota/dquot.c | 46 | ||||
-rw-r--r-- | include/linux/quota.h | 16 |
2 files changed, 17 insertions, 45 deletions
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 1ff91314b8a0..531dee651ef7 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -228,10 +228,6 @@ static struct hlist_head *dquot_hash; | |||
228 | 228 | ||
229 | struct dqstats dqstats; | 229 | struct dqstats dqstats; |
230 | EXPORT_SYMBOL(dqstats); | 230 | EXPORT_SYMBOL(dqstats); |
231 | #ifdef CONFIG_SMP | ||
232 | struct dqstats *dqstats_pcpu; | ||
233 | EXPORT_SYMBOL(dqstats_pcpu); | ||
234 | #endif | ||
235 | 231 | ||
236 | static qsize_t inode_get_rsv_space(struct inode *inode); | 232 | static qsize_t inode_get_rsv_space(struct inode *inode); |
237 | static void __dquot_initialize(struct inode *inode, int type); | 233 | static void __dquot_initialize(struct inode *inode, int type); |
@@ -676,27 +672,10 @@ static void prune_dqcache(int count) | |||
676 | } | 672 | } |
677 | } | 673 | } |
678 | 674 | ||
679 | static int dqstats_read(unsigned int type) | ||
680 | { | ||
681 | int count = 0; | ||
682 | #ifdef CONFIG_SMP | ||
683 | int cpu; | ||
684 | for_each_possible_cpu(cpu) | ||
685 | count += per_cpu_ptr(dqstats_pcpu, cpu)->stat[type]; | ||
686 | /* Statistics reading is racy, but absolute accuracy isn't required */ | ||
687 | if (count < 0) | ||
688 | count = 0; | ||
689 | #else | ||
690 | count = dqstats.stat[type]; | ||
691 | #endif | ||
692 | return count; | ||
693 | } | ||
694 | |||
695 | /* | 675 | /* |
696 | * This is called from kswapd when we think we need some | 676 | * This is called from kswapd when we think we need some |
697 | * more memory | 677 | * more memory |
698 | */ | 678 | */ |
699 | |||
700 | static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) | 679 | static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) |
701 | { | 680 | { |
702 | if (nr) { | 681 | if (nr) { |
@@ -704,7 +683,9 @@ static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) | |||
704 | prune_dqcache(nr); | 683 | prune_dqcache(nr); |
705 | spin_unlock(&dq_list_lock); | 684 | spin_unlock(&dq_list_lock); |
706 | } | 685 | } |
707 | return (dqstats_read(DQST_FREE_DQUOTS)/100) * sysctl_vfs_cache_pressure; | 686 | return ((unsigned) |
687 | percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS]) | ||
688 | /100) * sysctl_vfs_cache_pressure; | ||
708 | } | 689 | } |
709 | 690 | ||
710 | static struct shrinker dqcache_shrinker = { | 691 | static struct shrinker dqcache_shrinker = { |
@@ -2497,11 +2478,11 @@ EXPORT_SYMBOL(dquot_quotactl_ops); | |||
2497 | static int do_proc_dqstats(struct ctl_table *table, int write, | 2478 | static int do_proc_dqstats(struct ctl_table *table, int write, |
2498 | void __user *buffer, size_t *lenp, loff_t *ppos) | 2479 | void __user *buffer, size_t *lenp, loff_t *ppos) |
2499 | { | 2480 | { |
2500 | #ifdef CONFIG_SMP | ||
2501 | /* Update global table */ | ||
2502 | unsigned int type = (int *)table->data - dqstats.stat; | 2481 | unsigned int type = (int *)table->data - dqstats.stat; |
2503 | dqstats.stat[type] = dqstats_read(type); | 2482 | |
2504 | #endif | 2483 | /* Update global table */ |
2484 | dqstats.stat[type] = | ||
2485 | percpu_counter_sum_positive(&dqstats.counter[type]); | ||
2505 | return proc_dointvec(table, write, buffer, lenp, ppos); | 2486 | return proc_dointvec(table, write, buffer, lenp, ppos); |
2506 | } | 2487 | } |
2507 | 2488 | ||
@@ -2594,7 +2575,7 @@ static ctl_table sys_table[] = { | |||
2594 | 2575 | ||
2595 | static int __init dquot_init(void) | 2576 | static int __init dquot_init(void) |
2596 | { | 2577 | { |
2597 | int i; | 2578 | int i, ret; |
2598 | unsigned long nr_hash, order; | 2579 | unsigned long nr_hash, order; |
2599 | 2580 | ||
2600 | printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__); | 2581 | printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__); |
@@ -2612,12 +2593,11 @@ static int __init dquot_init(void) | |||
2612 | if (!dquot_hash) | 2593 | if (!dquot_hash) |
2613 | panic("Cannot create dquot hash table"); | 2594 | panic("Cannot create dquot hash table"); |
2614 | 2595 | ||
2615 | #ifdef CONFIG_SMP | 2596 | for (i = 0; i < _DQST_DQSTAT_LAST; i++) { |
2616 | dqstats_pcpu = alloc_percpu(struct dqstats); | 2597 | ret = percpu_counter_init(&dqstats.counter[i], 0); |
2617 | if (!dqstats_pcpu) | 2598 | if (ret) |
2618 | panic("Cannot create dquot stats table"); | 2599 | panic("Cannot create dquot stat counters"); |
2619 | #endif | 2600 | } |
2620 | memset(&dqstats, 0, sizeof(struct dqstats)); | ||
2621 | 2601 | ||
2622 | /* Find power-of-two hlist_heads which can fit into allocation */ | 2602 | /* Find power-of-two hlist_heads which can fit into allocation */ |
2623 | nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct hlist_head); | 2603 | nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct hlist_head); |
diff --git a/include/linux/quota.h b/include/linux/quota.h index 2789d07c37be..94c1f03b50eb 100644 --- a/include/linux/quota.h +++ b/include/linux/quota.h | |||
@@ -174,8 +174,7 @@ enum { | |||
174 | #include <linux/rwsem.h> | 174 | #include <linux/rwsem.h> |
175 | #include <linux/spinlock.h> | 175 | #include <linux/spinlock.h> |
176 | #include <linux/wait.h> | 176 | #include <linux/wait.h> |
177 | #include <linux/percpu.h> | 177 | #include <linux/percpu_counter.h> |
178 | #include <linux/smp.h> | ||
179 | 178 | ||
180 | #include <linux/dqblk_xfs.h> | 179 | #include <linux/dqblk_xfs.h> |
181 | #include <linux/dqblk_v1.h> | 180 | #include <linux/dqblk_v1.h> |
@@ -254,6 +253,7 @@ enum { | |||
254 | 253 | ||
255 | struct dqstats { | 254 | struct dqstats { |
256 | int stat[_DQST_DQSTAT_LAST]; | 255 | int stat[_DQST_DQSTAT_LAST]; |
256 | struct percpu_counter counter[_DQST_DQSTAT_LAST]; | ||
257 | }; | 257 | }; |
258 | 258 | ||
259 | extern struct dqstats *dqstats_pcpu; | 259 | extern struct dqstats *dqstats_pcpu; |
@@ -261,20 +261,12 @@ extern struct dqstats dqstats; | |||
261 | 261 | ||
262 | static inline void dqstats_inc(unsigned int type) | 262 | static inline void dqstats_inc(unsigned int type) |
263 | { | 263 | { |
264 | #ifdef CONFIG_SMP | 264 | percpu_counter_inc(&dqstats.counter[type]); |
265 | per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]++; | ||
266 | #else | ||
267 | dqstats.stat[type]++; | ||
268 | #endif | ||
269 | } | 265 | } |
270 | 266 | ||
271 | static inline void dqstats_dec(unsigned int type) | 267 | static inline void dqstats_dec(unsigned int type) |
272 | { | 268 | { |
273 | #ifdef CONFIG_SMP | 269 | percpu_counter_dec(&dqstats.counter[type]); |
274 | per_cpu_ptr(dqstats_pcpu, smp_processor_id())->stat[type]--; | ||
275 | #else | ||
276 | dqstats.stat[type]--; | ||
277 | #endif | ||
278 | } | 270 | } |
279 | 271 | ||
280 | #define DQ_MOD_B 0 /* dquot modified since read */ | 272 | #define DQ_MOD_B 0 /* dquot modified since read */ |