mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
Merge branch 'slab/for-7.0/sheaves' into slab/for-next
Merge series "slab: replace cpu (partial) slabs with sheaves". The percpu sheaves caching layer was introduced as opt-in but the goal was to eventually move all caches to them. This is the next step, enabling sheaves for all caches (except the two bootstrap ones) and then removing the per cpu (partial) slabs and lots of associated code. Besides the lower locking overhead and much more likely fastpath when freeing, this removes the rather complicated code related to the cpu slab lockless fastpaths (using this_cpu_try_cmpxchg128/64) and all its complications for PREEMPT_RT or kmalloc_nolock(). The lockless slab freelist+counters update operation using try_cmpxchg128/64 remains and is crucial for freeing remote NUMA objects and to allow flushing objects from sheaves to slabs mostly without the node list_lock. Link: https://lore.kernel.org/all/20260123-sheaves-for-all-v4-0-041323d506f7@suse.cz/
This commit is contained in:
commit
815c8e3551
7 changed files with 997 additions and 1786 deletions
|
|
@ -57,9 +57,7 @@ enum _slab_flag_bits {
|
|||
#endif
|
||||
_SLAB_OBJECT_POISON,
|
||||
_SLAB_CMPXCHG_DOUBLE,
|
||||
#ifdef CONFIG_SLAB_OBJ_EXT
|
||||
_SLAB_NO_OBJ_EXT,
|
||||
#endif
|
||||
#if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
|
||||
_SLAB_OBJ_EXT_IN_OBJ,
|
||||
#endif
|
||||
|
|
@ -241,11 +239,7 @@ enum _slab_flag_bits {
|
|||
#define SLAB_TEMPORARY SLAB_RECLAIM_ACCOUNT /* Objects are short-lived */
|
||||
|
||||
/* Slab created using create_boot_cache */
|
||||
#ifdef CONFIG_SLAB_OBJ_EXT
|
||||
#define SLAB_NO_OBJ_EXT __SLAB_FLAG_BIT(_SLAB_NO_OBJ_EXT)
|
||||
#else
|
||||
#define SLAB_NO_OBJ_EXT __SLAB_FLAG_UNUSED
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SLAB_OBJ_EXT) && defined(CONFIG_64BIT)
|
||||
#define SLAB_OBJ_EXT_IN_OBJ __SLAB_FLAG_BIT(_SLAB_OBJ_EXT_IN_OBJ)
|
||||
|
|
|
|||
11
mm/Kconfig
11
mm/Kconfig
|
|
@ -247,17 +247,6 @@ config SLUB_STATS
|
|||
out which slabs are relevant to a particular load.
|
||||
Try running: slabinfo -DA
|
||||
|
||||
config SLUB_CPU_PARTIAL
|
||||
default y
|
||||
depends on SMP && !SLUB_TINY
|
||||
bool "Enable per cpu partial caches"
|
||||
help
|
||||
Per cpu partial caches accelerate objects allocation and freeing
|
||||
that is local to a processor at the price of more indeterminism
|
||||
in the latency of the free. On overflow these caches will be cleared
|
||||
which requires the taking of locks that may cause latency spikes.
|
||||
Typically one would choose no for a realtime system.
|
||||
|
||||
config RANDOM_KMALLOC_CACHES
|
||||
default n
|
||||
depends on !SLUB_TINY
|
||||
|
|
|
|||
|
|
@ -846,6 +846,7 @@ static inline struct page *alloc_frozen_pages_noprof(gfp_t gfp, unsigned int ord
|
|||
struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned int order);
|
||||
#define alloc_frozen_pages_nolock(...) \
|
||||
alloc_hooks(alloc_frozen_pages_nolock_noprof(__VA_ARGS__))
|
||||
void free_frozen_pages_nolock(struct page *page, unsigned int order);
|
||||
|
||||
extern void zone_pcp_reset(struct zone *zone);
|
||||
extern void zone_pcp_disable(struct zone *zone);
|
||||
|
|
|
|||
|
|
@ -2981,6 +2981,11 @@ void free_frozen_pages(struct page *page, unsigned int order)
|
|||
__free_frozen_pages(page, order, FPI_NONE);
|
||||
}
|
||||
|
||||
void free_frozen_pages_nolock(struct page *page, unsigned int order)
|
||||
{
|
||||
__free_frozen_pages(page, order, FPI_TRYLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a batch of folios
|
||||
*/
|
||||
|
|
|
|||
57
mm/slab.h
57
mm/slab.h
|
|
@ -21,14 +21,12 @@
|
|||
# define system_has_freelist_aba() system_has_cmpxchg128()
|
||||
# define try_cmpxchg_freelist try_cmpxchg128
|
||||
# endif
|
||||
#define this_cpu_try_cmpxchg_freelist this_cpu_try_cmpxchg128
|
||||
typedef u128 freelist_full_t;
|
||||
#else /* CONFIG_64BIT */
|
||||
# ifdef system_has_cmpxchg64
|
||||
# define system_has_freelist_aba() system_has_cmpxchg64()
|
||||
# define try_cmpxchg_freelist try_cmpxchg64
|
||||
# endif
|
||||
#define this_cpu_try_cmpxchg_freelist this_cpu_try_cmpxchg64
|
||||
typedef u64 freelist_full_t;
|
||||
#endif /* CONFIG_64BIT */
|
||||
|
||||
|
|
@ -79,19 +77,7 @@ struct slab {
|
|||
struct kmem_cache *slab_cache;
|
||||
union {
|
||||
struct {
|
||||
union {
|
||||
struct list_head slab_list;
|
||||
struct { /* For deferred deactivate_slab() */
|
||||
struct llist_node llnode;
|
||||
void *flush_freelist;
|
||||
};
|
||||
#ifdef CONFIG_SLUB_CPU_PARTIAL
|
||||
struct {
|
||||
struct slab *next;
|
||||
int slabs; /* Nr of slabs left */
|
||||
};
|
||||
#endif
|
||||
};
|
||||
struct list_head slab_list;
|
||||
/* Double-word boundary */
|
||||
struct freelist_counters;
|
||||
};
|
||||
|
|
@ -196,23 +182,6 @@ static inline size_t slab_size(const struct slab *slab)
|
|||
return PAGE_SIZE << slab_order(slab);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SLUB_CPU_PARTIAL
|
||||
#define slub_percpu_partial(c) ((c)->partial)
|
||||
|
||||
#define slub_set_percpu_partial(c, p) \
|
||||
({ \
|
||||
slub_percpu_partial(c) = (p)->next; \
|
||||
})
|
||||
|
||||
#define slub_percpu_partial_read_once(c) READ_ONCE(slub_percpu_partial(c))
|
||||
#else
|
||||
#define slub_percpu_partial(c) NULL
|
||||
|
||||
#define slub_set_percpu_partial(c, p)
|
||||
|
||||
#define slub_percpu_partial_read_once(c) NULL
|
||||
#endif // CONFIG_SLUB_CPU_PARTIAL
|
||||
|
||||
/*
|
||||
* Word size structure that can be atomically updated or read and that
|
||||
* contains both the order and the number of objects that a slab of the
|
||||
|
|
@ -226,8 +195,6 @@ struct kmem_cache_order_objects {
|
|||
* Slab cache management.
|
||||
*/
|
||||
struct kmem_cache {
|
||||
struct kmem_cache_cpu __percpu *cpu_slab;
|
||||
struct lock_class_key lock_key;
|
||||
struct slub_percpu_sheaves __percpu *cpu_sheaves;
|
||||
/* Used for retrieving partial slabs, etc. */
|
||||
slab_flags_t flags;
|
||||
|
|
@ -236,12 +203,6 @@ struct kmem_cache {
|
|||
unsigned int object_size; /* Object size without metadata */
|
||||
struct reciprocal_value reciprocal_size;
|
||||
unsigned int offset; /* Free pointer offset */
|
||||
#ifdef CONFIG_SLUB_CPU_PARTIAL
|
||||
/* Number of per cpu partial objects to keep around */
|
||||
unsigned int cpu_partial;
|
||||
/* Number of per cpu partial slabs to keep around */
|
||||
unsigned int cpu_partial_slabs;
|
||||
#endif
|
||||
unsigned int sheaf_capacity;
|
||||
struct kmem_cache_order_objects oo;
|
||||
|
||||
|
|
@ -282,9 +243,25 @@ struct kmem_cache {
|
|||
unsigned int usersize; /* Usercopy region size */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SLUB_STATS
|
||||
struct kmem_cache_stats __percpu *cpu_stats;
|
||||
#endif
|
||||
|
||||
struct kmem_cache_node *node[MAX_NUMNODES];
|
||||
};
|
||||
|
||||
/*
|
||||
* Every cache has !NULL s->cpu_sheaves but they may point to the
|
||||
* bootstrap_sheaf temporarily during init, or permanently for the boot caches
|
||||
* and caches with debugging enabled, or all caches with CONFIG_SLUB_TINY. This
|
||||
* helper distinguishes whether cache has real non-bootstrap sheaves.
|
||||
*/
|
||||
static inline bool cache_has_sheaves(struct kmem_cache *s)
|
||||
{
|
||||
/* Test CONFIG_SLUB_TINY for code elimination purposes */
|
||||
return !IS_ENABLED(CONFIG_SLUB_TINY) && s->sheaf_capacity;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SYSFS) && !defined(CONFIG_SLUB_TINY)
|
||||
#define SLAB_SUPPORTS_SYSFS 1
|
||||
void sysfs_slab_unlink(struct kmem_cache *s);
|
||||
|
|
|
|||
|
|
@ -1604,11 +1604,8 @@ static bool kfree_rcu_sheaf(void *obj)
|
|||
return false;
|
||||
|
||||
s = slab->slab_cache;
|
||||
if (s->cpu_sheaves) {
|
||||
if (likely(!IS_ENABLED(CONFIG_NUMA) ||
|
||||
slab_nid(slab) == numa_mem_id()))
|
||||
return __kfree_rcu_sheaf(s, obj);
|
||||
}
|
||||
if (likely(!IS_ENABLED(CONFIG_NUMA) || slab_nid(slab) == numa_mem_id()))
|
||||
return __kfree_rcu_sheaf(s, obj);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2112,7 +2109,7 @@ EXPORT_SYMBOL_GPL(kvfree_rcu_barrier);
|
|||
*/
|
||||
void kvfree_rcu_barrier_on_cache(struct kmem_cache *s)
|
||||
{
|
||||
if (s->cpu_sheaves) {
|
||||
if (cache_has_sheaves(s)) {
|
||||
flush_rcu_sheaves_on_cache(s);
|
||||
rcu_barrier();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue