aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-05-04 09:38:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-04 17:20:20 -0400
commit30106b8ce2cc2243514116d6f29086e6deecc754 (patch)
treea2fe06bb2b47a508eaa38680112066bb2eb0bb6b
parent0ee5623f9a6e52df90a78bd21179f8ab370e102e (diff)
slub: Fix the lockless code on 32-bit platforms with no 64-bit cmpxchg
The SLUB allocator use of the cmpxchg_double logic was wrong: it actually needs the irq-safe one. That happens automatically when we use the native unlocked 'cmpxchg8b' instruction, but when compiling the kernel for older x86 CPUs that do not support that instruction, we fall back to the generic emulation code. And if you don't specify that you want the irq-safe version, the generic code ends up just open-coding the cmpxchg8b equivalent without any protection against interrupts or preemption. Which definitely doesn't work for SLUB. This was reported by Werner Landgraf <w.landgraf@ru.ru>, who saw instability with his distro-kernel that was compiled to support pretty much everything under the sun. Most big Linux distributions tend to compile for PPro and later, and would never have noticed this problem. This also fixes the prototypes for the irqsafe cmpxchg_double functions to use 'bool' like they should. [ Btw, that whole "generic code defaults to no protection" design just sounds stupid - if the code needs no protection, there is no reason to use "cmpxchg_double" to begin with. So we should probably just remove the unprotected version entirely as pointless. - Linus ] Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reported-and-tested-by: werner <w.landgraf@ru.ru> Acked-and-tested-by: Ingo Molnar <mingo@elte.hu> Acked-by: Christoph Lameter <cl@linux.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: Jens Axboe <axboe@kernel.dk> Cc: Tejun Heo <tj@kernel.org> Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1105041539050.3005@ionos Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/percpu.h2
-rw-r--r--mm/slub.c4
2 files changed, 3 insertions, 3 deletions
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 3a5c4449fd36..8b97308e65df 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -948,7 +948,7 @@ do { \
948 irqsafe_generic_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) 948 irqsafe_generic_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
949# endif 949# endif
950# define irqsafe_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ 950# define irqsafe_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \
951 __pcpu_double_call_return_int(irqsafe_cpu_cmpxchg_double_, (pcp1), (pcp2), (oval1), (oval2), (nval1), (nval2)) 951 __pcpu_double_call_return_bool(irqsafe_cpu_cmpxchg_double_, (pcp1), (pcp2), (oval1), (oval2), (nval1), (nval2))
952#endif 952#endif
953 953
954#endif /* __LINUX_PERCPU_H */ 954#endif /* __LINUX_PERCPU_H */
diff --git a/mm/slub.c b/mm/slub.c
index 94d2a33a866e..9d2e5e46bf09 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1940,7 +1940,7 @@ redo:
1940 * Since this is without lock semantics the protection is only against 1940 * Since this is without lock semantics the protection is only against
1941 * code executing on this cpu *not* from access by other cpus. 1941 * code executing on this cpu *not* from access by other cpus.
1942 */ 1942 */
1943 if (unlikely(!this_cpu_cmpxchg_double( 1943 if (unlikely(!irqsafe_cpu_cmpxchg_double(
1944 s->cpu_slab->freelist, s->cpu_slab->tid, 1944 s->cpu_slab->freelist, s->cpu_slab->tid,
1945 object, tid, 1945 object, tid,
1946 get_freepointer(s, object), next_tid(tid)))) { 1946 get_freepointer(s, object), next_tid(tid)))) {
@@ -2145,7 +2145,7 @@ redo:
2145 set_freepointer(s, object, c->freelist); 2145 set_freepointer(s, object, c->freelist);
2146 2146
2147#ifdef CONFIG_CMPXCHG_LOCAL 2147#ifdef CONFIG_CMPXCHG_LOCAL
2148 if (unlikely(!this_cpu_cmpxchg_double( 2148 if (unlikely(!irqsafe_cpu_cmpxchg_double(
2149 s->cpu_slab->freelist, s->cpu_slab->tid, 2149 s->cpu_slab->freelist, s->cpu_slab->tid,
2150 c->freelist, tid, 2150 c->freelist, tid,
2151 object, next_tid(tid)))) { 2151 object, next_tid(tid)))) {