Skip to content

Commit 4b5f8d9

Browse files
committed
mm/memcg: Convert slab objcgs from struct page to struct slab
page->memcg_data is used with MEMCG_DATA_OBJCGS flag only for slab pages so convert all the related infrastructure to struct slab. Also use struct folio instead of struct page when resolving object pointers. This is not just mechanistic changing of types and names. Now in mem_cgroup_from_obj() we use folio_test_slab() to decide if we interpret the folio as a real slab instead of a large kmalloc, instead of relying on MEMCG_DATA_OBJCGS bit that used to be checked in page_objcgs_check(). Similarly in memcg_slab_free_hook() where we can encounter kmalloc_large() pages (here the folio slab flag check is implied by virt_to_slab()). As a result, page_objcgs_check() can be dropped instead of converted. To avoid include cycles, move the inline definition of slab_objcgs() from memcontrol.h to mm/slab.h. Signed-off-by: Vlastimil Babka <[email protected]> Reviewed-by: Roman Gushchin <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Vladimir Davydov <[email protected]> Cc: <[email protected]>
1 parent 40f3bf0 commit 4b5f8d9

File tree

3 files changed

+80
-96
lines changed

3 files changed

+80
-96
lines changed

include/linux/memcontrol.h

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -536,61 +536,13 @@ static inline bool folio_memcg_kmem(struct folio *folio)
536536
return folio->memcg_data & MEMCG_DATA_KMEM;
537537
}
538538

539-
/*
540-
* page_objcgs - get the object cgroups vector associated with a page
541-
* @page: a pointer to the page struct
542-
*
543-
* Returns a pointer to the object cgroups vector associated with the page,
544-
* or NULL. This function assumes that the page is known to have an
545-
* associated object cgroups vector. It's not safe to call this function
546-
* against pages, which might have an associated memory cgroup: e.g.
547-
* kernel stack pages.
548-
*/
549-
static inline struct obj_cgroup **page_objcgs(struct page *page)
550-
{
551-
unsigned long memcg_data = READ_ONCE(page->memcg_data);
552-
553-
VM_BUG_ON_PAGE(memcg_data && !(memcg_data & MEMCG_DATA_OBJCGS), page);
554-
VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, page);
555-
556-
return (struct obj_cgroup **)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
557-
}
558-
559-
/*
560-
* page_objcgs_check - get the object cgroups vector associated with a page
561-
* @page: a pointer to the page struct
562-
*
563-
* Returns a pointer to the object cgroups vector associated with the page,
564-
* or NULL. This function is safe to use if the page can be directly associated
565-
* with a memory cgroup.
566-
*/
567-
static inline struct obj_cgroup **page_objcgs_check(struct page *page)
568-
{
569-
unsigned long memcg_data = READ_ONCE(page->memcg_data);
570-
571-
if (!memcg_data || !(memcg_data & MEMCG_DATA_OBJCGS))
572-
return NULL;
573-
574-
VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, page);
575-
576-
return (struct obj_cgroup **)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
577-
}
578539

579540
#else
580541
static inline bool folio_memcg_kmem(struct folio *folio)
581542
{
582543
return false;
583544
}
584545

585-
static inline struct obj_cgroup **page_objcgs(struct page *page)
586-
{
587-
return NULL;
588-
}
589-
590-
static inline struct obj_cgroup **page_objcgs_check(struct page *page)
591-
{
592-
return NULL;
593-
}
594546
#endif
595547

596548
static inline bool PageMemcgKmem(struct page *page)

mm/memcontrol.c

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2816,31 +2816,31 @@ static inline void mod_objcg_mlstate(struct obj_cgroup *objcg,
28162816
rcu_read_unlock();
28172817
}
28182818

2819-
int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
2820-
gfp_t gfp, bool new_page)
2819+
int memcg_alloc_slab_cgroups(struct slab *slab, struct kmem_cache *s,
2820+
gfp_t gfp, bool new_slab)
28212821
{
2822-
unsigned int objects = objs_per_slab(s, page_slab(page));
2822+
unsigned int objects = objs_per_slab(s, slab);
28232823
unsigned long memcg_data;
28242824
void *vec;
28252825

28262826
gfp &= ~OBJCGS_CLEAR_MASK;
28272827
vec = kcalloc_node(objects, sizeof(struct obj_cgroup *), gfp,
2828-
page_to_nid(page));
2828+
slab_nid(slab));
28292829
if (!vec)
28302830
return -ENOMEM;
28312831

