Skip to content

Commit 21c690a

Browse files
surenbaghdasaryanakpm00
authored andcommitted
mm: introduce slabobj_ext to support slab object extensions
Currently slab pages can store only vectors of obj_cgroup pointers in page->memcg_data. Introduce slabobj_ext structure to allow more data to be stored for each slab object. Wrap obj_cgroup into slabobj_ext to support current functionality while allowing to extend slabobj_ext in the future. Link: https://lkml.kernel.org/r/20240321163705.3067592-7-surenb@google.com Signed-off-by: Suren Baghdasaryan <surenb@google.com> Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com> Reviewed-by: Vlastimil Babka <vbabka@suse.cz> Tested-by: Kees Cook <keescook@chromium.org> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Alex Gaynor <alex.gaynor@gmail.com> Cc: Alice Ryhl <aliceryhl@google.com> Cc: Andreas Hindborg <a.hindborg@samsung.com> Cc: Benno Lossin <benno.lossin@proton.me> Cc: "Björn Roy Baron" <bjorn3_gh@protonmail.com> Cc: Boqun Feng <boqun.feng@gmail.com> Cc: Christoph Lameter <cl@linux.com> Cc: Dennis Zhou <dennis@kernel.org> Cc: Gary Guo <gary@garyguo.net> Cc: Kent Overstreet <kent.overstreet@linux.dev> Cc: Miguel Ojeda <ojeda@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Tejun Heo <tj@kernel.org> Cc: Wedson Almeida Filho <wedsonaf@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent a567411 commit 21c690a

File tree

9 files changed

+145
-112
lines changed

9 files changed

+145
-112
lines changed

include/linux/memcontrol.h

