summaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorChristoph Lameter <cl@linux.com>2013-01-23 21:45:48 (GMT)
committerScott Wood <scottwood@freescale.com>2013-04-04 22:09:04 (GMT)
commit3bc3e6047e6c95b221a7b8643a26525c3c9b5e55 (patch)
tree5ee0b1d3bf355ddbfd55a02bca110a9845a656d2 /mm
parentf7b344595ee56ed4d9ae21873c96654ec60958f0 (diff)
downloadlinux-fsl-qoriq-3bc3e6047e6c95b221a7b8643a26525c3c9b5e55.tar.xz
FIX [2/2] slub: Tid must be retrieved from the percpu area of the current processor
As Steven Rostedt has pointer out: Rescheduling could occur on a differnet processor after the determination of the per cpu pointer and before the tid is retrieved. This could result in allocation from the wrong node in slab_alloc. The effect is much more severe in slab_free() where we could free to the freelist of the wrong page. The window for something like that occurring is pretty small but it is possible. Signed-off-by: Christoph Lameter <cl@linux.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Pekka Enberg <penberg@kernel.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'mm')
-rw-r--r--mm/slub.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/mm/slub.c b/mm/slub.c
index 0f270db..3d2308f 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2331,13 +2331,13 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,
s = memcg_kmem_get_cache(s, gfpflags);
redo:
-
/*
- * Must read kmem_cache cpu data via this cpu ptr. Preemption is
- * enabled. We may switch back and forth between cpus while
- * reading from one cpu area. That does not matter as long
- * as we end up on the original cpu again when doing the cmpxchg.
+ * Preemption is disabled for the retrieval of the tid because that
+ * must occur from the current processor. We cannot allow rescheduling
+ * on a different processor between the determination of the pointer
+ * and the retrieval of the tid.
*/
+ preempt_disable();
c = __this_cpu_ptr(s->cpu_slab);
/*
@@ -2347,7 +2347,7 @@ redo:
* linked list in between.
*/
tid = c->tid;
- barrier();
+ preempt_enable();
object = c->freelist;
page = c->page;
@@ -2594,10 +2594,11 @@ redo:
* data is retrieved via this pointer. If we are on the same cpu
* during the cmpxchg then the free will succedd.
*/
+ preempt_disable();
c = __this_cpu_ptr(s->cpu_slab);
tid = c->tid;
- barrier();
+ preempt_enable();
if (likely(page == c->page)) {
set_freepointer(s, object, c->freelist);