28322832
memcg_data = (unsigned long) vec | MEMCG_DATA_OBJCGS;
2833-
if (new_page) {
2833+
if (new_slab) {
28342834
/*
2835-
* If the slab page is brand new and nobody can yet access
2836-
* it's memcg_data, no synchronization is required and
2837-
* memcg_data can be simply assigned.
2835+
* If the slab is brand new and nobody can yet access its
2836+
* memcg_data, no synchronization is required and memcg_data can
2837+
* be simply assigned.
28382838
*/
2839-
page->memcg_data = memcg_data;
2840-
} else if (cmpxchg(&page->memcg_data, 0, memcg_data)) {
2839+
slab->memcg_data = memcg_data;
2840+
} else if (cmpxchg(&slab->memcg_data, 0, memcg_data)) {
28412841
/*
2842-
* If the slab page is already in use, somebody can allocate
2843-
* and assign obj_cgroups in parallel. In this case the existing
2842+
* If the slab is already in use, somebody can allocate and
2843+
* assign obj_cgroups in parallel. In this case the existing
28442844
* objcg vector should be reused.
28452845
*/
28462846
kfree(vec);
@@ -2865,38 +2865,43 @@ int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
28652865
*/
28662866
struct mem_cgroup *mem_cgroup_from_obj(void *p)
28672867
{
2868-
struct page *page;
2868+
struct folio *folio;
28692869

28702870
if (mem_cgroup_disabled())
28712871
return NULL;
28722872

2873-
page = virt_to_head_page(p);
2873+
folio = virt_to_folio(p);
28742874

28752875
/*
28762876
* Slab objects are accounted individually, not per-page.
28772877
* Memcg membership data for each individual object is saved in
2878-
* the page->obj_cgroups.
2878+
* slab->memcg_data.
28792879
*/
2880-
if (page_objcgs_check(page)) {
2881-
struct obj_cgroup *objcg;
2880+
if (folio_test_slab(folio)) {
2881+
struct obj_cgroup **objcgs;
2882+
struct slab *slab;
28822883
unsigned int off;
28832884

2884-
off = obj_to_index(page->slab_cache, page_slab(page), p);
2885-
objcg = page_objcgs(page)[off];
2886-
if (objcg)
2887-
return obj_cgroup_memcg(objcg);
2885+
slab = folio_slab(folio);
2886+
objcgs = slab_objcgs(slab);
2887+
if (!objcgs)
2888+
return NULL;
2889+
2890+
off = obj_to_index(slab->slab_cache, slab, p);
2891+
if (objcgs[off])
2892+
return obj_cgroup_memcg(objcgs[off]);
28882893

28892894
return NULL;
28902895
}
28912896

28922897
/*
2893-
* page_memcg_check() is used here, because page_has_obj_cgroups()
2894-
* check above could fail because the object cgroups vector wasn't set
2895-
* at that moment, but it can be set concurrently.
2898+
* page_memcg_check() is used here, because in theory we can encounter
2899+
* a folio where the slab flag has been cleared already, but
2900+
* slab->memcg_data has not been freed yet
28962901
* page_memcg_check(page) will guarantee that a proper memory
28972902
* cgroup pointer or NULL will be returned.
28982903
*/
2899-
return page_memcg_check(page);
2904+
return page_memcg_check(folio_page(folio, 0));
29002905
}
29012906

29022907
__always_inline struct obj_cgroup *get_obj_cgroup_from_current(void)

mm/slab.h

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -412,15 +412,33 @@ static inline bool kmem_cache_debug_flags(struct kmem_cache *s, slab_flags_t fla
412412
}
413413

414414
#ifdef CONFIG_MEMCG_KMEM
415-
int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s,
416-
gfp_t gfp, bool new_page);
415+
/*
416+
* slab_objcgs - get the object cgroups vector associated with a slab
417+
* @slab: a pointer to the slab struct
418+
*
419+
* Returns a pointer to the object cgroups vector associated with the slab,
420+
* or NULL if no such vector has been associated yet.
421+
*/
422+
static inline struct obj_cgroup **slab_objcgs(struct slab *slab)
423+
{
424+
unsigned long memcg_data = READ_ONCE(slab->memcg_data);
425+
426+
VM_BUG_ON_PAGE(memcg_data && !(memcg_data & MEMCG_DATA_OBJCGS),
427+
slab_page(slab));
428+
VM_BUG_ON_PAGE(memcg_data & MEMCG_DATA_KMEM, slab_page(slab));
429+
430+
return (struct obj_cgroup **)(memcg_data & ~MEMCG_DATA_FLAGS_MASK);
431+
}
432+
433+
int memcg_alloc_slab_cgroups(struct slab *slab, struct kmem_cache *s,
434+
gfp_t gfp, bool new_slab);
417435
void mod_objcg_state(struct obj_cgroup *objcg, struct pglist_data *pgdat,
418436
enum node_stat_item idx, int nr);
419437

420-
static inline void memcg_free_page_obj_cgroups(struct page *page)
438+
static inline void memcg_free_slab_cgroups(struct slab *slab)
421439
{
422-
kfree(page_objcgs(page));
423-
page->memcg_data = 0;
440+
kfree(slab_objcgs(slab));
441+
slab->memcg_data = 0;
424442
}
425443

426444
static inline size_t obj_full_size(struct kmem_cache *s)
@@ -465,7 +483,7 @@ static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
465483
gfp_t flags, size_t size,
466484
void **p)
467485
{
468-
struct page *page;
486+
struct slab *slab;
469487
unsigned long off;
470488
size_t i;
471489

@@ -474,19 +492,19 @@ static inline void memcg_slab_post_alloc_hook(struct kmem_cache *s,
474492

475493
for (i = 0; i < size; i++) {
476494
if (likely(p[i])) {
477-
page = virt_to_head_page(p[i]);
495+
slab = virt_to_slab(p[i]);
478496

479-
if (!page_objcgs(page) &&
480-
memcg_alloc_page_obj_cgroups(page, s, flags,
497+
if (!slab_objcgs(slab) &&
498+
memcg_alloc_slab_cgroups(slab, s, flags,
481499
false)) {
482500
obj_cgroup_uncharge(objcg, obj_full_size(s));
483501
continue;
484502
}
485503

486-
off = obj_to_index(s, page_slab(page), p[i]);
504+
off = obj_to_index(s, slab, p[i]);
487505
obj_cgroup_get(objcg);
488-
page_objcgs(page)[off] = objcg;
489-
mod_objcg_state(objcg, page_pgdat(page),
506+
slab_objcgs(slab)[off] = objcg;
507+
mod_objcg_state(objcg, slab_pgdat(slab),
490508
cache_vmstat_idx(s), obj_full_size(s));
491509
} else {
492510
obj_cgroup_uncharge(objcg, obj_full_size(s));
@@ -501,7 +519,7 @@ static inline void memcg_slab_free_hook(struct kmem_cache *s_orig,
501519
struct kmem_cache *s;
502520
struct obj_cgroup **objcgs;
503521
struct obj_cgroup *objcg;
504-
struct page *page;
522+
struct slab *slab;
505523
unsigned int off;
506524
int i;
507525

@@ -512,43 +530,52 @@ static inline void memcg_slab_free_hook(struct kmem_cache *s_orig,
512530
if (unlikely(!p[i]))
513531
continue;
514532

515-
page = virt_to_head_page(p[i]);
516-
objcgs = page_objcgs_check(page);
533+
slab = virt_to_slab(p[i]);
534+
/* we could be given a kmalloc_large() object, skip those */
535+
if (!slab)
536+
continue;
537+
538+
objcgs = slab_objcgs(slab);
517539
if (!objcgs)
518540
continue;
519541

520542
if (!s_orig)
521-
s = page->slab_cache;
543+
s = slab->slab_cache;
522544
else
523545
s = s_orig;
524546

525-
off = obj_to_index(s, page_slab(page), p[i]);
547+
off = obj_to_index(s, slab, p[i]);
526548
objcg = objcgs[off];
527549
if (!objcg)
528550
continue;
529551

530552
objcgs[off] = NULL;
531553
obj_cgroup_uncharge(objcg, obj_full_size(s));
532-
mod_objcg_state(objcg, page_pgdat(page), cache_vmstat_idx(s),
554+
mod_objcg_state(objcg, slab_pgdat(slab), cache_vmstat_idx(s),
533555
-obj_full_size(s));
534556
obj_cgroup_put(objcg);
535557
}
536558
}
537559

538560
#else /* CONFIG_MEMCG_KMEM */
561+
static inline struct obj_cgroup **slab_objcgs(struct slab *slab)
562+
{
563+
return NULL;
564+
}
565+
539566
static inline struct mem_cgroup *memcg_from_slab_obj(void *ptr)
540567
{
541568
return NULL;
542569
}
543570

544-
static inline int memcg_alloc_page_obj_cgroups(struct page *page,
571+
static inline int memcg_alloc_slab_cgroups(struct slab *slab,
545572
struct kmem_cache *s, gfp_t gfp,
546-
bool new_page)
573+
bool new_slab)
547574
{
548575
return 0;
549576
}
550577

551-
static inline void memcg_free_page_obj_cgroups(struct page *page)
578+
static inline void memcg_free_slab_cgroups(struct slab *slab)
552579
{
553580
}
554581

@@ -587,7 +614,7 @@ static __always_inline void account_slab(struct slab *slab, int order,
587614
struct kmem_cache *s, gfp_t gfp)
588615
{
589616
if (memcg_kmem_enabled() && (s->flags & SLAB_ACCOUNT))
590-
memcg_alloc_page_obj_cgroups(slab_page(slab), s, gfp, true);
617+
memcg_alloc_slab_cgroups(slab, s, gfp, true);
591618

592619
mod_node_page_state(slab_pgdat(slab), cache_vmstat_idx(s),
593620
PAGE_SIZE << order);
@@ -597,7 +624,7 @@ static __always_inline void unaccount_slab(struct slab *slab, int order,
597624
struct kmem_cache *s)
598625
{
599626
if (memcg_kmem_enabled())
600-
memcg_free_page_obj_cgroups(slab_page(slab));
627+
memcg_free_slab_cgroups(slab);
601628

602629
mod_node_page_state(slab_pgdat(slab), cache_vmstat_idx(s),
603630
-(PAGE_SIZE << order));

0 commit comments

Comments
 (0)