+14-6
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,8 @@ struct mem_cgroup {
349349
extern struct mem_cgroup *root_mem_cgroup;
350350

351351
enum page_memcg_data_flags {
352-
/* page->memcg_data is a pointer to an objcgs vector */
353-
MEMCG_DATA_OBJCGS = (1UL << 0),
352+
/* page->memcg_data is a pointer to an slabobj_ext vector */
353+
MEMCG_DATA_OBJEXTS = (1UL << 0),
354354
/* page has been accounted as a non-slab kernel page */
355355
MEMCG_DATA_KMEM = (1UL << 1),
356356
/* the next bit after the last actual flag */
@@ -388,7 +388,7 @@ static inline struct mem_cgroup *__folio_memcg(struct folio *folio)
388388
unsigned long memcg_data = folio->memcg_data;
389389

390390
VM_BUG_ON_FOLIO(folio_test_slab(folio), folio);
391-
VM_BUG_ON_FOLIO(memcg_data & MEMCG_DATA_OBJCGS, folio);
391+
VM_BUG_ON_FOLIO(memcg_data & MEMCG_DATA_OBJEXTS, folio);
392392
VM_BUG_ON_FOLIO(memcg_data & MEMCG_DATA_KMEM, folio);
393393

394394
return (struct mem_cgroup *)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
@@ -409,7 +409,7 @@ static inline struct obj_cgroup *__folio_objcg(struct folio *folio)
409409
unsigned long memcg_data = folio->memcg_data;
410410

411411
VM_BUG_ON_FOLIO(folio_test_slab(folio), folio);
412-
VM_BUG_ON_FOLIO(memcg_data & MEMCG_DATA_OBJCGS, folio);
412+
VM_BUG_ON_FOLIO(memcg_data & MEMCG_DATA_OBJEXTS, folio);
413413
VM_BUG_ON_FOLIO(!(memcg_data & MEMCG_DATA_KMEM), folio);
414414

415415
return (struct obj_cgroup *)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
@@ -506,7 +506,7 @@ static inline struct mem_cgroup *folio_memcg_check(struct folio *folio)
506506
*/
507507
unsigned long memcg_data = READ_ONCE(folio->memcg_data);
508508

509-
if (memcg_data & MEMCG_DATA_OBJCGS)
509+
if (memcg_data & MEMCG_DATA_OBJEXTS)
510510
return NULL;
511511

512512
if (memcg_data & MEMCG_DATA_KMEM) {
@@ -552,7 +552,7 @@ static inline struct mem_cgroup *get_mem_cgroup_from_objcg(struct obj_cgroup *ob
552552
static inline bool folio_memcg_kmem(struct folio *folio)
553553
{
554554
VM_BUG_ON_PGFLAGS(PageTail(&folio->page), &folio->page);
555-
VM_BUG_ON_FOLIO(folio->memcg_data & MEMCG_DATA_OBJCGS, folio);
555+
VM_BUG_ON_FOLIO(folio->memcg_data & MEMCG_DATA_OBJEXTS, folio);
556556
return folio->memcg_data & MEMCG_DATA_KMEM;
557557
}
558558

@@ -1633,6 +1633,14 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
16331633
}
16341634
#endif /* CONFIG_MEMCG */
16351635

1636+
/*
1637+
* Extended information for slab objects stored as an array in page->memcg_data
1638+
* if MEMCG_DATA_OBJEXTS is set.
1639+
*/
1640+
struct slabobj_ext {
1641+
struct obj_cgroup *objcg;
1642+
} __aligned(8);
1643+
16361644
static inline void __inc_lruvec_kmem_state(void *p, enum node_stat_item idx)
16371645
{
16381646
__mod_lruvec_kmem_state(p, idx, 1);

include/linux/mm_types.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ struct page {
169169
/* Usage count. *DO NOT USE DIRECTLY*. See page_ref.h */
170170
atomic_t _refcount;
171171

172-
#ifdef CONFIG_MEMCG
172+
#ifdef CONFIG_SLAB_OBJ_EXT
173173
unsigned long memcg_data;
174174
#endif
175175

@@ -331,7 +331,7 @@ struct folio {
331331
};
332332
atomic_t _mapcount;
333333
atomic_t _refcount;
334-
#ifdef CONFIG_MEMCG
334+
#ifdef CONFIG_SLAB_OBJ_EXT
335335
unsigned long memcg_data;
336336
#endif
337337
#if defined(WANT_PAGE_VIRTUAL)

init/Kconfig

+4
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,9 @@ config NUMA_BALANCING_DEFAULT_ENABLED
929929
If set, automatic NUMA balancing will be enabled if running on a NUMA
930930
machine.
931931

932+
config SLAB_OBJ_EXT
933+
bool
934+
932935
menuconfig CGROUPS
933936
bool "Control Group support"
934937
select KERNFS
@@ -962,6 +965,7 @@ config MEMCG
962965
bool "Memory controller"
963966
select PAGE_COUNTER
964967
select EVENTFD
968+
select SLAB_OBJ_EXT
965969
help
966970
Provides control over the memory footprint of tasks in a cgroup.
967971

mm/kfence/core.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -595,9 +595,9 @@ static unsigned long kfence_init_pool(void)
595595
continue;
596596

597597
__folio_set_slab(slab_folio(slab));
598-
#ifdef CONFIG_MEMCG
599-
slab->memcg_data = (unsigned long)&kfence_metadata_init[i / 2 - 1].objcg |
600-
MEMCG_DATA_OBJCGS;
598+
#ifdef CONFIG_MEMCG_KMEM
599+
slab->obj_exts = (unsigned long)&kfence_metadata_init[i / 2 - 1].obj_exts |
600+
MEMCG_DATA_OBJEXTS;
601601
#endif
602602
}
603603

@@ -645,8 +645,8 @@ static unsigned long kfence_init_pool(void)
645645

646646
if (!i || (i % 2))
647647
continue;
648-
#ifdef CONFIG_MEMCG
649-
slab->memcg_data = 0;
648+
#ifdef CONFIG_MEMCG_KMEM
649+
slab->obj_exts = 0;
650650
#endif
651651
__folio_clear_slab(slab_folio(slab));
652652
}
@@ -1139,8 +1139,8 @@ void __kfence_free(void *addr)
11391139
{
11401140
struct kfence_metadata *meta = addr_to_metadata((unsigned long)addr);
11411141

1142-
#ifdef CONFIG_MEMCG
1143-
KFENCE_WARN_ON(meta->objcg);
1142+
#ifdef CONFIG_MEMCG_KMEM
1143+
KFENCE_WARN_ON(meta->obj_exts.objcg);
11441144
#endif
11451145
/*
11461146
* If the objects of the cache are SLAB_TYPESAFE_BY_RCU, defer freeing

mm/kfence/kfence.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ struct kfence_metadata {
9797
struct kfence_track free_track;
9898
/* For updating alloc_covered on frees. */
9999
u32 alloc_stack_hash;
100-
#ifdef CONFIG_MEMCG
101-
struct obj_cgroup *objcg;
100+
#ifdef CONFIG_MEMCG_KMEM
101+
struct slabobj_ext obj_exts;
102102
#endif
103103
};
104104

mm/memcontrol.c

+7-49
Original file line numberDiff line numberDiff line change
@@ -2977,13 +2977,6 @@ void mem_cgroup_commit_charge(struct folio *folio, struct mem_cgroup *memcg)
29772977
}
29782978

29792979
#ifdef CONFIG_MEMCG_KMEM
2980-
/*
2981-
* The allocated objcg pointers array is not accounted directly.
2982-
* Moreover, it should not come from DMA buffer and is not readily
2983-
* reclaimable. So those GFP bits should be masked off.
2984-
*/
2985-
#define OBJCGS_CLEAR_MASK (__GFP_DMA | __GFP_RECLAIMABLE | \
2986-
__GFP_ACCOUNT | __GFP_NOFAIL)
29872980

29882981
/*
29892982
* mod_objcg_mlstate() may be called with irq enabled, so
@@ -3003,70 +2996,35 @@ static inline void mod_objcg_mlstate(struct obj_cgroup *objcg,
30032996
rcu_read_unlock();
30042997
}
30052998

3006-
int memcg_alloc_slab_cgroups(struct slab *slab, struct kmem_cache *s,
3007-
gfp_t gfp, bool new_slab)
3008-
{
3009-
unsigned int objects = objs_per_slab(s, slab);
3010-
unsigned long memcg_data;
3011-
void *vec;
3012-
3013-
gfp &= ~OBJCGS_CLEAR_MASK;
3014-
vec = kcalloc_node(objects, sizeof(struct obj_cgroup *), gfp,
3015-
slab_nid(slab));
3016-
if (!vec)
3017-
return -ENOMEM;
3018-
3019-
memcg_data = (unsigned long) vec | MEMCG_DATA_OBJCGS;
3020-
if (new_slab) {
3021-
/*
3022-
* If the slab is brand new and nobody can yet access its
3023-
* memcg_data, no synchronization is required and memcg_data can
3024-
* be simply assigned.
3025-
*/
3026-
slab->memcg_data = memcg_data;
3027-
} else if (cmpxchg(&slab->memcg_data, 0, memcg_data)) {
3028-
/*
3029-
* If the slab is already in use, somebody can allocate and
3030-
* assign obj_cgroups in parallel. In this case the existing
3031-
* objcg vector should be reused.
3032-
*/
3033-
kfree(vec);
3034-
return 0;
3035-
}
3036-
3037-
kmemleak_not_leak(vec);
3038-
return 0;
3039-
}
3040-
30412999
static __always_inline
30423000
struct mem_cgroup *mem_cgroup_from_obj_folio(struct folio *folio, void *p)
30433001
{
30443002
/*
30453003
* Slab objects are accounted individually, not per-page.
30463004
* Memcg membership data for each individual object is saved in
3047-
* slab->memcg_data.
3005+
* slab->obj_exts.
30483006
*/
30493007
if (folio_test_slab(folio)) {
3050-
struct obj_cgroup **objcgs;
3008+
struct slabobj_ext *obj_exts;
30513009
struct slab *slab;
30523010
unsigned int off;
30533011

30543012
slab = folio_slab(folio);
3055-
objcgs = slab_objcgs(slab);
3056-
if (!objcgs)
3013+
obj_exts = slab_obj_exts(slab);
3014+
if (!obj_exts)
30573015
return NULL;
30583016

30593017
off = obj_to_index(slab->slab_cache, slab, p);
3060-
if (objcgs[off])
3061-
return obj_cgroup_memcg(objcgs[off]);
3018+
if (obj_exts[off].objcg)
3019+
return obj_cgroup_memcg(obj_exts[off].objcg);
30623020

30633021
return NULL;
30643022
}
30653023

30663024
/*
30673025
* folio_memcg_check() is used here, because in theory we can encounter
30683026
* a folio where the slab flag has been cleared already, but
3069-
* slab->memcg_data has not been freed yet
3027+
* slab->obj_exts has not been freed yet
30703028
* folio_memcg_check() will guarantee that a proper memory
30713029
* cgroup pointer or NULL will be returned.
30723030
*/

mm/page_owner.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
515515
if (!memcg_data)
516516
goto out_unlock;
517517

518-
if (memcg_data & MEMCG_DATA_OBJCGS)
518+
if (memcg_data & MEMCG_DATA_OBJEXTS)
519519
ret += scnprintf(kbuf + ret, count - ret,
520520
"Slab cache page\n");
521521

mm/slab.h

+27-25
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ struct slab {
8787
unsigned int __unused;
8888

8989
atomic_t __page_refcount;
90-
#ifdef CONFIG_MEMCG
91-
unsigned long memcg_data;
90+
#ifdef CONFIG_SLAB_OBJ_EXT
91+
unsigned long obj_exts;
9292
#endif
9393
};
9494

@@ -97,8 +97,8 @@ struct slab {
9797
SLAB_MATCH(flags, __page_flags);
9898
SLAB_MATCH(compound_head, slab_cache); /* Ensure bit 0 is clear */
9999
SLAB_MATCH(_refcount, __page_refcount);
100-
#ifdef CONFIG_MEMCG
101-
SLAB_MATCH(memcg_data, memcg_data);
100+
#ifdef CONFIG_SLAB_OBJ_EXT
101+
SLAB_MATCH(memcg_data, obj_exts);
102102
#endif
103103
#undef SLAB_MATCH
104104
static_assert(sizeof(struct slab) <= sizeof(struct page));
@@ -536,42 +536,44 @@ static inline bool kmem_cache_debug_flags(struct kmem_cache *s, slab_flags_t fla
536536
return false;
537537
}
538538

539-
#ifdef CONFIG_MEMCG_KMEM
539+
#ifdef CONFIG_SLAB_OBJ_EXT
540+
540541
/*
541-
* slab_objcgs - get the object cgroups vector associated with a slab
542+
* slab_obj_exts - get the pointer to the slab object extension vector
543+
* associated with a slab.
542544
* @slab: a pointer to the slab struct
543545
*
544-
* Returns a pointer to the object cgroups vector associated with the slab,
546+
* Returns a pointer to the object extension vector associated with the slab,
545547
* or NULL if no such vector has been associated yet.
546548
*/
547-
static inline struct obj_cgroup **slab_objcgs(struct slab *slab)
549+
static inline struct slabobj_ext *slab_obj_exts(struct slab *slab)
548550
{
549-
unsigned long memcg_data = READ_ONCE(slab->memcg_data);
551+
unsigned long obj_exts = READ_ONCE(slab->obj_exts);
550552

551-
VM_BUG_ON_PAGE(memcg_data && !(memcg_data & MEMCG_DATA_OBJCGS),
553+
#ifdef CONFIG_MEMCG
554+
VM_BUG_ON_PAGE(obj_exts && !(obj_exts & MEMCG_DATA_OBJEXTS),
552555
slab_page(slab));
553-
VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, slab_page(slab));
556+
VM_BUG_ON_PAGE(obj_exts & MEMCG_DATA_KMEM, slab_page(slab));
554557

555-
return (struct obj_cgroup **)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
558+
return (struct slabobj_ext *)(obj_exts & ~MEMCG_DATA_FLAGS_MASK);
559+
#else
560+
return (struct slabobj_ext *)obj_exts;
561+
#endif
556562
}
557563

558-
int memcg_alloc_slab_cgroups(struct slab *slab, struct kmem_cache *s,
559-
gfp_t gfp, bool new_slab);
560-
void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
561-
enum node_stat_item idx, int nr);
562-
#else /* CONFIG_MEMCG_KMEM */
563-
static inline struct obj_cgroup **slab_objcgs(struct slab *slab)
564+
#else /* CONFIG_SLAB_OBJ_EXT */
565+
566+
static inline struct slabobj_ext *slab_obj_exts(struct slab *slab)
564567
{
565568
return NULL;
566569
}
567570

568-
static inline int memcg_alloc_slab_cgroups(struct slab *slab,
569-
struct kmem_cache *s, gfp_t gfp,
570-
bool new_slab)
571-
{
572-
return 0;
573-
}
574-
#endif /* CONFIG_MEMCG_KMEM */
571+
#endif /* CONFIG_SLAB_OBJ_EXT */
572+
573+
#ifdef CONFIG_MEMCG_KMEM
574+
void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
575+
enum node_stat_item idx, int nr);
576+
#endif
575577

576578
size_t __ksize(const void *objp);
577579

0 commit comments

Comments
 (0)