mirror of https://github.com/torvalds/linux.git
Merge branch 'slab/for-6.19/sheaves_cleanups' into slab/for-next
Merge series "slab: preparatory cleanups before adding sheaves to all caches" [1] Cleanups that were written as part of the full sheaves conversion, which is not fully ready yet, but they are useful on their own. Link: https://lore.kernel.org/all/20251105-sheaves-cleanups-v1-0-b8218e1ac7ef@suse.cz/ [1]
This commit is contained in:
commit
3065c20d5d
|
|
@ -55,9 +55,7 @@ enum {
|
|||
#ifdef CONFIG_LOCKDEP
|
||||
___GFP_NOLOCKDEP_BIT,
|
||||
#endif
|
||||
#ifdef CONFIG_SLAB_OBJ_EXT
|
||||
___GFP_NO_OBJ_EXT_BIT,
|
||||
#endif
|
||||
___GFP_LAST_BIT
|
||||
};
|
||||
|
||||
|
|
@ -98,11 +96,7 @@ enum {
|
|||
#else
|
||||
#define ___GFP_NOLOCKDEP 0
|
||||
#endif
|
||||
#ifdef CONFIG_SLAB_OBJ_EXT
|
||||
#define ___GFP_NO_OBJ_EXT BIT(___GFP_NO_OBJ_EXT_BIT)
|
||||
#else
|
||||
#define ___GFP_NO_OBJ_EXT 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Physical address zone modifiers (see linux/mmzone.h - low four bits)
|
||||
|
|
|
|||
|
|
@ -236,10 +236,8 @@ struct kmem_cache_order_objects {
|
|||
* Slab cache management.
|
||||
*/
|
||||
struct kmem_cache {
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
struct kmem_cache_cpu __percpu *cpu_slab;
|
||||
struct lock_class_key lock_key;
|
||||
#endif
|
||||
struct slub_percpu_sheaves __percpu *cpu_sheaves;
|
||||
/* Used for retrieving partial slabs, etc. */
|
||||
slab_flags_t flags;
|
||||
|
|
|
|||
331
mm/slub.c
331
mm/slub.c
|
|
@ -410,7 +410,6 @@ enum stat_item {
|
|||
NR_SLUB_STAT_ITEMS
|
||||
};
|
||||
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
/*
|
||||
* When changing the layout, make sure freelist and tid are still compatible
|
||||
* with this_cpu_cmpxchg_double() alignment requirements.
|
||||
|
|
@ -432,7 +431,6 @@ struct kmem_cache_cpu {
|
|||
unsigned int stat[NR_SLUB_STAT_ITEMS];
|
||||
#endif
|
||||
};
|
||||
#endif /* CONFIG_SLUB_TINY */
|
||||
|
||||
static inline void stat(const struct kmem_cache *s, enum stat_item si)
|
||||
{
|
||||
|
|
@ -469,7 +467,10 @@ struct slab_sheaf {
|
|||
struct rcu_head rcu_head;
|
||||
struct list_head barn_list;
|
||||
/* only used for prefilled sheafs */
|
||||
unsigned int capacity;
|
||||
struct {
|
||||
unsigned int capacity;
|
||||
bool pfmemalloc;
|
||||
};
|
||||
};
|
||||
struct kmem_cache *cache;
|
||||
unsigned int size;
|
||||
|
|
@ -594,12 +595,10 @@ static inline void *get_freepointer(struct kmem_cache *s, void *object)
|
|||
return freelist_ptr_decode(s, p, ptr_addr);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
static void prefetch_freepointer(const struct kmem_cache *s, void *object)
|
||||
{
|
||||
prefetchw(object + s->offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When running under KMSAN, get_freepointer_safe() may return an uninitialized
|
||||
|
|
@ -711,10 +710,12 @@ static inline unsigned int slub_get_cpu_partial(struct kmem_cache *s)
|
|||
return s->cpu_partial_slabs;
|
||||
}
|
||||
#else
|
||||
#ifdef SLAB_SUPPORTS_SYSFS
|
||||
static inline void
|
||||
slub_set_cpu_partial(struct kmem_cache *s, unsigned int nr_objects)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline unsigned int slub_get_cpu_partial(struct kmem_cache *s)
|
||||
{
|
||||
|
|
@ -2027,15 +2028,21 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node,
|
|||
int objects) {}
|
||||
static inline void dec_slabs_node(struct kmem_cache *s, int node,
|
||||
int objects) {}
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
static bool freelist_corrupted(struct kmem_cache *s, struct slab *slab,
|
||||
void **freelist, void *nextfree)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_SLUB_DEBUG */
|
||||
|
||||
/*
|
||||
* The allocated objcg pointers array is not accounted directly.
|
||||
* Moreover, it should not come from DMA buffer and is not readily
|
||||
* reclaimable. So those GFP bits should be masked off.
|
||||
*/
|
||||
#define OBJCGS_CLEAR_MASK (__GFP_DMA | __GFP_RECLAIMABLE | \
|
||||
__GFP_ACCOUNT | __GFP_NOFAIL)
|
||||
|
||||
#ifdef CONFIG_SLAB_OBJ_EXT
|
||||
|
||||
#ifdef CONFIG_MEM_ALLOC_PROFILING_DEBUG
|
||||
|
|
@ -2086,14 +2093,6 @@ static inline void handle_failed_objexts_alloc(unsigned long obj_exts,
|
|||
|
||||
#endif /* CONFIG_MEM_ALLOC_PROFILING_DEBUG */
|
||||
|
||||
/*
|
||||
* The allocated objcg pointers array is not accounted directly.
|
||||
* Moreover, it should not come from DMA buffer and is not readily
|
||||
* reclaimable. So those GFP bits should be masked off.
|
||||
*/
|
||||
#define OBJCGS_CLEAR_MASK (__GFP_DMA | __GFP_RECLAIMABLE | \
|
||||
__GFP_ACCOUNT | __GFP_NOFAIL)
|
||||
|
||||
static inline void init_slab_obj_exts(struct slab *slab)
|
||||
{
|
||||
slab->obj_exts = 0;
|
||||
|
|
@ -2601,8 +2600,24 @@ static void *setup_object(struct kmem_cache *s, void *object)
|
|||
|
||||
static struct slab_sheaf *alloc_empty_sheaf(struct kmem_cache *s, gfp_t gfp)
|
||||
{
|
||||
struct slab_sheaf *sheaf = kzalloc(struct_size(sheaf, objects,
|
||||
s->sheaf_capacity), gfp);
|
||||
struct slab_sheaf *sheaf;
|
||||
size_t sheaf_size;
|
||||
|
||||
if (gfp & __GFP_NO_OBJ_EXT)
|
||||
return NULL;
|
||||
|
||||
gfp &= ~OBJCGS_CLEAR_MASK;
|
||||
|
||||
/*
|
||||
* Prevent recursion to the same cache, or a deep stack of kmallocs of
|
||||
* varying sizes (sheaf capacity might differ for each kmalloc size
|
||||
* bucket)
|
||||
*/
|
||||
if (s->flags & SLAB_KMALLOC)
|
||||
gfp |= __GFP_NO_OBJ_EXT;
|
||||
|
||||
sheaf_size = struct_size(sheaf, objects, s->sheaf_capacity);
|
||||
sheaf = kzalloc(sheaf_size, gfp);
|
||||
|
||||
if (unlikely(!sheaf))
|
||||
return NULL;
|
||||
|
|
@ -2655,7 +2670,7 @@ static struct slab_sheaf *alloc_full_sheaf(struct kmem_cache *s, gfp_t gfp)
|
|||
if (!sheaf)
|
||||
return NULL;
|
||||
|
||||
if (refill_sheaf(s, sheaf, gfp)) {
|
||||
if (refill_sheaf(s, sheaf, gfp | __GFP_NOMEMALLOC)) {
|
||||
free_empty_sheaf(s, sheaf);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -2733,12 +2748,13 @@ static void sheaf_flush_unused(struct kmem_cache *s, struct slab_sheaf *sheaf)
|
|||
sheaf->size = 0;
|
||||
}
|
||||
|
||||
static void __rcu_free_sheaf_prepare(struct kmem_cache *s,
|
||||
static bool __rcu_free_sheaf_prepare(struct kmem_cache *s,
|
||||
struct slab_sheaf *sheaf)
|
||||
{
|
||||
bool init = slab_want_init_on_free(s);
|
||||
void **p = &sheaf->objects[0];
|
||||
unsigned int i = 0;
|
||||
bool pfmemalloc = false;
|
||||
|
||||
while (i < sheaf->size) {
|
||||
struct slab *slab = virt_to_slab(p[i]);
|
||||
|
|
@ -2751,8 +2767,13 @@ static void __rcu_free_sheaf_prepare(struct kmem_cache *s,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (slab_test_pfmemalloc(slab))
|
||||
pfmemalloc = true;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return pfmemalloc;
|
||||
}
|
||||
|
||||
static void rcu_free_sheaf_nobarn(struct rcu_head *head)
|
||||
|
|
@ -3015,14 +3036,11 @@ static void barn_init(struct node_barn *barn)
|
|||
|
||||
static void barn_shrink(struct kmem_cache *s, struct node_barn *barn)
|
||||
{
|
||||
struct list_head empty_list;
|
||||
struct list_head full_list;
|
||||
LIST_HEAD(empty_list);
|
||||
LIST_HEAD(full_list);
|
||||
struct slab_sheaf *sheaf, *sheaf2;
|
||||
unsigned long flags;
|
||||
|
||||
INIT_LIST_HEAD(&empty_list);
|
||||
INIT_LIST_HEAD(&full_list);
|
||||
|
||||
spin_lock_irqsave(&barn->lock, flags);
|
||||
|
||||
list_splice_init(&barn->sheaves_full, &full_list);
|
||||
|
|
@ -3618,8 +3636,6 @@ static struct slab *get_partial(struct kmem_cache *s, int node,
|
|||
return get_any_partial(s, pc);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
|
||||
#ifdef CONFIG_PREEMPTION
|
||||
/*
|
||||
* Calculate the next globally unique transaction for disambiguation
|
||||
|
|
@ -4019,12 +4035,6 @@ static bool has_cpu_slab(int cpu, struct kmem_cache *s)
|
|||
return c->slab || slub_percpu_partial(c);
|
||||
}
|
||||
|
||||
#else /* CONFIG_SLUB_TINY */
|
||||
static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu) { }
|
||||
static inline bool has_cpu_slab(int cpu, struct kmem_cache *s) { return false; }
|
||||
static inline void flush_this_cpu_slab(struct kmem_cache *s) { }
|
||||
#endif /* CONFIG_SLUB_TINY */
|
||||
|
||||
static bool has_pcs_used(int cpu, struct kmem_cache *s)
|
||||
{
|
||||
struct slub_percpu_sheaves *pcs;
|
||||
|
|
@ -4365,7 +4375,6 @@ static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags)
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
static inline bool
|
||||
__update_cpu_freelist_fast(struct kmem_cache *s,
|
||||
void *freelist_old, void *freelist_new,
|
||||
|
|
@ -4629,7 +4638,7 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
|
|||
pc.orig_size = orig_size;
|
||||
slab = get_partial(s, node, &pc);
|
||||
if (slab) {
|
||||
if (kmem_cache_debug(s)) {
|
||||
if (IS_ENABLED(CONFIG_SLUB_TINY) || kmem_cache_debug(s)) {
|
||||
freelist = pc.object;
|
||||
/*
|
||||
* For debug caches here we had to go through
|
||||
|
|
@ -4667,11 +4676,15 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
|
|||
|
||||
stat(s, ALLOC_SLAB);
|
||||
|
||||
if (kmem_cache_debug(s)) {
|
||||
if (IS_ENABLED(CONFIG_SLUB_TINY) || kmem_cache_debug(s)) {
|
||||
freelist = alloc_single_from_new_slab(s, slab, orig_size, gfpflags);
|
||||
|
||||
if (unlikely(!freelist))
|
||||
if (unlikely(!freelist)) {
|
||||
/* This could cause an endless loop. Fail instead. */
|
||||
if (!allow_spin)
|
||||
return NULL;
|
||||
goto new_objects;
|
||||
}
|
||||
|
||||
if (s->flags & SLAB_STORE_USER)
|
||||
set_track(s, freelist, TRACK_ALLOC, addr,
|
||||
|
|
@ -4875,32 +4888,6 @@ static __always_inline void *__slab_alloc_node(struct kmem_cache *s,
|
|||
|
||||
return object;
|
||||
}
|
||||
#else /* CONFIG_SLUB_TINY */
|
||||
static void *__slab_alloc_node(struct kmem_cache *s,
|
||||
gfp_t gfpflags, int node, unsigned long addr, size_t orig_size)
|
||||
{
|
||||
struct partial_context pc;
|
||||
struct slab *slab;
|
||||
void *object;
|
||||
|
||||
pc.flags = gfpflags;
|
||||
pc.orig_size = orig_size;
|
||||
slab = get_partial(s, node, &pc);
|
||||
|
||||
if (slab)
|
||||
return pc.object;
|
||||
|
||||
slab = new_slab(s, gfpflags, node);
|
||||
if (unlikely(!slab)) {
|
||||
slab_out_of_memory(s, gfpflags, node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
object = alloc_single_from_new_slab(s, slab, orig_size, gfpflags);
|
||||
|
||||
return object;
|
||||
}
|
||||
#endif /* CONFIG_SLUB_TINY */
|
||||
|
||||
/*
|
||||
* If the object has been wiped upon free, make sure it's fully initialized by
|
||||
|
|
@ -5041,7 +5028,7 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,
|
|||
return NULL;
|
||||
|
||||
if (empty) {
|
||||
if (!refill_sheaf(s, empty, gfp)) {
|
||||
if (!refill_sheaf(s, empty, gfp | __GFP_NOMEMALLOC)) {
|
||||
full = empty;
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -5341,6 +5328,26 @@ void *kmem_cache_alloc_node_noprof(struct kmem_cache *s, gfp_t gfpflags, int nod
|
|||
}
|
||||
EXPORT_SYMBOL(kmem_cache_alloc_node_noprof);
|
||||
|
||||
static int __prefill_sheaf_pfmemalloc(struct kmem_cache *s,
|
||||
struct slab_sheaf *sheaf, gfp_t gfp)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = refill_sheaf(s, sheaf, gfp | __GFP_NOMEMALLOC);
|
||||
|
||||
if (likely(!ret || !gfp_pfmemalloc_allowed(gfp)))
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* if we are allowed to, refill sheaf with pfmemalloc but then remember
|
||||
* it for when it's returned
|
||||
*/
|
||||
ret = refill_sheaf(s, sheaf, gfp);
|
||||
sheaf->pfmemalloc = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns a sheaf that has at least the requested size
|
||||
* when prefilling is needed, do so with given gfp flags
|
||||
|
|
@ -5375,6 +5382,10 @@ kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size)
|
|||
sheaf->cache = s;
|
||||
sheaf->capacity = size;
|
||||
|
||||
/*
|
||||
* we do not need to care about pfmemalloc here because oversize
|
||||
* sheaves area always flushed and freed when returned
|
||||
*/
|
||||
if (!__kmem_cache_alloc_bulk(s, gfp, size,
|
||||
&sheaf->objects[0])) {
|
||||
kfree(sheaf);
|
||||
|
|
@ -5411,17 +5422,18 @@ kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size)
|
|||
if (!sheaf)
|
||||
sheaf = alloc_empty_sheaf(s, gfp);
|
||||
|
||||
if (sheaf && sheaf->size < size) {
|
||||
if (refill_sheaf(s, sheaf, gfp)) {
|
||||
if (sheaf) {
|
||||
sheaf->capacity = s->sheaf_capacity;
|
||||
sheaf->pfmemalloc = false;
|
||||
|
||||
if (sheaf->size < size &&
|
||||
__prefill_sheaf_pfmemalloc(s, sheaf, gfp)) {
|
||||
sheaf_flush_unused(s, sheaf);
|
||||
free_empty_sheaf(s, sheaf);
|
||||
sheaf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (sheaf)
|
||||
sheaf->capacity = s->sheaf_capacity;
|
||||
|
||||
return sheaf;
|
||||
}
|
||||
|
||||
|
|
@ -5441,7 +5453,8 @@ void kmem_cache_return_sheaf(struct kmem_cache *s, gfp_t gfp,
|
|||
struct slub_percpu_sheaves *pcs;
|
||||
struct node_barn *barn;
|
||||
|
||||
if (unlikely(sheaf->capacity != s->sheaf_capacity)) {
|
||||
if (unlikely((sheaf->capacity != s->sheaf_capacity)
|
||||
|| sheaf->pfmemalloc)) {
|
||||
sheaf_flush_unused(s, sheaf);
|
||||
kfree(sheaf);
|
||||
return;
|
||||
|
|
@ -5507,7 +5520,7 @@ int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp,
|
|||
|
||||
if (likely(sheaf->capacity >= size)) {
|
||||
if (likely(sheaf->capacity == s->sheaf_capacity))
|
||||
return refill_sheaf(s, sheaf, gfp);
|
||||
return __prefill_sheaf_pfmemalloc(s, sheaf, gfp);
|
||||
|
||||
if (!__kmem_cache_alloc_bulk(s, gfp, sheaf->capacity - sheaf->size,
|
||||
&sheaf->objects[sheaf->size])) {
|
||||
|
|
@ -5540,6 +5553,9 @@ int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp,
|
|||
*
|
||||
* The gfp parameter is meant only to specify __GFP_ZERO or __GFP_ACCOUNT
|
||||
* memcg charging is forced over limit if necessary, to avoid failure.
|
||||
*
|
||||
* It is possible that the allocation comes from kfence and then the sheaf
|
||||
* size is not decreased.
|
||||
*/
|
||||
void *
|
||||
kmem_cache_alloc_from_sheaf_noprof(struct kmem_cache *s, gfp_t gfp,
|
||||
|
|
@ -5551,7 +5567,10 @@ kmem_cache_alloc_from_sheaf_noprof(struct kmem_cache *s, gfp_t gfp,
|
|||
if (sheaf->size == 0)
|
||||
goto out;
|
||||
|
||||
ret = sheaf->objects[--sheaf->size];
|
||||
ret = kfence_alloc(s, s->object_size, gfp);
|
||||
|
||||
if (likely(!ret))
|
||||
ret = sheaf->objects[--sheaf->size];
|
||||
|
||||
init = slab_want_init_on_alloc(gfp, s);
|
||||
|
||||
|
|
@ -5719,9 +5738,7 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node)
|
|||
* it did local_lock_irqsave(&s->cpu_slab->lock, flags).
|
||||
* In this case fast path with __update_cpu_freelist_fast() is not safe.
|
||||
*/
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
if (!in_nmi() || !local_lock_is_locked(&s->cpu_slab->lock))
|
||||
#endif
|
||||
ret = __slab_alloc_node(s, alloc_gfp, node, _RET_IP_, size);
|
||||
|
||||
if (PTR_ERR(ret) == -EBUSY) {
|
||||
|
|
@ -5859,8 +5876,8 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab,
|
|||
unsigned long addr)
|
||||
|
||||
{
|
||||
void *prior;
|
||||
int was_frozen;
|
||||
void *old_head;
|
||||
bool was_frozen, was_full;
|
||||
struct slab new;
|
||||
unsigned long counters;
|
||||
struct kmem_cache_node *n = NULL;
|
||||
|
|
@ -5874,20 +5891,37 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab,
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is enough to test IS_ENABLED(CONFIG_SLUB_CPU_PARTIAL) below
|
||||
* instead of kmem_cache_has_cpu_partial(s), because kmem_cache_debug(s)
|
||||
* is the only other reason it can be false, and it is already handled
|
||||
* above.
|
||||
*/
|
||||
|
||||
do {
|
||||
if (unlikely(n)) {
|
||||
spin_unlock_irqrestore(&n->list_lock, flags);
|
||||
n = NULL;
|
||||
}
|
||||
prior = slab->freelist;
|
||||
old_head = slab->freelist;
|
||||
counters = slab->counters;
|
||||
set_freepointer(s, tail, prior);
|
||||
set_freepointer(s, tail, old_head);
|
||||
new.counters = counters;
|
||||
was_frozen = new.frozen;
|
||||
was_frozen = !!new.frozen;
|
||||
was_full = (old_head == NULL);
|
||||
new.inuse -= cnt;
|
||||
if ((!new.inuse || !prior) && !was_frozen) {
|
||||
/* Needs to be taken off a list */
|
||||
if (!kmem_cache_has_cpu_partial(s) || prior) {
|
||||
/*
|
||||
* Might need to be taken off (due to becoming empty) or added
|
||||
* to (due to not being full anymore) the partial list.
|
||||
* Unless it's frozen.
|
||||
*/
|
||||
if ((!new.inuse || was_full) && !was_frozen) {
|
||||
/*
|
||||
* If slab becomes non-full and we have cpu partial
|
||||
* lists, we put it there unconditionally to avoid
|
||||
* taking the list_lock. Otherwise we need it.
|
||||
*/
|
||||
if (!(IS_ENABLED(CONFIG_SLUB_CPU_PARTIAL) && was_full)) {
|
||||
|
||||
n = get_node(s, slab_nid(slab));
|
||||
/*
|
||||
|
|
@ -5905,7 +5939,7 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab,
|
|||
}
|
||||
|
||||
} while (!slab_update_freelist(s, slab,
|
||||
prior, counters,
|
||||
old_head, counters,
|
||||
head, new.counters,
|
||||
"__slab_free"));
|
||||
|
||||
|
|
@ -5917,7 +5951,7 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab,
|
|||
* activity can be necessary.
|
||||
*/
|
||||
stat(s, FREE_FROZEN);
|
||||
} else if (kmem_cache_has_cpu_partial(s) && !prior) {
|
||||
} else if (IS_ENABLED(CONFIG_SLUB_CPU_PARTIAL) && was_full) {
|
||||
/*
|
||||
* If we started with a full slab then put it onto the
|
||||
* per cpu partial list.
|
||||
|
|
@ -5926,6 +5960,11 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab,
|
|||
stat(s, CPU_PARTIAL_FREE);
|
||||
}
|
||||
|
||||
/*
|
||||
* In other cases we didn't take the list_lock because the slab
|
||||
* was already on the partial list and will remain there.
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -5933,19 +5972,24 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab,
|
|||
* This slab was partially empty but not on the per-node partial list,
|
||||
* in which case we shouldn't manipulate its list, just return.
|
||||
*/
|
||||
if (prior && !on_node_partial) {
|
||||
if (!was_full && !on_node_partial) {
|
||||
spin_unlock_irqrestore(&n->list_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If slab became empty, should we add/keep it on the partial list or we
|
||||
* have enough?
|
||||
*/
|
||||
if (unlikely(!new.inuse && n->nr_partial >= s->min_partial))
|
||||
goto slab_empty;
|
||||
|
||||
/*
|
||||
* Objects left in the slab. If it was not on the partial list before
|
||||
* then add it.
|
||||
* then add it. This can only happen when cache has no per cpu partial
|
||||
* list otherwise we would have put it there.
|
||||
*/
|
||||
if (!kmem_cache_has_cpu_partial(s) && unlikely(!prior)) {
|
||||
if (!IS_ENABLED(CONFIG_SLUB_CPU_PARTIAL) && unlikely(was_full)) {
|
||||
add_partial(n, slab, DEACTIVATE_TO_TAIL);
|
||||
stat(s, FREE_ADD_PARTIAL);
|
||||
}
|
||||
|
|
@ -5953,10 +5997,11 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab,
|
|||
return;
|
||||
|
||||
slab_empty:
|
||||
if (prior) {
|
||||
/*
|
||||
* Slab on the partial list.
|
||||
*/
|
||||
/*
|
||||
* The slab could have a single object and thus go from full to empty in
|
||||
* a single free, but more likely it was on the partial list. Remove it.
|
||||
*/
|
||||
if (likely(!was_full)) {
|
||||
remove_partial(n, slab);
|
||||
stat(s, FREE_REMOVE_PARTIAL);
|
||||
}
|
||||
|
|
@ -6181,8 +6226,12 @@ static void rcu_free_sheaf(struct rcu_head *head)
|
|||
* handles it fine. The only downside is that sheaf will serve fewer
|
||||
* allocations when reused. It only happens due to debugging, which is a
|
||||
* performance hit anyway.
|
||||
*
|
||||
* If it returns true, there was at least one object from pfmemalloc
|
||||
* slab so simply flush everything.
|
||||
*/
|
||||
__rcu_free_sheaf_prepare(s, sheaf);
|
||||
if (__rcu_free_sheaf_prepare(s, sheaf))
|
||||
goto flush;
|
||||
|
||||
n = get_node(s, sheaf->node);
|
||||
if (!n)
|
||||
|
|
@ -6337,7 +6386,8 @@ static void free_to_pcs_bulk(struct kmem_cache *s, size_t size, void **p)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (unlikely(IS_ENABLED(CONFIG_NUMA) && slab_nid(slab) != node)) {
|
||||
if (unlikely((IS_ENABLED(CONFIG_NUMA) && slab_nid(slab) != node)
|
||||
|| slab_test_pfmemalloc(slab))) {
|
||||
remote_objects[remote_nr] = p[i];
|
||||
p[i] = p[--size];
|
||||
if (++remote_nr >= PCS_BATCH_MAX)
|
||||
|
|
@ -6479,14 +6529,10 @@ static void free_deferred_objects(struct irq_work *work)
|
|||
llist_for_each_safe(pos, t, llnode) {
|
||||
struct slab *slab = container_of(pos, struct slab, llnode);
|
||||
|
||||
#ifdef CONFIG_SLUB_TINY
|
||||
free_slab(slab->slab_cache, slab);
|
||||
#else
|
||||
if (slab->frozen)
|
||||
deactivate_slab(slab->slab_cache, slab, slab->flush_freelist);
|
||||
else
|
||||
free_slab(slab->slab_cache, slab);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6522,7 +6568,6 @@ void defer_free_barrier(void)
|
|||
irq_work_sync(&per_cpu_ptr(&defer_free_objects, cpu)->work);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
/*
|
||||
* Fastpath with forced inlining to produce a kfree and kmem_cache_free that
|
||||
* can perform fastpath freeing without additional function calls.
|
||||
|
|
@ -6615,14 +6660,6 @@ static __always_inline void do_slab_free(struct kmem_cache *s,
|
|||
}
|
||||
stat_add(s, FREE_FASTPATH, cnt);
|
||||
}
|
||||
#else /* CONFIG_SLUB_TINY */
|
||||
static void do_slab_free(struct kmem_cache *s,
|
||||
struct slab *slab, void *head, void *tail,
|
||||
int cnt, unsigned long addr)
|
||||
{
|
||||
__slab_free(s, slab, head, tail, cnt, addr);
|
||||
}
|
||||
#endif /* CONFIG_SLUB_TINY */
|
||||
|
||||
static __fastpath_inline
|
||||
void slab_free(struct kmem_cache *s, struct slab *slab, void *object,
|
||||
|
|
@ -6635,7 +6672,8 @@ void slab_free(struct kmem_cache *s, struct slab *slab, void *object,
|
|||
return;
|
||||
|
||||
if (s->cpu_sheaves && likely(!IS_ENABLED(CONFIG_NUMA) ||
|
||||
slab_nid(slab) == numa_mem_id())) {
|
||||
slab_nid(slab) == numa_mem_id())
|
||||
&& likely(!slab_test_pfmemalloc(slab))) {
|
||||
if (likely(free_to_pcs(s, object)))
|
||||
return;
|
||||
}
|
||||
|
|
@ -6899,11 +6937,7 @@ void kfree_nolock(const void *object)
|
|||
* since kasan quarantine takes locks and not supported from NMI.
|
||||
*/
|
||||
kasan_slab_free(s, x, false, false, /* skip quarantine */true);
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
do_slab_free(s, slab, x, x, 0, _RET_IP_);
|
||||
#else
|
||||
defer_free(s, x);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kfree_nolock);
|
||||
|
||||
|
|
@ -7353,7 +7387,6 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
|
|||
}
|
||||
EXPORT_SYMBOL(kmem_cache_free_bulk);
|
||||
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
static inline
|
||||
int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
|
||||
void **p)
|
||||
|
|
@ -7371,14 +7404,8 @@ int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
|
|||
local_lock_irqsave(&s->cpu_slab->lock, irqflags);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
void *object = kfence_alloc(s, s->object_size, flags);
|
||||
void *object = c->freelist;
|
||||
|
||||
if (unlikely(object)) {
|
||||
p[i] = object;
|
||||
continue;
|
||||
}
|
||||
|
||||
object = c->freelist;
|
||||
if (unlikely(!object)) {
|
||||
/*
|
||||
* We may have removed an object from c->freelist using
|
||||
|
|
@ -7424,41 +7451,13 @@ int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
|
|||
return 0;
|
||||
|
||||
}
|
||||
#else /* CONFIG_SLUB_TINY */
|
||||
static int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags,
|
||||
size_t size, void **p)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
void *object = kfence_alloc(s, s->object_size, flags);
|
||||
|
||||
if (unlikely(object)) {
|
||||
p[i] = object;
|
||||
continue;
|
||||
}
|
||||
|
||||
p[i] = __slab_alloc_node(s, flags, NUMA_NO_NODE,
|
||||
_RET_IP_, s->object_size);
|
||||
if (unlikely(!p[i]))
|
||||
goto error;
|
||||
|
||||
maybe_wipe_obj_freeptr(s, p[i]);
|
||||
}
|
||||
|
||||
return i;
|
||||
|
||||
error:
|
||||
__kmem_cache_free_bulk(s, i, p);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SLUB_TINY */
|
||||
|
||||
/* Note that interrupts must be enabled when calling this function. */
|
||||
int kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, size_t size,
|
||||
void **p)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
void *kfence_obj;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
|
@ -7467,6 +7466,20 @@ int kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, size_t size,
|
|||
if (unlikely(!s))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* to make things simpler, only assume at most once kfence allocated
|
||||
* object per bulk allocation and choose its index randomly
|
||||
*/
|
||||
kfence_obj = kfence_alloc(s, s->object_size, flags);
|
||||
|
||||
if (unlikely(kfence_obj)) {
|
||||
if (unlikely(size == 1)) {
|
||||
p[0] = kfence_obj;
|
||||
goto out;
|
||||
}
|
||||
size--;
|
||||
}
|
||||
|
||||
if (s->cpu_sheaves)
|
||||
i = alloc_from_pcs_bulk(s, size, p);
|
||||
|
||||
|
|
@ -7478,10 +7491,23 @@ int kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, size_t size,
|
|||
if (unlikely(__kmem_cache_alloc_bulk(s, flags, size - i, p + i) == 0)) {
|
||||
if (i > 0)
|
||||
__kmem_cache_free_bulk(s, i, p);
|
||||
if (kfence_obj)
|
||||
__kfence_free(kfence_obj);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(kfence_obj)) {
|
||||
int idx = get_random_u32_below(size + 1);
|
||||
|
||||
if (idx != size)
|
||||
p[size] = p[idx];
|
||||
p[idx] = kfence_obj;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* memcg and kmem_cache debug support and memory initialization.
|
||||
* Done outside of the IRQ disabled fastpath loop.
|
||||
|
|
@ -7643,7 +7669,6 @@ init_kmem_cache_node(struct kmem_cache_node *n, struct node_barn *barn)
|
|||
barn_init(barn);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
|
||||
{
|
||||
BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
|
||||
|
|
@ -7664,12 +7689,6 @@ static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
|
|||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif /* CONFIG_SLUB_TINY */
|
||||
|
||||
static int init_percpu_sheaves(struct kmem_cache *s)
|
||||
{
|
||||
|
|
@ -7759,13 +7778,11 @@ void __kmem_cache_release(struct kmem_cache *s)
|
|||
cache_random_seq_destroy(s);
|
||||
if (s->cpu_sheaves)
|
||||
pcs_destroy(s);
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
#ifdef CONFIG_PREEMPT_RT
|
||||
if (s->cpu_slab)
|
||||
lockdep_unregister_key(&s->lock_key);
|
||||
#endif
|
||||
free_percpu(s->cpu_slab);
|
||||
#endif
|
||||
free_kmem_cache_nodes(s);
|
||||
}
|
||||
|
||||
|
|
@ -8519,10 +8536,8 @@ void __init kmem_cache_init(void)
|
|||
|
||||
void __init kmem_cache_init_late(void)
|
||||
{
|
||||
#ifndef CONFIG_SLUB_TINY
|
||||
flushwq = alloc_workqueue("slub_flushwq", WQ_MEM_RECLAIM, 0);
|
||||
WARN_ON(!flushwq);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct kmem_cache *
|
||||
|
|
|
|||
Loading…
Reference in New Issue