summaryrefslogtreecommitdiffstats
path: root/mm/slub.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-03-17 11:04:09 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-03-25 08:06:13 +0100
commit451d4a2390ed7236b3713c315780c3c50618748c (patch)
treee3c1cef67a845cff59b88f7f9f2a6cbc11a27408 /mm/slub.c
parente48392bc0fdb14f10bc624c745996400a298fbfb (diff)
downloadlinux-stable-451d4a2390ed7236b3713c315780c3c50618748c.tar.gz
linux-stable-451d4a2390ed7236b3713c315780c3c50618748c.tar.bz2
linux-stable-451d4a2390ed7236b3713c315780c3c50618748c.zip
mm: slub: be more careful about the double cmpxchg of freelist
commit 5076190daded2197f62fe92cf69674488be44175 upstream. This is just a cleanup addition to Jann's fix to properly update the transaction ID for the slub slowpath in commit fd4d9c7d0c71 ("mm: slub: add missing TID bump.."). The transaction ID is what protects us against any concurrent accesses, but we should really also make sure to make the 'freelist' comparison itself always use the same freelist value that we then used as the new next free pointer. Jann points out that if we do all of this carefully, we could skip the transaction ID update for all the paths that only remove entries from the lists, and only update the TID when adding entries (to avoid the ABA issue with cmpxchg and list handling re-adding a previously seen value). But this patch just does the "make sure to cmpxchg the same value we used" rather than then try to be clever. Acked-by: Jann Horn <jannh@google.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'mm/slub.c')
-rw-r--r--mm/slub.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/mm/slub.c b/mm/slub.c
index 764a1023ed87..aa30de783e63 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2926,11 +2926,13 @@ redo:
barrier();
if (likely(page == c->page)) {
- set_freepointer(s, tail_obj, c->freelist);
+ void **freelist = READ_ONCE(c->freelist);
+
+ set_freepointer(s, tail_obj, freelist);
if (unlikely(!this_cpu_cmpxchg_double(
s->cpu_slab->freelist, s->cpu_slab->tid,
- c->freelist, tid,
+ freelist, tid,
head, next_tid(tid)))) {
note_cmpxchg_failure("slab_free", s, tid);