Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'slab-for-6.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab

Pull slab fixes from Vlastimil Babka:

- Two fixes for race conditions in obj_exts allocation (Hao Ge)

- Fix for slab accounting imbalance due to deferred slab decativation
(Vlastimil Babka)

* tag 'slab-for-6.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab:
slab: Fix obj_ext mistakenly considered NULL due to race condition
slab: fix slab accounting imbalance due to defer_deactivate_slab()
slab: Avoid race on slab->obj_exts in alloc_slab_obj_exts

+21 -10
+21 -10
mm/slub.c
··· 2052 2052 } 2053 2053 } 2054 2054 2055 - static inline void mark_failed_objexts_alloc(struct slab *slab) 2055 + static inline bool mark_failed_objexts_alloc(struct slab *slab) 2056 2056 { 2057 - slab->obj_exts = OBJEXTS_ALLOC_FAIL; 2057 + return cmpxchg(&slab->obj_exts, 0, OBJEXTS_ALLOC_FAIL) == 0; 2058 2058 } 2059 2059 2060 2060 static inline void handle_failed_objexts_alloc(unsigned long obj_exts, ··· 2076 2076 #else /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */ 2077 2077 2078 2078 static inline void mark_objexts_empty(struct slabobj_ext *obj_exts) {} 2079 - static inline void mark_failed_objexts_alloc(struct slab *slab) {} 2079 + static inline bool mark_failed_objexts_alloc(struct slab *slab) { return false; } 2080 2080 static inline void handle_failed_objexts_alloc(unsigned long obj_exts, 2081 2081 struct slabobj_ext *vec, unsigned int objects) {} 2082 2082 ··· 2124 2124 slab_nid(slab)); 2125 2125 } 2126 2126 if (!vec) { 2127 - /* Mark vectors which failed to allocate */ 2128 - mark_failed_objexts_alloc(slab); 2127 + /* 2128 + * Try to mark vectors which failed to allocate. 2129 + * If this operation fails, there may be a racing process 2130 + * that has already completed the allocation. 2131 + */ 2132 + if (!mark_failed_objexts_alloc(slab) && 2133 + slab_obj_exts(slab)) 2134 + return 0; 2129 2135 2130 2136 return -ENOMEM; 2131 2137 } ··· 2142 2136 #ifdef CONFIG_MEMCG 2143 2137 new_exts |= MEMCG_DATA_OBJEXTS; 2144 2138 #endif 2139 + retry: 2145 2140 old_exts = READ_ONCE(slab->obj_exts); 2146 2141 handle_failed_objexts_alloc(old_exts, vec, objects); 2147 2142 if (new_slab) { ··· 2152 2145 * be simply assigned. 2153 2146 */ 2154 2147 slab->obj_exts = new_exts; 2155 - } else if ((old_exts & ~OBJEXTS_FLAGS_MASK) || 2156 - cmpxchg(&slab->obj_exts, old_exts, new_exts) != old_exts) { 2148 + } else if (old_exts & ~OBJEXTS_FLAGS_MASK) { 2157 2149 /* 2158 2150 * If the slab is already in use, somebody can allocate and 2159 2151 * assign slabobj_exts in parallel. In this case the existing ··· 2164 2158 else 2165 2159 kfree(vec); 2166 2160 return 0; 2161 + } else if (cmpxchg(&slab->obj_exts, old_exts, new_exts) != old_exts) { 2162 + /* Retry if a racing thread changed slab->obj_exts from under us. */ 2163 + goto retry; 2167 2164 } 2168 2165 2169 2166 if (allow_spin) ··· 3428 3419 3429 3420 if (!allow_spin && !spin_trylock_irqsave(&n->list_lock, flags)) { 3430 3421 /* Unlucky, discard newly allocated slab */ 3431 - slab->frozen = 1; 3432 3422 defer_deactivate_slab(slab, NULL); 3433 3423 return NULL; 3434 3424 } ··· 6476 6468 struct slab *slab = container_of(pos, struct slab, llnode); 6477 6469 6478 6470 #ifdef CONFIG_SLUB_TINY 6479 - discard_slab(slab->slab_cache, slab); 6471 + free_slab(slab->slab_cache, slab); 6480 6472 #else 6481 - deactivate_slab(slab->slab_cache, slab, slab->flush_freelist); 6473 + if (slab->frozen) 6474 + deactivate_slab(slab->slab_cache, slab, slab->flush_freelist); 6475 + else 6476 + free_slab(slab->slab_cache, slab); 6482 6477 #endif 6483 6478 } 6484 6479 }