diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2012-01-12 18:02:14 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2012-01-12 18:02:14 -0500 |
commit | bd77c04772da38fca510c81f78e51f727123b919 (patch) | |
tree | 8554b40191d3d5adebbd2461d26450c0ed7295d4 | |
parent | 48fd11880b5ef04270be8a87d9a9a9ee2fdae338 (diff) |
module: struct module_ref should contains long fields
module_ref contains two "unsigned int" fields.
Thats now too small, since some machines can open more than 2^32 files.
Check commit 518de9b39e8 (fs: allow for more than 2^31 files) for
reference.
We can add an aligned(2 * sizeof(unsigned long)) attribute to force
alloc_percpu() allocating module_ref areas in single cache lines.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Rusty Russell <rusty@rustcorp.com.au>
CC: Tejun Heo <tj@kernel.org>
CC: Robin Holt <holt@sgi.com>
CC: David Miller <davem@davemloft.net>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r-- | include/linux/module.h | 21 | ||||
-rw-r--r-- | kernel/debug/kdb/kdb_main.c | 2 | ||||
-rw-r--r-- | kernel/module.c | 8 |
3 files changed, 21 insertions, 10 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index 3cb7839a60b9..4598bf03e98b 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -205,6 +205,20 @@ enum module_state | |||
205 | MODULE_STATE_GOING, | 205 | MODULE_STATE_GOING, |
206 | }; | 206 | }; |
207 | 207 | ||
208 | /** | ||
209 | * struct module_ref - per cpu module reference counts | ||
210 | * @incs: number of module get on this cpu | ||
211 | * @decs: number of module put on this cpu | ||
212 | * | ||
213 | * We force an alignment on 8 or 16 bytes, so that alloc_percpu() | ||
214 | * put @incs/@decs in same cache line, with no extra memory cost, | ||
215 | * since alloc_percpu() is fine grained. | ||
216 | */ | ||
217 | struct module_ref { | ||
218 | unsigned long incs; | ||
219 | unsigned long decs; | ||
220 | } __attribute((aligned(2 * sizeof(unsigned long)))); | ||
221 | |||
208 | struct module | 222 | struct module |
209 | { | 223 | { |
210 | enum module_state state; | 224 | enum module_state state; |
@@ -347,10 +361,7 @@ struct module | |||
347 | /* Destruction function. */ | 361 | /* Destruction function. */ |
348 | void (*exit)(void); | 362 | void (*exit)(void); |
349 | 363 | ||
350 | struct module_ref { | 364 | struct module_ref __percpu *refptr; |
351 | unsigned int incs; | ||
352 | unsigned int decs; | ||
353 | } __percpu *refptr; | ||
354 | #endif | 365 | #endif |
355 | 366 | ||
356 | #ifdef CONFIG_CONSTRUCTORS | 367 | #ifdef CONFIG_CONSTRUCTORS |
@@ -434,7 +445,7 @@ extern void __module_put_and_exit(struct module *mod, long code) | |||
434 | #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code); | 445 | #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code); |
435 | 446 | ||
436 | #ifdef CONFIG_MODULE_UNLOAD | 447 | #ifdef CONFIG_MODULE_UNLOAD |
437 | unsigned int module_refcount(struct module *mod); | 448 | unsigned long module_refcount(struct module *mod); |
438 | void __symbol_put(const char *symbol); | 449 | void __symbol_put(const char *symbol); |
439 | #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x) | 450 | #define symbol_put(x) __symbol_put(MODULE_SYMBOL_PREFIX #x) |
440 | void symbol_put_addr(void *addr); | 451 | void symbol_put_addr(void *addr); |
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 63786e71a3cd..e2ae7349437f 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c | |||
@@ -1982,7 +1982,7 @@ static int kdb_lsmod(int argc, const char **argv) | |||
1982 | kdb_printf("%-20s%8u 0x%p ", mod->name, | 1982 | kdb_printf("%-20s%8u 0x%p ", mod->name, |
1983 | mod->core_size, (void *)mod); | 1983 | mod->core_size, (void *)mod); |
1984 | #ifdef CONFIG_MODULE_UNLOAD | 1984 | #ifdef CONFIG_MODULE_UNLOAD |
1985 | kdb_printf("%4d ", module_refcount(mod)); | 1985 | kdb_printf("%4ld ", module_refcount(mod)); |
1986 | #endif | 1986 | #endif |
1987 | if (mod->state == MODULE_STATE_GOING) | 1987 | if (mod->state == MODULE_STATE_GOING) |
1988 | kdb_printf(" (Unloading)"); | 1988 | kdb_printf(" (Unloading)"); |
diff --git a/kernel/module.c b/kernel/module.c index 4928cffc3dcc..14b8e82e05d4 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -725,9 +725,9 @@ static int try_stop_module(struct module *mod, int flags, int *forced) | |||
725 | } | 725 | } |
726 | } | 726 | } |
727 | 727 | ||
728 | unsigned int module_refcount(struct module *mod) | 728 | unsigned long module_refcount(struct module *mod) |
729 | { | 729 | { |
730 | unsigned int incs = 0, decs = 0; | 730 | unsigned long incs = 0, decs = 0; |
731 | int cpu; | 731 | int cpu; |
732 | 732 | ||
733 | for_each_possible_cpu(cpu) | 733 | for_each_possible_cpu(cpu) |
@@ -853,7 +853,7 @@ static inline void print_unload_info(struct seq_file *m, struct module *mod) | |||
853 | struct module_use *use; | 853 | struct module_use *use; |
854 | int printed_something = 0; | 854 | int printed_something = 0; |
855 | 855 | ||
856 | seq_printf(m, " %u ", module_refcount(mod)); | 856 | seq_printf(m, " %lu ", module_refcount(mod)); |
857 | 857 | ||
858 | /* Always include a trailing , so userspace can differentiate | 858 | /* Always include a trailing , so userspace can differentiate |
859 | between this and the old multi-field proc format. */ | 859 | between this and the old multi-field proc format. */ |
@@ -903,7 +903,7 @@ EXPORT_SYMBOL_GPL(symbol_put_addr); | |||
903 | static ssize_t show_refcnt(struct module_attribute *mattr, | 903 | static ssize_t show_refcnt(struct module_attribute *mattr, |
904 | struct module_kobject *mk, char *buffer) | 904 | struct module_kobject *mk, char *buffer) |
905 | { | 905 | { |
906 | return sprintf(buffer, "%u\n", module_refcount(mk->mod)); | 906 | return sprintf(buffer, "%lu\n", module_refcount(mk->mod)); |
907 | } | 907 | } |
908 | 908 | ||
909 | static struct module_attribute refcnt = { | 909 | static struct module_attribute refcnt = { |