| From mathieu.desnoyers@efficios.com Wed Apr 21 15:42:43 2010 |
| From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
| Date: Tue, 20 Apr 2010 10:38:10 -0400 |
| Subject: module: fix __module_ref_addr() |
| To: Greg KH <greg@kroah.com> |
| Cc: Steven Rostedt <rostedt@goodmis.org>, Randy Dunlap <randy.dunlap@oracle.com>, Greg Kroah-Hartman <gregkh@suse.de>, Peter Zijlstra <a.p.zijlstra@chello.nl>, stable <stable@kernel.org>, Rusty Russell <rusty@rustcorp.com.au>, linux-kernel@vger.kernel.org, Eric Dumazet <dada1@cosmosbay.com>, Tejun Heo <tj@kernel.org>, Ingo Molnar <mingo@elte.hu>, Linus Torvalds <torvalds@linux-foundation.org>, Andrew Morton <akpm@linux-foundation.org> |
| Message-ID: <20100420143810.GC14622@Krystal> |
| Content-Disposition: inline |
| |
| From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
| |
| The __module_ref_addr() problem disappears in 2.6.34-rc kernels because these |
| percpu accesses were re-factored. |
| |
| __module_ref_addr() should use per_cpu_ptr() to obfuscate the pointer |
| (RELOC_HIDE is needed for per cpu pointers). |
| |
| This non-standard per-cpu pointer use has been introduced by commit |
| 720eba31f47aeade8ec130ca7f4353223c49170f |
| |
| It causes a NULL pointer exception on some configurations when CONFIG_TRACING is |
| enabled on 2.6.33. This patch fixes the problem (acknowledged by Randy who |
| reported the bug). |
| |
| It did not appear to hurt previously because most of the accesses were done |
| through local_inc, which probably obfuscated the access enough that no compiler |
| optimizations were done. But with local_read() done when CONFIG_TRACING is |
| active, this becomes a problem. Non-CONFIG_TRACING is probably affected as well |
| (module.c contains local_set and local_read that use __module_ref_addr()), but I |
| guess nobody noticed because we've been lucky enough that the compiler did not |
| generate the inappropriate optimization pattern there. |
| |
| This patch should be queued for the 2.6.29.x through 2.6.33.x stable branches. |
| (tested on 2.6.33.1 x86_64) |
| |
| Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
| Tested-by: Randy Dunlap <randy.dunlap@oracle.com> |
| CC: Eric Dumazet <dada1@cosmosbay.com> |
| CC: Rusty Russell <rusty@rustcorp.com.au> |
| CC: Peter Zijlstra <a.p.zijlstra@chello.nl> |
| CC: Tejun Heo <tj@kernel.org> |
| CC: Ingo Molnar <mingo@elte.hu> |
| CC: Andrew Morton <akpm@linux-foundation.org> |
| CC: Linus Torvalds <torvalds@linux-foundation.org> |
| CC: Greg Kroah-Hartman <gregkh@suse.de> |
| CC: Steven Rostedt <rostedt@goodmis.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| include/linux/module.h | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/include/linux/module.h |
| +++ b/include/linux/module.h |
| @@ -455,7 +455,7 @@ void symbol_put_addr(void *addr); |
| static inline local_t *__module_ref_addr(struct module *mod, int cpu) |
| { |
| #ifdef CONFIG_SMP |
| - return (local_t *) (mod->refptr + per_cpu_offset(cpu)); |
| + return (local_t *) per_cpu_ptr(mod->refptr, cpu); |
| #else |
| return &mod->ref; |
| #endif |