Skip to content

Commit 1bbdfd6

Browse files
GeHao01994gregkh
authored andcommitted
slab: Fix obj_ext mistakenly considered NULL due to race condition
commit 7f434e1 upstream. If two competing threads enter alloc_slab_obj_exts(), and the one that allocates the vector wins the cmpxchg(), the other thread that failed allocation mistakenly assumes that slab->obj_exts is still empty due to its own allocation failure. This will then trigger warnings with CONFIG_MEM_ALLOC_PROFILING_DEBUG checks in the subsequent free path. Therefore, let's check the result of cmpxchg() to see if marking the allocation as failed was successful. If it wasn't, check whether the winning side has succeeded its allocation (it might have been also marking it as failed) and if yes, return success. Suggested-by: Harry Yoo <[email protected]> Fixes: f7381b9 ("slab: mark slab->obj_exts allocation failures unconditionally") Cc: <[email protected]> Signed-off-by: Hao Ge <[email protected]> Link: https://patch.msgid.link/[email protected] Reviewed-by: Suren Baghdasaryan <[email protected]> Reviewed-by: Harry Yoo <[email protected]> Signed-off-by: Vlastimil Babka <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 7c34fed commit 1bbdfd6

File tree

1 file changed

+11
-5
lines changed

1 file changed

+11
-5
lines changed

mm/slub.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,9 +1976,9 @@ static inline void mark_objexts_empty(struct slabobj_ext *obj_exts)
19761976
}
19771977
}
19781978

1979-
static inline void mark_failed_objexts_alloc(struct slab *slab)
1979+
static inline bool mark_failed_objexts_alloc(struct slab *slab)
19801980
{
1981-
cmpxchg(&slab->obj_exts, 0, OBJEXTS_ALLOC_FAIL);
1981+
return cmpxchg(&slab->obj_exts, 0, OBJEXTS_ALLOC_FAIL) == 0;
19821982
}
19831983

19841984
static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
@@ -2000,7 +2000,7 @@ static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
20002000
#else /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */
20012001

20022002
static inline void mark_objexts_empty(struct slabobj_ext *obj_exts) {}
2003-
static inline void mark_failed_objexts_alloc(struct slab *slab) {}
2003+
static inline bool mark_failed_objexts_alloc(struct slab *slab) { return false; }
20042004
static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
20052005
struct slabobj_ext *vec, unsigned int objects) {}
20062006

@@ -2033,8 +2033,14 @@ int alloc_slab_obj_exts(struct slab *slab, struct kmem_cache *s,
20332033
vec = kcalloc_node(objects, sizeof(struct slabobj_ext), gfp,
20342034
slab_nid(slab));
20352035
if (!vec) {
2036-
/* Mark vectors which failed to allocate */
2037-
mark_failed_objexts_alloc(slab);
2036+
/*
2037+
* Try to mark vectors which failed to allocate.
2038+
* If this operation fails, there may be a racing process
2039+
* that has already completed the allocation.
2040+
*/
2041+
if (!mark_failed_objexts_alloc(slab) &&
2042+
slab_obj_exts(slab))
2043+
return 0;
20382044

20392045
return -ENOMEM;
20402046
}

0 commit comments

Comments
 (0)