Merge branch 'slub-tiny-v1r6' into slab/for-next
Merge my series [1] to deprecate the SLOB allocator. - Renames CONFIG_SLOB to CONFIG_SLOB_DEPRECATED with deprecation notice. - The recommended replacement is CONFIG_SLUB, optionally with the new CONFIG_SLUB_TINY tweaks for systems with 16MB or less RAM. - Use cases that stopped working with CONFIG_SLUB_TINY instead of SLOB should be reported to linux-mm@kvack.org and slab maintainers, otherwise SLOB will be removed in few cycles. [1] https://lore.kernel.org/all/20221121171202.22080-1-vbabka@suse.cz/
This commit is contained in:
Коммит
dc19745ad0
|
@ -14,7 +14,8 @@ CONFIG_ARCH_EDB7211=y
|
||||||
CONFIG_ARCH_P720T=y
|
CONFIG_ARCH_P720T=y
|
||||||
CONFIG_AEABI=y
|
CONFIG_AEABI=y
|
||||||
# CONFIG_COREDUMP is not set
|
# CONFIG_COREDUMP is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
CONFIG_PACKET=y
|
CONFIG_PACKET=y
|
||||||
CONFIG_UNIX=y
|
CONFIG_UNIX=y
|
||||||
|
|
|
@ -13,7 +13,8 @@ CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2 fbcon=rotate:1"
|
||||||
CONFIG_FPE_NWFPE=y
|
CONFIG_FPE_NWFPE=y
|
||||||
CONFIG_PM=y
|
CONFIG_PM=y
|
||||||
# CONFIG_SWAP is not set
|
# CONFIG_SWAP is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
CONFIG_PACKET=y
|
CONFIG_PACKET=y
|
||||||
CONFIG_UNIX=y
|
CONFIG_UNIX=y
|
||||||
|
|
|
@ -25,7 +25,8 @@ CONFIG_ARM_CLPS711X_CPUIDLE=y
|
||||||
CONFIG_JUMP_LABEL=y
|
CONFIG_JUMP_LABEL=y
|
||||||
CONFIG_PARTITION_ADVANCED=y
|
CONFIG_PARTITION_ADVANCED=y
|
||||||
# CONFIG_COREDUMP is not set
|
# CONFIG_COREDUMP is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_MTD=y
|
CONFIG_MTD=y
|
||||||
CONFIG_MTD_CMDLINE_PARTS=y
|
CONFIG_MTD_CMDLINE_PARTS=y
|
||||||
CONFIG_MTD_BLOCK=y
|
CONFIG_MTD_BLOCK=y
|
||||||
|
|
|
@ -42,7 +42,8 @@ CONFIG_MODULE_FORCE_UNLOAD=y
|
||||||
CONFIG_PARTITION_ADVANCED=y
|
CONFIG_PARTITION_ADVANCED=y
|
||||||
CONFIG_BINFMT_MISC=y
|
CONFIG_BINFMT_MISC=y
|
||||||
# CONFIG_SWAP is not set
|
# CONFIG_SWAP is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
CONFIG_PACKET=y
|
CONFIG_PACKET=y
|
||||||
|
|
|
@ -49,7 +49,8 @@ CONFIG_PARTITION_ADVANCED=y
|
||||||
CONFIG_LDM_PARTITION=y
|
CONFIG_LDM_PARTITION=y
|
||||||
CONFIG_CMDLINE_PARTITION=y
|
CONFIG_CMDLINE_PARTITION=y
|
||||||
CONFIG_BINFMT_MISC=y
|
CONFIG_BINFMT_MISC=y
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
# CONFIG_COMPACTION is not set
|
# CONFIG_COMPACTION is not set
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
CONFIG_PACKET=y
|
CONFIG_PACKET=y
|
||||||
|
|
|
@ -19,7 +19,8 @@ CONFIG_FPE_NWFPE=y
|
||||||
CONFIG_MODULES=y
|
CONFIG_MODULES=y
|
||||||
CONFIG_MODULE_UNLOAD=y
|
CONFIG_MODULE_UNLOAD=y
|
||||||
# CONFIG_SWAP is not set
|
# CONFIG_SWAP is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
CONFIG_PACKET=y
|
CONFIG_PACKET=y
|
||||||
CONFIG_UNIX=y
|
CONFIG_UNIX=y
|
||||||
|
|
|
@ -26,7 +26,8 @@ CONFIG_MODULE_UNLOAD=y
|
||||||
CONFIG_MODVERSIONS=y
|
CONFIG_MODVERSIONS=y
|
||||||
CONFIG_MODULE_SRCVERSION_ALL=y
|
CONFIG_MODULE_SRCVERSION_ALL=y
|
||||||
# CONFIG_BLOCK is not set
|
# CONFIG_BLOCK is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
# CONFIG_COMPAT_BRK is not set
|
# CONFIG_COMPAT_BRK is not set
|
||||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
|
|
|
@ -10,7 +10,8 @@ CONFIG_EXPERT=y
|
||||||
# CONFIG_AIO is not set
|
# CONFIG_AIO is not set
|
||||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||||
# CONFIG_COMPAT_BRK is not set
|
# CONFIG_COMPAT_BRK is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_MODULES=y
|
CONFIG_MODULES=y
|
||||||
# CONFIG_BLOCK is not set
|
# CONFIG_BLOCK is not set
|
||||||
CONFIG_OPENRISC_BUILTIN_DTB="or1ksim"
|
CONFIG_OPENRISC_BUILTIN_DTB="or1ksim"
|
||||||
|
|
|
@ -16,7 +16,8 @@ CONFIG_EXPERT=y
|
||||||
# CONFIG_AIO is not set
|
# CONFIG_AIO is not set
|
||||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||||
# CONFIG_COMPAT_BRK is not set
|
# CONFIG_COMPAT_BRK is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_MODULES=y
|
CONFIG_MODULES=y
|
||||||
# CONFIG_BLOCK is not set
|
# CONFIG_BLOCK is not set
|
||||||
CONFIG_OPENRISC_BUILTIN_DTB="simple_smp"
|
CONFIG_OPENRISC_BUILTIN_DTB="simple_smp"
|
||||||
|
|
|
@ -25,7 +25,8 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||||
CONFIG_EMBEDDED=y
|
CONFIG_EMBEDDED=y
|
||||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||||
# CONFIG_COMPAT_BRK is not set
|
# CONFIG_COMPAT_BRK is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
# CONFIG_MMU is not set
|
# CONFIG_MMU is not set
|
||||||
CONFIG_SOC_CANAAN=y
|
CONFIG_SOC_CANAAN=y
|
||||||
CONFIG_NONPORTABLE=y
|
CONFIG_NONPORTABLE=y
|
||||||
|
|
|
@ -17,7 +17,8 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||||
CONFIG_EMBEDDED=y
|
CONFIG_EMBEDDED=y
|
||||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||||
# CONFIG_COMPAT_BRK is not set
|
# CONFIG_COMPAT_BRK is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
# CONFIG_MMU is not set
|
# CONFIG_MMU is not set
|
||||||
CONFIG_SOC_CANAAN=y
|
CONFIG_SOC_CANAAN=y
|
||||||
CONFIG_NONPORTABLE=y
|
CONFIG_NONPORTABLE=y
|
||||||
|
|
|
@ -22,7 +22,8 @@ CONFIG_EXPERT=y
|
||||||
# CONFIG_KALLSYMS is not set
|
# CONFIG_KALLSYMS is not set
|
||||||
# CONFIG_VM_EVENT_COUNTERS is not set
|
# CONFIG_VM_EVENT_COUNTERS is not set
|
||||||
# CONFIG_COMPAT_BRK is not set
|
# CONFIG_COMPAT_BRK is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
# CONFIG_MMU is not set
|
# CONFIG_MMU is not set
|
||||||
CONFIG_SOC_VIRT=y
|
CONFIG_SOC_VIRT=y
|
||||||
CONFIG_NONPORTABLE=y
|
CONFIG_NONPORTABLE=y
|
||||||
|
|
|
@ -10,7 +10,8 @@ CONFIG_USER_NS=y
|
||||||
CONFIG_PID_NS=y
|
CONFIG_PID_NS=y
|
||||||
CONFIG_BLK_DEV_INITRD=y
|
CONFIG_BLK_DEV_INITRD=y
|
||||||
# CONFIG_AIO is not set
|
# CONFIG_AIO is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_PROFILING=y
|
CONFIG_PROFILING=y
|
||||||
CONFIG_MODULES=y
|
CONFIG_MODULES=y
|
||||||
# CONFIG_BLK_DEV_BSG is not set
|
# CONFIG_BLK_DEV_BSG is not set
|
||||||
|
|
|
@ -11,7 +11,8 @@ CONFIG_USER_NS=y
|
||||||
CONFIG_PID_NS=y
|
CONFIG_PID_NS=y
|
||||||
CONFIG_BLK_DEV_INITRD=y
|
CONFIG_BLK_DEV_INITRD=y
|
||||||
CONFIG_KALLSYMS_ALL=y
|
CONFIG_KALLSYMS_ALL=y
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_PROFILING=y
|
CONFIG_PROFILING=y
|
||||||
CONFIG_MODULES=y
|
CONFIG_MODULES=y
|
||||||
# CONFIG_BLK_DEV_BSG is not set
|
# CONFIG_BLK_DEV_BSG is not set
|
||||||
|
|
|
@ -21,7 +21,8 @@ CONFIG_BLK_DEV_INITRD=y
|
||||||
CONFIG_KALLSYMS_ALL=y
|
CONFIG_KALLSYMS_ALL=y
|
||||||
# CONFIG_ELF_CORE is not set
|
# CONFIG_ELF_CORE is not set
|
||||||
# CONFIG_COMPAT_BRK is not set
|
# CONFIG_COMPAT_BRK is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_PROFILING=y
|
CONFIG_PROFILING=y
|
||||||
CONFIG_MODULES=y
|
CONFIG_MODULES=y
|
||||||
CONFIG_MODULE_UNLOAD=y
|
CONFIG_MODULE_UNLOAD=y
|
||||||
|
|
|
@ -9,7 +9,8 @@ CONFIG_LOG_BUF_SHIFT=14
|
||||||
# CONFIG_FUTEX is not set
|
# CONFIG_FUTEX is not set
|
||||||
# CONFIG_EPOLL is not set
|
# CONFIG_EPOLL is not set
|
||||||
# CONFIG_SHMEM is not set
|
# CONFIG_SHMEM is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
# CONFIG_BLK_DEV_BSG is not set
|
# CONFIG_BLK_DEV_BSG is not set
|
||||||
CONFIG_CPU_SUBTYPE_SH7706=y
|
CONFIG_CPU_SUBTYPE_SH7706=y
|
||||||
CONFIG_MEMORY_START=0x0c000000
|
CONFIG_MEMORY_START=0x0c000000
|
||||||
|
|
|
@ -20,7 +20,8 @@ CONFIG_USER_NS=y
|
||||||
CONFIG_PID_NS=y
|
CONFIG_PID_NS=y
|
||||||
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
||||||
CONFIG_KALLSYMS_ALL=y
|
CONFIG_KALLSYMS_ALL=y
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
CONFIG_PROFILING=y
|
CONFIG_PROFILING=y
|
||||||
CONFIG_KPROBES=y
|
CONFIG_KPROBES=y
|
||||||
CONFIG_MODULES=y
|
CONFIG_MODULES=y
|
||||||
|
|
|
@ -129,7 +129,11 @@
|
||||||
|
|
||||||
/* The following flags affect the page allocator grouping pages by mobility */
|
/* The following flags affect the page allocator grouping pages by mobility */
|
||||||
/* Objects are reclaimable */
|
/* Objects are reclaimable */
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
#define SLAB_RECLAIM_ACCOUNT ((slab_flags_t __force)0x00020000U)
|
#define SLAB_RECLAIM_ACCOUNT ((slab_flags_t __force)0x00020000U)
|
||||||
|
#else
|
||||||
|
#define SLAB_RECLAIM_ACCOUNT ((slab_flags_t __force)0)
|
||||||
|
#endif
|
||||||
#define SLAB_TEMPORARY SLAB_RECLAIM_ACCOUNT /* Objects are short-lived */
|
#define SLAB_TEMPORARY SLAB_RECLAIM_ACCOUNT /* Objects are short-lived */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -336,12 +340,17 @@ enum kmalloc_cache_type {
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_MEMCG_KMEM
|
#ifndef CONFIG_MEMCG_KMEM
|
||||||
KMALLOC_CGROUP = KMALLOC_NORMAL,
|
KMALLOC_CGROUP = KMALLOC_NORMAL,
|
||||||
#else
|
|
||||||
KMALLOC_CGROUP,
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_SLUB_TINY
|
||||||
|
KMALLOC_RECLAIM = KMALLOC_NORMAL,
|
||||||
|
#else
|
||||||
KMALLOC_RECLAIM,
|
KMALLOC_RECLAIM,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_ZONE_DMA
|
#ifdef CONFIG_ZONE_DMA
|
||||||
KMALLOC_DMA,
|
KMALLOC_DMA,
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_MEMCG_KMEM
|
||||||
|
KMALLOC_CGROUP,
|
||||||
#endif
|
#endif
|
||||||
NR_KMALLOC_TYPES
|
NR_KMALLOC_TYPES
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,8 +80,10 @@ struct kmem_cache {
|
||||||
unsigned int *random_seq;
|
unsigned int *random_seq;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_HARDENED_USERCOPY
|
||||||
unsigned int useroffset; /* Usercopy region offset */
|
unsigned int useroffset; /* Usercopy region offset */
|
||||||
unsigned int usersize; /* Usercopy region size */
|
unsigned int usersize; /* Usercopy region size */
|
||||||
|
#endif
|
||||||
|
|
||||||
struct kmem_cache_node *node[MAX_NUMNODES];
|
struct kmem_cache_node *node[MAX_NUMNODES];
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,7 @@ enum stat_item {
|
||||||
CPU_PARTIAL_DRAIN, /* Drain cpu partial to node partial */
|
CPU_PARTIAL_DRAIN, /* Drain cpu partial to node partial */
|
||||||
NR_SLUB_STAT_ITEMS };
|
NR_SLUB_STAT_ITEMS };
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
/*
|
/*
|
||||||
* When changing the layout, make sure freelist and tid are still compatible
|
* When changing the layout, make sure freelist and tid are still compatible
|
||||||
* with this_cpu_cmpxchg_double() alignment requirements.
|
* with this_cpu_cmpxchg_double() alignment requirements.
|
||||||
|
@ -57,6 +58,7 @@ struct kmem_cache_cpu {
|
||||||
unsigned stat[NR_SLUB_STAT_ITEMS];
|
unsigned stat[NR_SLUB_STAT_ITEMS];
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
#endif /* CONFIG_SLUB_TINY */
|
||||||
|
|
||||||
#ifdef CONFIG_SLUB_CPU_PARTIAL
|
#ifdef CONFIG_SLUB_CPU_PARTIAL
|
||||||
#define slub_percpu_partial(c) ((c)->partial)
|
#define slub_percpu_partial(c) ((c)->partial)
|
||||||
|
@ -88,7 +90,9 @@ struct kmem_cache_order_objects {
|
||||||
* Slab cache management.
|
* Slab cache management.
|
||||||
*/
|
*/
|
||||||
struct kmem_cache {
|
struct kmem_cache {
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
struct kmem_cache_cpu __percpu *cpu_slab;
|
struct kmem_cache_cpu __percpu *cpu_slab;
|
||||||
|
#endif
|
||||||
/* Used for retrieving partial slabs, etc. */
|
/* Used for retrieving partial slabs, etc. */
|
||||||
slab_flags_t flags;
|
slab_flags_t flags;
|
||||||
unsigned long min_partial;
|
unsigned long min_partial;
|
||||||
|
@ -136,13 +140,15 @@ struct kmem_cache {
|
||||||
struct kasan_cache kasan_info;
|
struct kasan_cache kasan_info;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_HARDENED_USERCOPY
|
||||||
unsigned int useroffset; /* Usercopy region offset */
|
unsigned int useroffset; /* Usercopy region offset */
|
||||||
unsigned int usersize; /* Usercopy region size */
|
unsigned int usersize; /* Usercopy region size */
|
||||||
|
#endif
|
||||||
|
|
||||||
struct kmem_cache_node *node[MAX_NUMNODES];
|
struct kmem_cache_node *node[MAX_NUMNODES];
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_SYSFS
|
#if defined(CONFIG_SYSFS) && !defined(CONFIG_SLUB_TINY)
|
||||||
#define SLAB_SUPPORTS_SYSFS
|
#define SLAB_SUPPORTS_SYSFS
|
||||||
void sysfs_slab_unlink(struct kmem_cache *);
|
void sysfs_slab_unlink(struct kmem_cache *);
|
||||||
void sysfs_slab_release(struct kmem_cache *);
|
void sysfs_slab_release(struct kmem_cache *);
|
||||||
|
|
|
@ -7,5 +7,6 @@ CONFIG_KERNEL_XZ=y
|
||||||
# CONFIG_KERNEL_LZO is not set
|
# CONFIG_KERNEL_LZO is not set
|
||||||
# CONFIG_KERNEL_LZ4 is not set
|
# CONFIG_KERNEL_LZ4 is not set
|
||||||
# CONFIG_SLAB is not set
|
# CONFIG_SLAB is not set
|
||||||
# CONFIG_SLUB is not set
|
# CONFIG_SLOB_DEPRECATED is not set
|
||||||
CONFIG_SLOB=y
|
CONFIG_SLUB=y
|
||||||
|
CONFIG_SLUB_TINY=y
|
||||||
|
|
|
@ -37,7 +37,7 @@ menuconfig KASAN
|
||||||
(HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS)) && \
|
(HAVE_ARCH_KASAN_SW_TAGS && CC_HAS_KASAN_SW_TAGS)) && \
|
||||||
CC_HAS_WORKING_NOSANITIZE_ADDRESS) || \
|
CC_HAS_WORKING_NOSANITIZE_ADDRESS) || \
|
||||||
HAVE_ARCH_KASAN_HW_TAGS
|
HAVE_ARCH_KASAN_HW_TAGS
|
||||||
depends on (SLUB && SYSFS) || (SLAB && !DEBUG_SLAB)
|
depends on (SLUB && SYSFS && !SLUB_TINY) || (SLAB && !DEBUG_SLAB)
|
||||||
select STACKDEPOT_ALWAYS_INIT
|
select STACKDEPOT_ALWAYS_INIT
|
||||||
help
|
help
|
||||||
Enables KASAN (Kernel Address Sanitizer) - a dynamic memory safety
|
Enables KASAN (Kernel Address Sanitizer) - a dynamic memory safety
|
||||||
|
|
38
mm/Kconfig
38
mm/Kconfig
|
@ -219,17 +219,43 @@ config SLUB
|
||||||
and has enhanced diagnostics. SLUB is the default choice for
|
and has enhanced diagnostics. SLUB is the default choice for
|
||||||
a slab allocator.
|
a slab allocator.
|
||||||
|
|
||||||
config SLOB
|
config SLOB_DEPRECATED
|
||||||
depends on EXPERT
|
depends on EXPERT
|
||||||
bool "SLOB (Simple Allocator)"
|
bool "SLOB (Simple Allocator - DEPRECATED)"
|
||||||
depends on !PREEMPT_RT
|
depends on !PREEMPT_RT
|
||||||
help
|
help
|
||||||
|
Deprecated and scheduled for removal in a few cycles. SLUB
|
||||||
|
recommended as replacement. CONFIG_SLUB_TINY can be considered
|
||||||
|
on systems with 16MB or less RAM.
|
||||||
|
|
||||||
|
If you need SLOB to stay, please contact linux-mm@kvack.org and
|
||||||
|
people listed in the SLAB ALLOCATOR section of MAINTAINERS file,
|
||||||
|
with your use case.
|
||||||
|
|
||||||
SLOB replaces the stock allocator with a drastically simpler
|
SLOB replaces the stock allocator with a drastically simpler
|
||||||
allocator. SLOB is generally more space efficient but
|
allocator. SLOB is generally more space efficient but
|
||||||
does not perform as well on large systems.
|
does not perform as well on large systems.
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
config SLOB
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
depends on SLOB_DEPRECATED
|
||||||
|
|
||||||
|
config SLUB_TINY
|
||||||
|
bool "Configure SLUB for minimal memory footprint"
|
||||||
|
depends on SLUB && EXPERT
|
||||||
|
select SLAB_MERGE_DEFAULT
|
||||||
|
help
|
||||||
|
Configures the SLUB allocator in a way to achieve minimal memory
|
||||||
|
footprint, sacrificing scalability, debugging and other features.
|
||||||
|
This is intended only for the smallest system that had used the
|
||||||
|
SLOB allocator and is not recommended for systems with more than
|
||||||
|
16MB RAM.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
config SLAB_MERGE_DEFAULT
|
config SLAB_MERGE_DEFAULT
|
||||||
bool "Allow slab caches to be merged"
|
bool "Allow slab caches to be merged"
|
||||||
default y
|
default y
|
||||||
|
@ -247,7 +273,7 @@ config SLAB_MERGE_DEFAULT
|
||||||
|
|
||||||
config SLAB_FREELIST_RANDOM
|
config SLAB_FREELIST_RANDOM
|
||||||
bool "Randomize slab freelist"
|
bool "Randomize slab freelist"
|
||||||
depends on SLAB || SLUB
|
depends on SLAB || (SLUB && !SLUB_TINY)
|
||||||
help
|
help
|
||||||
Randomizes the freelist order used on creating new pages. This
|
Randomizes the freelist order used on creating new pages. This
|
||||||
security feature reduces the predictability of the kernel slab
|
security feature reduces the predictability of the kernel slab
|
||||||
|
@ -255,7 +281,7 @@ config SLAB_FREELIST_RANDOM
|
||||||
|
|
||||||
config SLAB_FREELIST_HARDENED
|
config SLAB_FREELIST_HARDENED
|
||||||
bool "Harden slab freelist metadata"
|
bool "Harden slab freelist metadata"
|
||||||
depends on SLAB || SLUB
|
depends on SLAB || (SLUB && !SLUB_TINY)
|
||||||
help
|
help
|
||||||
Many kernel heap attacks try to target slab cache metadata and
|
Many kernel heap attacks try to target slab cache metadata and
|
||||||
other infrastructure. This options makes minor performance
|
other infrastructure. This options makes minor performance
|
||||||
|
@ -267,7 +293,7 @@ config SLAB_FREELIST_HARDENED
|
||||||
config SLUB_STATS
|
config SLUB_STATS
|
||||||
default n
|
default n
|
||||||
bool "Enable SLUB performance statistics"
|
bool "Enable SLUB performance statistics"
|
||||||
depends on SLUB && SYSFS
|
depends on SLUB && SYSFS && !SLUB_TINY
|
||||||
help
|
help
|
||||||
SLUB statistics are useful to debug SLUBs allocation behavior in
|
SLUB statistics are useful to debug SLUBs allocation behavior in
|
||||||
order find ways to optimize the allocator. This should never be
|
order find ways to optimize the allocator. This should never be
|
||||||
|
@ -279,7 +305,7 @@ config SLUB_STATS
|
||||||
|
|
||||||
config SLUB_CPU_PARTIAL
|
config SLUB_CPU_PARTIAL
|
||||||
default y
|
default y
|
||||||
depends on SLUB && SMP
|
depends on SLUB && SMP && !SLUB_TINY
|
||||||
bool "SLUB per cpu partial cache"
|
bool "SLUB per cpu partial cache"
|
||||||
help
|
help
|
||||||
Per cpu partial caches accelerate objects allocation and freeing
|
Per cpu partial caches accelerate objects allocation and freeing
|
||||||
|
|
|
@ -56,7 +56,7 @@ config DEBUG_SLAB
|
||||||
config SLUB_DEBUG
|
config SLUB_DEBUG
|
||||||
default y
|
default y
|
||||||
bool "Enable SLUB debugging support" if EXPERT
|
bool "Enable SLUB debugging support" if EXPERT
|
||||||
depends on SLUB && SYSFS
|
depends on SLUB && SYSFS && !SLUB_TINY
|
||||||
select STACKDEPOT if STACKTRACE_SUPPORT
|
select STACKDEPOT if STACKTRACE_SUPPORT
|
||||||
help
|
help
|
||||||
SLUB has extensive debug support features. Disabling these can
|
SLUB has extensive debug support features. Disabling these can
|
||||||
|
|
|
@ -217,8 +217,6 @@ struct kmem_cache {
|
||||||
unsigned int size; /* The aligned/padded/added on size */
|
unsigned int size; /* The aligned/padded/added on size */
|
||||||
unsigned int align; /* Alignment as calculated */
|
unsigned int align; /* Alignment as calculated */
|
||||||
slab_flags_t flags; /* Active flags on the slab */
|
slab_flags_t flags; /* Active flags on the slab */
|
||||||
unsigned int useroffset;/* Usercopy region offset */
|
|
||||||
unsigned int usersize; /* Usercopy region size */
|
|
||||||
const char *name; /* Slab name for sysfs */
|
const char *name; /* Slab name for sysfs */
|
||||||
int refcount; /* Use counter */
|
int refcount; /* Use counter */
|
||||||
void (*ctor)(void *); /* Called on object slot creation */
|
void (*ctor)(void *); /* Called on object slot creation */
|
||||||
|
|
|
@ -143,8 +143,10 @@ int slab_unmergeable(struct kmem_cache *s)
|
||||||
if (s->ctor)
|
if (s->ctor)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
#ifdef CONFIG_HARDENED_USERCOPY
|
||||||
if (s->usersize)
|
if (s->usersize)
|
||||||
return 1;
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We may have set a slab to be unmergeable during bootstrap.
|
* We may have set a slab to be unmergeable during bootstrap.
|
||||||
|
@ -223,8 +225,10 @@ static struct kmem_cache *create_cache(const char *name,
|
||||||
s->size = s->object_size = object_size;
|
s->size = s->object_size = object_size;
|
||||||
s->align = align;
|
s->align = align;
|
||||||
s->ctor = ctor;
|
s->ctor = ctor;
|
||||||
|
#ifdef CONFIG_HARDENED_USERCOPY
|
||||||
s->useroffset = useroffset;
|
s->useroffset = useroffset;
|
||||||
s->usersize = usersize;
|
s->usersize = usersize;
|
||||||
|
#endif
|
||||||
|
|
||||||
err = __kmem_cache_create(s, flags);
|
err = __kmem_cache_create(s, flags);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -317,7 +321,8 @@ kmem_cache_create_usercopy(const char *name,
|
||||||
flags &= CACHE_CREATE_MASK;
|
flags &= CACHE_CREATE_MASK;
|
||||||
|
|
||||||
/* Fail closed on bad usersize of useroffset values. */
|
/* Fail closed on bad usersize of useroffset values. */
|
||||||
if (WARN_ON(!usersize && useroffset) ||
|
if (!IS_ENABLED(CONFIG_HARDENED_USERCOPY) ||
|
||||||
|
WARN_ON(!usersize && useroffset) ||
|
||||||
WARN_ON(size < usersize || size - usersize < useroffset))
|
WARN_ON(size < usersize || size - usersize < useroffset))
|
||||||
usersize = useroffset = 0;
|
usersize = useroffset = 0;
|
||||||
|
|
||||||
|
@ -595,8 +600,8 @@ void kmem_dump_obj(void *object)
|
||||||
ptroffset = ((char *)object - (char *)kp.kp_objp) - kp.kp_data_offset;
|
ptroffset = ((char *)object - (char *)kp.kp_objp) - kp.kp_data_offset;
|
||||||
pr_cont(" pointer offset %lu", ptroffset);
|
pr_cont(" pointer offset %lu", ptroffset);
|
||||||
}
|
}
|
||||||
if (kp.kp_slab_cache && kp.kp_slab_cache->usersize)
|
if (kp.kp_slab_cache && kp.kp_slab_cache->object_size)
|
||||||
pr_cont(" size %u", kp.kp_slab_cache->usersize);
|
pr_cont(" size %u", kp.kp_slab_cache->object_size);
|
||||||
if (kp.kp_ret)
|
if (kp.kp_ret)
|
||||||
pr_cont(" allocated at %pS\n", kp.kp_ret);
|
pr_cont(" allocated at %pS\n", kp.kp_ret);
|
||||||
else
|
else
|
||||||
|
@ -640,8 +645,10 @@ void __init create_boot_cache(struct kmem_cache *s, const char *name,
|
||||||
align = max(align, size);
|
align = max(align, size);
|
||||||
s->align = calculate_alignment(flags, align, size);
|
s->align = calculate_alignment(flags, align, size);
|
||||||
|
|
||||||
|
#ifdef CONFIG_HARDENED_USERCOPY
|
||||||
s->useroffset = useroffset;
|
s->useroffset = useroffset;
|
||||||
s->usersize = usersize;
|
s->usersize = usersize;
|
||||||
|
#endif
|
||||||
|
|
||||||
err = __kmem_cache_create(s, flags);
|
err = __kmem_cache_create(s, flags);
|
||||||
|
|
||||||
|
@ -766,10 +773,16 @@ EXPORT_SYMBOL(kmalloc_size_roundup);
|
||||||
#define KMALLOC_CGROUP_NAME(sz)
|
#define KMALLOC_CGROUP_NAME(sz)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
|
#define KMALLOC_RCL_NAME(sz) .name[KMALLOC_RECLAIM] = "kmalloc-rcl-" #sz,
|
||||||
|
#else
|
||||||
|
#define KMALLOC_RCL_NAME(sz)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define INIT_KMALLOC_INFO(__size, __short_size) \
|
#define INIT_KMALLOC_INFO(__size, __short_size) \
|
||||||
{ \
|
{ \
|
||||||
.name[KMALLOC_NORMAL] = "kmalloc-" #__short_size, \
|
.name[KMALLOC_NORMAL] = "kmalloc-" #__short_size, \
|
||||||
.name[KMALLOC_RECLAIM] = "kmalloc-rcl-" #__short_size, \
|
KMALLOC_RCL_NAME(__short_size) \
|
||||||
KMALLOC_CGROUP_NAME(__short_size) \
|
KMALLOC_CGROUP_NAME(__short_size) \
|
||||||
KMALLOC_DMA_NAME(__short_size) \
|
KMALLOC_DMA_NAME(__short_size) \
|
||||||
.size = __size, \
|
.size = __size, \
|
||||||
|
@ -855,7 +868,7 @@ void __init setup_kmalloc_cache_index_table(void)
|
||||||
static void __init
|
static void __init
|
||||||
new_kmalloc_cache(int idx, enum kmalloc_cache_type type, slab_flags_t flags)
|
new_kmalloc_cache(int idx, enum kmalloc_cache_type type, slab_flags_t flags)
|
||||||
{
|
{
|
||||||
if (type == KMALLOC_RECLAIM) {
|
if ((KMALLOC_RECLAIM != KMALLOC_NORMAL) && (type == KMALLOC_RECLAIM)) {
|
||||||
flags |= SLAB_RECLAIM_ACCOUNT;
|
flags |= SLAB_RECLAIM_ACCOUNT;
|
||||||
} else if (IS_ENABLED(CONFIG_MEMCG_KMEM) && (type == KMALLOC_CGROUP)) {
|
} else if (IS_ENABLED(CONFIG_MEMCG_KMEM) && (type == KMALLOC_CGROUP)) {
|
||||||
if (mem_cgroup_kmem_disabled()) {
|
if (mem_cgroup_kmem_disabled()) {
|
||||||
|
|
422
mm/slub.c
422
mm/slub.c
|
@ -187,6 +187,12 @@ do { \
|
||||||
#define USE_LOCKLESS_FAST_PATH() (false)
|
#define USE_LOCKLESS_FAST_PATH() (false)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
|
#define __fastpath_inline __always_inline
|
||||||
|
#else
|
||||||
|
#define __fastpath_inline
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SLUB_DEBUG
|
#ifdef CONFIG_SLUB_DEBUG
|
||||||
#ifdef CONFIG_SLUB_DEBUG_ON
|
#ifdef CONFIG_SLUB_DEBUG_ON
|
||||||
DEFINE_STATIC_KEY_TRUE(slub_debug_enabled);
|
DEFINE_STATIC_KEY_TRUE(slub_debug_enabled);
|
||||||
|
@ -241,6 +247,7 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
|
||||||
/* Enable to log cmpxchg failures */
|
/* Enable to log cmpxchg failures */
|
||||||
#undef SLUB_DEBUG_CMPXCHG
|
#undef SLUB_DEBUG_CMPXCHG
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
/*
|
/*
|
||||||
* Minimum number of partial slabs. These will be left on the partial
|
* Minimum number of partial slabs. These will be left on the partial
|
||||||
* lists even if they are empty. kmem_cache_shrink may reclaim them.
|
* lists even if they are empty. kmem_cache_shrink may reclaim them.
|
||||||
|
@ -253,6 +260,10 @@ static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
|
||||||
* sort the partial list by the number of objects in use.
|
* sort the partial list by the number of objects in use.
|
||||||
*/
|
*/
|
||||||
#define MAX_PARTIAL 10
|
#define MAX_PARTIAL 10
|
||||||
|
#else
|
||||||
|
#define MIN_PARTIAL 0
|
||||||
|
#define MAX_PARTIAL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEBUG_DEFAULT_FLAGS (SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE | \
|
#define DEBUG_DEFAULT_FLAGS (SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE | \
|
||||||
SLAB_POISON | SLAB_STORE_USER)
|
SLAB_POISON | SLAB_STORE_USER)
|
||||||
|
@ -298,7 +309,7 @@ struct track {
|
||||||
|
|
||||||
enum track_item { TRACK_ALLOC, TRACK_FREE };
|
enum track_item { TRACK_ALLOC, TRACK_FREE };
|
||||||
|
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef SLAB_SUPPORTS_SYSFS
|
||||||
static int sysfs_slab_add(struct kmem_cache *);
|
static int sysfs_slab_add(struct kmem_cache *);
|
||||||
static int sysfs_slab_alias(struct kmem_cache *, const char *);
|
static int sysfs_slab_alias(struct kmem_cache *, const char *);
|
||||||
#else
|
#else
|
||||||
|
@ -332,10 +343,12 @@ static inline void stat(const struct kmem_cache *s, enum stat_item si)
|
||||||
*/
|
*/
|
||||||
static nodemask_t slab_nodes;
|
static nodemask_t slab_nodes;
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
/*
|
/*
|
||||||
* Workqueue used for flush_cpu_slab().
|
* Workqueue used for flush_cpu_slab().
|
||||||
*/
|
*/
|
||||||
static struct workqueue_struct *flushwq;
|
static struct workqueue_struct *flushwq;
|
||||||
|
#endif
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Core slab cache functions
|
* Core slab cache functions
|
||||||
|
@ -381,10 +394,12 @@ static inline void *get_freepointer(struct kmem_cache *s, void *object)
|
||||||
return freelist_dereference(s, object + s->offset);
|
return freelist_dereference(s, object + s->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
static void prefetch_freepointer(const struct kmem_cache *s, void *object)
|
static void prefetch_freepointer(const struct kmem_cache *s, void *object)
|
||||||
{
|
{
|
||||||
prefetchw(object + s->offset);
|
prefetchw(object + s->offset);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When running under KMSAN, get_freepointer_safe() may return an uninitialized
|
* When running under KMSAN, get_freepointer_safe() may return an uninitialized
|
||||||
|
@ -1402,7 +1417,7 @@ static inline int alloc_consistency_checks(struct kmem_cache *s,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline int alloc_debug_processing(struct kmem_cache *s,
|
static noinline bool alloc_debug_processing(struct kmem_cache *s,
|
||||||
struct slab *slab, void *object, int orig_size)
|
struct slab *slab, void *object, int orig_size)
|
||||||
{
|
{
|
||||||
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
|
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
|
||||||
|
@ -1414,7 +1429,7 @@ static noinline int alloc_debug_processing(struct kmem_cache *s,
|
||||||
trace(s, slab, object, 1);
|
trace(s, slab, object, 1);
|
||||||
set_orig_size(s, object, orig_size);
|
set_orig_size(s, object, orig_size);
|
||||||
init_object(s, object, SLUB_RED_ACTIVE);
|
init_object(s, object, SLUB_RED_ACTIVE);
|
||||||
return 1;
|
return true;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
if (folio_test_slab(slab_folio(slab))) {
|
if (folio_test_slab(slab_folio(slab))) {
|
||||||
|
@ -1427,7 +1442,7 @@ bad:
|
||||||
slab->inuse = slab->objects;
|
slab->inuse = slab->objects;
|
||||||
slab->freelist = NULL;
|
slab->freelist = NULL;
|
||||||
}
|
}
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int free_consistency_checks(struct kmem_cache *s,
|
static inline int free_consistency_checks(struct kmem_cache *s,
|
||||||
|
@ -1680,17 +1695,17 @@ static inline void setup_object_debug(struct kmem_cache *s, void *object) {}
|
||||||
static inline
|
static inline
|
||||||
void setup_slab_debug(struct kmem_cache *s, struct slab *slab, void *addr) {}
|
void setup_slab_debug(struct kmem_cache *s, struct slab *slab, void *addr) {}
|
||||||
|
|
||||||
static inline int alloc_debug_processing(struct kmem_cache *s,
|
static inline bool alloc_debug_processing(struct kmem_cache *s,
|
||||||
struct slab *slab, void *object, int orig_size) { return 0; }
|
struct slab *slab, void *object, int orig_size) { return true; }
|
||||||
|
|
||||||
static inline void free_debug_processing(
|
static inline bool free_debug_processing(struct kmem_cache *s,
|
||||||
struct kmem_cache *s, struct slab *slab,
|
struct slab *slab, void *head, void *tail, int *bulk_cnt,
|
||||||
void *head, void *tail, int bulk_cnt,
|
unsigned long addr, depot_stack_handle_t handle) { return true; }
|
||||||
unsigned long addr) {}
|
|
||||||
|
|
||||||
static inline void slab_pad_check(struct kmem_cache *s, struct slab *slab) {}
|
static inline void slab_pad_check(struct kmem_cache *s, struct slab *slab) {}
|
||||||
static inline int check_object(struct kmem_cache *s, struct slab *slab,
|
static inline int check_object(struct kmem_cache *s, struct slab *slab,
|
||||||
void *object, u8 val) { return 1; }
|
void *object, u8 val) { return 1; }
|
||||||
|
static inline depot_stack_handle_t set_track_prepare(void) { return 0; }
|
||||||
static inline void set_track(struct kmem_cache *s, void *object,
|
static inline void set_track(struct kmem_cache *s, void *object,
|
||||||
enum track_item alloc, unsigned long addr) {}
|
enum track_item alloc, unsigned long addr) {}
|
||||||
static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
|
static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
|
||||||
|
@ -1715,11 +1730,13 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node,
|
||||||
static inline void dec_slabs_node(struct kmem_cache *s, int node,
|
static inline void dec_slabs_node(struct kmem_cache *s, int node,
|
||||||
int objects) {}
|
int objects) {}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
static bool freelist_corrupted(struct kmem_cache *s, struct slab *slab,
|
static bool freelist_corrupted(struct kmem_cache *s, struct slab *slab,
|
||||||
void **freelist, void *nextfree)
|
void **freelist, void *nextfree)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif /* CONFIG_SLUB_DEBUG */
|
#endif /* CONFIG_SLUB_DEBUG */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2257,7 +2274,7 @@ static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
|
||||||
if (!pfmemalloc_match(slab, pc->flags))
|
if (!pfmemalloc_match(slab, pc->flags))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (kmem_cache_debug(s)) {
|
if (IS_ENABLED(CONFIG_SLUB_TINY) || kmem_cache_debug(s)) {
|
||||||
object = alloc_single_from_partial(s, n, slab,
|
object = alloc_single_from_partial(s, n, slab,
|
||||||
pc->orig_size);
|
pc->orig_size);
|
||||||
if (object)
|
if (object)
|
||||||
|
@ -2372,6 +2389,8 @@ static void *get_partial(struct kmem_cache *s, int node, struct partial_context
|
||||||
return get_any_partial(s, pc);
|
return get_any_partial(s, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
|
|
||||||
#ifdef CONFIG_PREEMPTION
|
#ifdef CONFIG_PREEMPTION
|
||||||
/*
|
/*
|
||||||
* Calculate the next globally unique transaction for disambiguation
|
* Calculate the next globally unique transaction for disambiguation
|
||||||
|
@ -2385,7 +2404,7 @@ static void *get_partial(struct kmem_cache *s, int node, struct partial_context
|
||||||
* different cpus.
|
* different cpus.
|
||||||
*/
|
*/
|
||||||
#define TID_STEP 1
|
#define TID_STEP 1
|
||||||
#endif
|
#endif /* CONFIG_PREEMPTION */
|
||||||
|
|
||||||
static inline unsigned long next_tid(unsigned long tid)
|
static inline unsigned long next_tid(unsigned long tid)
|
||||||
{
|
{
|
||||||
|
@ -2834,6 +2853,13 @@ static int slub_cpu_dead(unsigned int cpu)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else /* CONFIG_SLUB_TINY */
|
||||||
|
static inline void flush_all_cpus_locked(struct kmem_cache *s) { }
|
||||||
|
static inline void flush_all(struct kmem_cache *s) { }
|
||||||
|
static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu) { }
|
||||||
|
static inline int slub_cpu_dead(unsigned int cpu) { return 0; }
|
||||||
|
#endif /* CONFIG_SLUB_TINY */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the objects in a per cpu structure fit numa
|
* Check if the objects in a per cpu structure fit numa
|
||||||
* locality expectations.
|
* locality expectations.
|
||||||
|
@ -2859,38 +2885,28 @@ static inline unsigned long node_nr_objs(struct kmem_cache_node *n)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Supports checking bulk free of a constructed freelist */
|
/* Supports checking bulk free of a constructed freelist */
|
||||||
static noinline void free_debug_processing(
|
static inline bool free_debug_processing(struct kmem_cache *s,
|
||||||
struct kmem_cache *s, struct slab *slab,
|
struct slab *slab, void *head, void *tail, int *bulk_cnt,
|
||||||
void *head, void *tail, int bulk_cnt,
|
unsigned long addr, depot_stack_handle_t handle)
|
||||||
unsigned long addr)
|
|
||||||
{
|
{
|
||||||
struct kmem_cache_node *n = get_node(s, slab_nid(slab));
|
bool checks_ok = false;
|
||||||
struct slab *slab_free = NULL;
|
|
||||||
void *object = head;
|
void *object = head;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
unsigned long flags;
|
|
||||||
bool checks_ok = false;
|
|
||||||
depot_stack_handle_t handle = 0;
|
|
||||||
|
|
||||||
if (s->flags & SLAB_STORE_USER)
|
|
||||||
handle = set_track_prepare();
|
|
||||||
|
|
||||||
spin_lock_irqsave(&n->list_lock, flags);
|
|
||||||
|
|
||||||
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
|
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
|
||||||
if (!check_slab(s, slab))
|
if (!check_slab(s, slab))
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slab->inuse < bulk_cnt) {
|
if (slab->inuse < *bulk_cnt) {
|
||||||
slab_err(s, slab, "Slab has %d allocated objects but %d are to be freed\n",
|
slab_err(s, slab, "Slab has %d allocated objects but %d are to be freed\n",
|
||||||
slab->inuse, bulk_cnt);
|
slab->inuse, *bulk_cnt);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_object:
|
next_object:
|
||||||
|
|
||||||
if (++cnt > bulk_cnt)
|
if (++cnt > *bulk_cnt)
|
||||||
goto out_cnt;
|
goto out_cnt;
|
||||||
|
|
||||||
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
|
if (s->flags & SLAB_CONSISTENCY_CHECKS) {
|
||||||
|
@ -2912,61 +2928,22 @@ next_object:
|
||||||
checks_ok = true;
|
checks_ok = true;
|
||||||
|
|
||||||
out_cnt:
|
out_cnt:
|
||||||
if (cnt != bulk_cnt)
|
if (cnt != *bulk_cnt) {
|
||||||
slab_err(s, slab, "Bulk free expected %d objects but found %d\n",
|
slab_err(s, slab, "Bulk free expected %d objects but found %d\n",
|
||||||
bulk_cnt, cnt);
|
*bulk_cnt, cnt);
|
||||||
|
*bulk_cnt = cnt;
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (checks_ok) {
|
|
||||||
void *prior = slab->freelist;
|
|
||||||
|
|
||||||
/* Perform the actual freeing while we still hold the locks */
|
|
||||||
slab->inuse -= cnt;
|
|
||||||
set_freepointer(s, tail, prior);
|
|
||||||
slab->freelist = head;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the slab is empty, and node's partial list is full,
|
|
||||||
* it should be discarded anyway no matter it's on full or
|
|
||||||
* partial list.
|
|
||||||
*/
|
|
||||||
if (slab->inuse == 0 && n->nr_partial >= s->min_partial)
|
|
||||||
slab_free = slab;
|
|
||||||
|
|
||||||
if (!prior) {
|
|
||||||
/* was on full list */
|
|
||||||
remove_full(s, n, slab);
|
|
||||||
if (!slab_free) {
|
|
||||||
add_partial(n, slab, DEACTIVATE_TO_TAIL);
|
|
||||||
stat(s, FREE_ADD_PARTIAL);
|
|
||||||
}
|
|
||||||
} else if (slab_free) {
|
|
||||||
remove_partial(n, slab);
|
|
||||||
stat(s, FREE_REMOVE_PARTIAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slab_free) {
|
|
||||||
/*
|
|
||||||
* Update the counters while still holding n->list_lock to
|
|
||||||
* prevent spurious validation warnings
|
|
||||||
*/
|
|
||||||
dec_slabs_node(s, slab_nid(slab_free), slab_free->objects);
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&n->list_lock, flags);
|
|
||||||
|
|
||||||
if (!checks_ok)
|
if (!checks_ok)
|
||||||
slab_fix(s, "Object at 0x%p not freed", object);
|
slab_fix(s, "Object at 0x%p not freed", object);
|
||||||
|
|
||||||
if (slab_free) {
|
return checks_ok;
|
||||||
stat(s, FREE_SLAB);
|
|
||||||
free_slab(s, slab_free);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SLUB_DEBUG */
|
#endif /* CONFIG_SLUB_DEBUG */
|
||||||
|
|
||||||
#if defined(CONFIG_SLUB_DEBUG) || defined(CONFIG_SYSFS)
|
#if defined(CONFIG_SLUB_DEBUG) || defined(SLAB_SUPPORTS_SYSFS)
|
||||||
static unsigned long count_partial(struct kmem_cache_node *n,
|
static unsigned long count_partial(struct kmem_cache_node *n,
|
||||||
int (*get_count)(struct slab *))
|
int (*get_count)(struct slab *))
|
||||||
{
|
{
|
||||||
|
@ -2980,12 +2957,12 @@ static unsigned long count_partial(struct kmem_cache_node *n,
|
||||||
spin_unlock_irqrestore(&n->list_lock, flags);
|
spin_unlock_irqrestore(&n->list_lock, flags);
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SLUB_DEBUG || CONFIG_SYSFS */
|
#endif /* CONFIG_SLUB_DEBUG || SLAB_SUPPORTS_SYSFS */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SLUB_DEBUG
|
||||||
static noinline void
|
static noinline void
|
||||||
slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
|
slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SLUB_DEBUG
|
|
||||||
static DEFINE_RATELIMIT_STATE(slub_oom_rs, DEFAULT_RATELIMIT_INTERVAL,
|
static DEFINE_RATELIMIT_STATE(slub_oom_rs, DEFAULT_RATELIMIT_INTERVAL,
|
||||||
DEFAULT_RATELIMIT_BURST);
|
DEFAULT_RATELIMIT_BURST);
|
||||||
int node;
|
int node;
|
||||||
|
@ -3016,8 +2993,11 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
|
||||||
pr_warn(" node %d: slabs: %ld, objs: %ld, free: %ld\n",
|
pr_warn(" node %d: slabs: %ld, objs: %ld, free: %ld\n",
|
||||||
node, nr_slabs, nr_objs, nr_free);
|
node, nr_slabs, nr_objs, nr_free);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#else /* CONFIG_SLUB_DEBUG */
|
||||||
|
static inline void
|
||||||
|
slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags)
|
static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags)
|
||||||
{
|
{
|
||||||
|
@ -3027,6 +3007,7 @@ static inline bool pfmemalloc_match(struct slab *slab, gfp_t gfpflags)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
/*
|
/*
|
||||||
* Check the slab->freelist and either transfer the freelist to the
|
* Check the slab->freelist and either transfer the freelist to the
|
||||||
* per cpu freelist or deactivate the slab.
|
* per cpu freelist or deactivate the slab.
|
||||||
|
@ -3314,45 +3295,13 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static __always_inline void *__slab_alloc_node(struct kmem_cache *s,
|
||||||
* If the object has been wiped upon free, make sure it's fully initialized by
|
|
||||||
* zeroing out freelist pointer.
|
|
||||||
*/
|
|
||||||
static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s,
|
|
||||||
void *obj)
|
|
||||||
{
|
|
||||||
if (unlikely(slab_want_init_on_free(s)) && obj)
|
|
||||||
memset((void *)((char *)kasan_reset_tag(obj) + s->offset),
|
|
||||||
0, sizeof(void *));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc)
|
|
||||||
* have the fastpath folded into their functions. So no function call
|
|
||||||
* overhead for requests that can be satisfied on the fastpath.
|
|
||||||
*
|
|
||||||
* The fastpath works by first checking if the lockless freelist can be used.
|
|
||||||
* If not then __slab_alloc is called for slow processing.
|
|
||||||
*
|
|
||||||
* Otherwise we can simply pick the next object from the lockless free list.
|
|
||||||
*/
|
|
||||||
static __always_inline void *slab_alloc_node(struct kmem_cache *s, struct list_lru *lru,
|
|
||||||
gfp_t gfpflags, int node, unsigned long addr, size_t orig_size)
|
gfp_t gfpflags, int node, unsigned long addr, size_t orig_size)
|
||||||
{
|
{
|
||||||
void *object;
|
|
||||||
struct kmem_cache_cpu *c;
|
struct kmem_cache_cpu *c;
|
||||||
struct slab *slab;
|
struct slab *slab;
|
||||||
unsigned long tid;
|
unsigned long tid;
|
||||||
struct obj_cgroup *objcg = NULL;
|
void *object;
|
||||||
bool init = false;
|
|
||||||
|
|
||||||
s = slab_pre_alloc_hook(s, lru, &objcg, 1, gfpflags);
|
|
||||||
if (!s)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
object = kfence_alloc(s, orig_size, gfpflags);
|
|
||||||
if (unlikely(object))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
redo:
|
redo:
|
||||||
/*
|
/*
|
||||||
|
@ -3422,6 +3371,75 @@ redo:
|
||||||
stat(s, ALLOC_FASTPATH);
|
stat(s, ALLOC_FASTPATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.slab = &slab;
|
||||||
|
pc.orig_size = orig_size;
|
||||||
|
object = get_partial(s, node, &pc);
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
return 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);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SLUB_TINY */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the object has been wiped upon free, make sure it's fully initialized by
|
||||||
|
* zeroing out freelist pointer.
|
||||||
|
*/
|
||||||
|
static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s,
|
||||||
|
void *obj)
|
||||||
|
{
|
||||||
|
if (unlikely(slab_want_init_on_free(s)) && obj)
|
||||||
|
memset((void *)((char *)kasan_reset_tag(obj) + s->offset),
|
||||||
|
0, sizeof(void *));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc)
|
||||||
|
* have the fastpath folded into their functions. So no function call
|
||||||
|
* overhead for requests that can be satisfied on the fastpath.
|
||||||
|
*
|
||||||
|
* The fastpath works by first checking if the lockless freelist can be used.
|
||||||
|
* If not then __slab_alloc is called for slow processing.
|
||||||
|
*
|
||||||
|
* Otherwise we can simply pick the next object from the lockless free list.
|
||||||
|
*/
|
||||||
|
static __fastpath_inline void *slab_alloc_node(struct kmem_cache *s, struct list_lru *lru,
|
||||||
|
gfp_t gfpflags, int node, unsigned long addr, size_t orig_size)
|
||||||
|
{
|
||||||
|
void *object;
|
||||||
|
struct obj_cgroup *objcg = NULL;
|
||||||
|
bool init = false;
|
||||||
|
|
||||||
|
s = slab_pre_alloc_hook(s, lru, &objcg, 1, gfpflags);
|
||||||
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
object = kfence_alloc(s, orig_size, gfpflags);
|
||||||
|
if (unlikely(object))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
object = __slab_alloc_node(s, gfpflags, node, addr, orig_size);
|
||||||
|
|
||||||
maybe_wipe_obj_freeptr(s, object);
|
maybe_wipe_obj_freeptr(s, object);
|
||||||
init = slab_want_init_on_alloc(gfpflags, s);
|
init = slab_want_init_on_alloc(gfpflags, s);
|
||||||
|
|
||||||
|
@ -3435,13 +3453,13 @@ out:
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline void *slab_alloc(struct kmem_cache *s, struct list_lru *lru,
|
static __fastpath_inline void *slab_alloc(struct kmem_cache *s, struct list_lru *lru,
|
||||||
gfp_t gfpflags, unsigned long addr, size_t orig_size)
|
gfp_t gfpflags, unsigned long addr, size_t orig_size)
|
||||||
{
|
{
|
||||||
return slab_alloc_node(s, lru, gfpflags, NUMA_NO_NODE, addr, orig_size);
|
return slab_alloc_node(s, lru, gfpflags, NUMA_NO_NODE, addr, orig_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __always_inline
|
static __fastpath_inline
|
||||||
void *__kmem_cache_alloc_lru(struct kmem_cache *s, struct list_lru *lru,
|
void *__kmem_cache_alloc_lru(struct kmem_cache *s, struct list_lru *lru,
|
||||||
gfp_t gfpflags)
|
gfp_t gfpflags)
|
||||||
{
|
{
|
||||||
|
@ -3483,6 +3501,67 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kmem_cache_alloc_node);
|
EXPORT_SYMBOL(kmem_cache_alloc_node);
|
||||||
|
|
||||||
|
static noinline void free_to_partial_list(
|
||||||
|
struct kmem_cache *s, struct slab *slab,
|
||||||
|
void *head, void *tail, int bulk_cnt,
|
||||||
|
unsigned long addr)
|
||||||
|
{
|
||||||
|
struct kmem_cache_node *n = get_node(s, slab_nid(slab));
|
||||||
|
struct slab *slab_free = NULL;
|
||||||
|
int cnt = bulk_cnt;
|
||||||
|
unsigned long flags;
|
||||||
|
depot_stack_handle_t handle = 0;
|
||||||
|
|
||||||
|
if (s->flags & SLAB_STORE_USER)
|
||||||
|
handle = set_track_prepare();
|
||||||
|
|
||||||
|
spin_lock_irqsave(&n->list_lock, flags);
|
||||||
|
|
||||||
|
if (free_debug_processing(s, slab, head, tail, &cnt, addr, handle)) {
|
||||||
|
void *prior = slab->freelist;
|
||||||
|
|
||||||
|
/* Perform the actual freeing while we still hold the locks */
|
||||||
|
slab->inuse -= cnt;
|
||||||
|
set_freepointer(s, tail, prior);
|
||||||
|
slab->freelist = head;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the slab is empty, and node's partial list is full,
|
||||||
|
* it should be discarded anyway no matter it's on full or
|
||||||
|
* partial list.
|
||||||
|
*/
|
||||||
|
if (slab->inuse == 0 && n->nr_partial >= s->min_partial)
|
||||||
|
slab_free = slab;
|
||||||
|
|
||||||
|
if (!prior) {
|
||||||
|
/* was on full list */
|
||||||
|
remove_full(s, n, slab);
|
||||||
|
if (!slab_free) {
|
||||||
|
add_partial(n, slab, DEACTIVATE_TO_TAIL);
|
||||||
|
stat(s, FREE_ADD_PARTIAL);
|
||||||
|
}
|
||||||
|
} else if (slab_free) {
|
||||||
|
remove_partial(n, slab);
|
||||||
|
stat(s, FREE_REMOVE_PARTIAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slab_free) {
|
||||||
|
/*
|
||||||
|
* Update the counters while still holding n->list_lock to
|
||||||
|
* prevent spurious validation warnings
|
||||||
|
*/
|
||||||
|
dec_slabs_node(s, slab_nid(slab_free), slab_free->objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&n->list_lock, flags);
|
||||||
|
|
||||||
|
if (slab_free) {
|
||||||
|
stat(s, FREE_SLAB);
|
||||||
|
free_slab(s, slab_free);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Slow path handling. This may still be called frequently since objects
|
* Slow path handling. This may still be called frequently since objects
|
||||||
* have a longer lifetime than the cpu slabs in most processing loads.
|
* have a longer lifetime than the cpu slabs in most processing loads.
|
||||||
|
@ -3508,8 +3587,8 @@ static void __slab_free(struct kmem_cache *s, struct slab *slab,
|
||||||
if (kfence_free(head))
|
if (kfence_free(head))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (kmem_cache_debug(s)) {
|
if (IS_ENABLED(CONFIG_SLUB_TINY) || kmem_cache_debug(s)) {
|
||||||
free_debug_processing(s, slab, head, tail, cnt, addr);
|
free_to_partial_list(s, slab, head, tail, cnt, addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3609,6 +3688,7 @@ slab_empty:
|
||||||
discard_slab(s, slab);
|
discard_slab(s, slab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
/*
|
/*
|
||||||
* Fastpath with forced inlining to produce a kfree and kmem_cache_free that
|
* Fastpath with forced inlining to produce a kfree and kmem_cache_free that
|
||||||
* can perform fastpath freeing without additional function calls.
|
* can perform fastpath freeing without additional function calls.
|
||||||
|
@ -3683,8 +3763,18 @@ redo:
|
||||||
}
|
}
|
||||||
stat(s, FREE_FASTPATH);
|
stat(s, FREE_FASTPATH);
|
||||||
}
|
}
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
void *tail_obj = tail ? : head;
|
||||||
|
|
||||||
static __always_inline void slab_free(struct kmem_cache *s, struct slab *slab,
|
__slab_free(s, slab, head, tail_obj, cnt, addr);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SLUB_TINY */
|
||||||
|
|
||||||
|
static __fastpath_inline void slab_free(struct kmem_cache *s, struct slab *slab,
|
||||||
void *head, void *tail, void **p, int cnt,
|
void *head, void *tail, void **p, int cnt,
|
||||||
unsigned long addr)
|
unsigned long addr)
|
||||||
{
|
{
|
||||||
|
@ -3817,18 +3907,13 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kmem_cache_free_bulk);
|
EXPORT_SYMBOL(kmem_cache_free_bulk);
|
||||||
|
|
||||||
/* Note that interrupts must be enabled when calling this function. */
|
#ifndef CONFIG_SLUB_TINY
|
||||||
int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
|
static inline int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags,
|
||||||
void **p)
|
size_t size, void **p, struct obj_cgroup *objcg)
|
||||||
{
|
{
|
||||||
struct kmem_cache_cpu *c;
|
struct kmem_cache_cpu *c;
|
||||||
int i;
|
int i;
|
||||||
struct obj_cgroup *objcg = NULL;
|
|
||||||
|
|
||||||
/* memcg and kmem_cache debug support */
|
|
||||||
s = slab_pre_alloc_hook(s, NULL, &objcg, size, flags);
|
|
||||||
if (unlikely(!s))
|
|
||||||
return false;
|
|
||||||
/*
|
/*
|
||||||
* Drain objects in the per cpu slab, while disabling local
|
* Drain objects in the per cpu slab, while disabling local
|
||||||
* IRQs, which protects against PREEMPT and interrupts
|
* IRQs, which protects against PREEMPT and interrupts
|
||||||
|
@ -3882,18 +3967,71 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
|
||||||
local_unlock_irq(&s->cpu_slab->lock);
|
local_unlock_irq(&s->cpu_slab->lock);
|
||||||
slub_put_cpu_ptr(s->cpu_slab);
|
slub_put_cpu_ptr(s->cpu_slab);
|
||||||
|
|
||||||
/*
|
|
||||||
* memcg and kmem_cache debug support and memory initialization.
|
|
||||||
* Done outside of the IRQ disabled fastpath loop.
|
|
||||||
*/
|
|
||||||
slab_post_alloc_hook(s, objcg, flags, size, p,
|
|
||||||
slab_want_init_on_alloc(flags, s), s->object_size);
|
|
||||||
return i;
|
return i;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
slub_put_cpu_ptr(s->cpu_slab);
|
slub_put_cpu_ptr(s->cpu_slab);
|
||||||
slab_post_alloc_hook(s, objcg, flags, i, p, false, s->object_size);
|
slab_post_alloc_hook(s, objcg, flags, i, p, false, s->object_size);
|
||||||
kmem_cache_free_bulk(s, i, p);
|
kmem_cache_free_bulk(s, i, p);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
#else /* CONFIG_SLUB_TINY */
|
||||||
|
static int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags,
|
||||||
|
size_t size, void **p, struct obj_cgroup *objcg)
|
||||||
|
{
|
||||||
|
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:
|
||||||
|
slab_post_alloc_hook(s, objcg, flags, i, p, false, s->object_size);
|
||||||
|
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(struct kmem_cache *s, gfp_t flags, size_t size,
|
||||||
|
void **p)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct obj_cgroup *objcg = NULL;
|
||||||
|
|
||||||
|
if (!size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* memcg and kmem_cache debug support */
|
||||||
|
s = slab_pre_alloc_hook(s, NULL, &objcg, size, flags);
|
||||||
|
if (unlikely(!s))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
i = __kmem_cache_alloc_bulk(s, flags, size, p, objcg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memcg and kmem_cache debug support and memory initialization.
|
||||||
|
* Done outside of the IRQ disabled fastpath loop.
|
||||||
|
*/
|
||||||
|
if (i != 0)
|
||||||
|
slab_post_alloc_hook(s, objcg, flags, size, p,
|
||||||
|
slab_want_init_on_alloc(flags, s), s->object_size);
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kmem_cache_alloc_bulk);
|
EXPORT_SYMBOL(kmem_cache_alloc_bulk);
|
||||||
|
|
||||||
|
@ -3918,7 +4056,8 @@ EXPORT_SYMBOL(kmem_cache_alloc_bulk);
|
||||||
* take the list_lock.
|
* take the list_lock.
|
||||||
*/
|
*/
|
||||||
static unsigned int slub_min_order;
|
static unsigned int slub_min_order;
|
||||||
static unsigned int slub_max_order = PAGE_ALLOC_COSTLY_ORDER;
|
static unsigned int slub_max_order =
|
||||||
|
IS_ENABLED(CONFIG_SLUB_TINY) ? 1 : PAGE_ALLOC_COSTLY_ORDER;
|
||||||
static unsigned int slub_min_objects;
|
static unsigned int slub_min_objects;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4049,6 +4188,7 @@ init_kmem_cache_node(struct kmem_cache_node *n)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
|
static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
|
||||||
{
|
{
|
||||||
BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
|
BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
|
||||||
|
@ -4069,6 +4209,12 @@ static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SLUB_TINY */
|
||||||
|
|
||||||
static struct kmem_cache *kmem_cache_node;
|
static struct kmem_cache *kmem_cache_node;
|
||||||
|
|
||||||
|
@ -4131,7 +4277,9 @@ static void free_kmem_cache_nodes(struct kmem_cache *s)
|
||||||
void __kmem_cache_release(struct kmem_cache *s)
|
void __kmem_cache_release(struct kmem_cache *s)
|
||||||
{
|
{
|
||||||
cache_random_seq_destroy(s);
|
cache_random_seq_destroy(s);
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
free_percpu(s->cpu_slab);
|
free_percpu(s->cpu_slab);
|
||||||
|
#endif
|
||||||
free_kmem_cache_nodes(s);
|
free_kmem_cache_nodes(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4909,8 +5057,10 @@ void __init kmem_cache_init(void)
|
||||||
|
|
||||||
void __init kmem_cache_init_late(void)
|
void __init kmem_cache_init_late(void)
|
||||||
{
|
{
|
||||||
|
#ifndef CONFIG_SLUB_TINY
|
||||||
flushwq = alloc_workqueue("slub_flushwq", WQ_MEM_RECLAIM, 0);
|
flushwq = alloc_workqueue("slub_flushwq", WQ_MEM_RECLAIM, 0);
|
||||||
WARN_ON(!flushwq);
|
WARN_ON(!flushwq);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct kmem_cache *
|
struct kmem_cache *
|
||||||
|
@ -4961,7 +5111,7 @@ int __kmem_cache_create(struct kmem_cache *s, slab_flags_t flags)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef SLAB_SUPPORTS_SYSFS
|
||||||
static int count_inuse(struct slab *slab)
|
static int count_inuse(struct slab *slab)
|
||||||
{
|
{
|
||||||
return slab->inuse;
|
return slab->inuse;
|
||||||
|
@ -5219,7 +5369,7 @@ static void process_slab(struct loc_track *t, struct kmem_cache *s,
|
||||||
#endif /* CONFIG_DEBUG_FS */
|
#endif /* CONFIG_DEBUG_FS */
|
||||||
#endif /* CONFIG_SLUB_DEBUG */
|
#endif /* CONFIG_SLUB_DEBUG */
|
||||||
|
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef SLAB_SUPPORTS_SYSFS
|
||||||
enum slab_stat_type {
|
enum slab_stat_type {
|
||||||
SL_ALL, /* All slabs */
|
SL_ALL, /* All slabs */
|
||||||
SL_PARTIAL, /* Only partially allocated slabs */
|
SL_PARTIAL, /* Only partially allocated slabs */
|
||||||
|
@ -5539,11 +5689,13 @@ static ssize_t cache_dma_show(struct kmem_cache *s, char *buf)
|
||||||
SLAB_ATTR_RO(cache_dma);
|
SLAB_ATTR_RO(cache_dma);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_HARDENED_USERCOPY
|
||||||
static ssize_t usersize_show(struct kmem_cache *s, char *buf)
|
static ssize_t usersize_show(struct kmem_cache *s, char *buf)
|
||||||
{
|
{
|
||||||
return sysfs_emit(buf, "%u\n", s->usersize);
|
return sysfs_emit(buf, "%u\n", s->usersize);
|
||||||
}
|
}
|
||||||
SLAB_ATTR_RO(usersize);
|
SLAB_ATTR_RO(usersize);
|
||||||
|
#endif
|
||||||
|
|
||||||
static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
|
static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
|
||||||
{
|
{
|
||||||
|
@ -5854,7 +6006,9 @@ static struct attribute *slab_attrs[] = {
|
||||||
#ifdef CONFIG_FAILSLAB
|
#ifdef CONFIG_FAILSLAB
|
||||||
&failslab_attr.attr,
|
&failslab_attr.attr,
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_HARDENED_USERCOPY
|
||||||
&usersize_attr.attr,
|
&usersize_attr.attr,
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_KFENCE
|
#ifdef CONFIG_KFENCE
|
||||||
&skip_kfence_attr.attr,
|
&skip_kfence_attr.attr,
|
||||||
#endif
|
#endif
|
||||||
|
@ -6101,7 +6255,7 @@ static int __init slab_sysfs_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
late_initcall(slab_sysfs_init);
|
late_initcall(slab_sysfs_init);
|
||||||
#endif /* CONFIG_SYSFS */
|
#endif /* SLAB_SUPPORTS_SYSFS */
|
||||||
|
|
||||||
#if defined(CONFIG_SLUB_DEBUG) && defined(CONFIG_DEBUG_FS)
|
#if defined(CONFIG_SLUB_DEBUG) && defined(CONFIG_DEBUG_FS)
|
||||||
static int slab_debugfs_show(struct seq_file *seq, void *v)
|
static int slab_debugfs_show(struct seq_file *seq, void *v)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче