From bbaf879a418e2d02edb9916ba257f7e4aaa6b97c Mon Sep 17 00:00:00 2001 From: Tianchen Ding Date: Tue, 6 Feb 2024 10:23:42 +0800 Subject: [PATCH 1/2] anolis: mm/kidled: do not monitor kfence memory ANBZ: #8176 Since memory from kfence pool cannot be reclaimed, it is meaningless to scan the kfence pages. Mark them out of kidled available slab and prepare for the next patch that lets kfence free page->obj_cgroups. Signed-off-by: Tianchen Ding --- mm/kidled.c | 4 ++-- mm/memcontrol.c | 2 +- mm/slab.h | 10 +++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/mm/kidled.c b/mm/kidled.c index beb852a8638f..f0ad48deb491 100644 --- a/mm/kidled.c +++ b/mm/kidled.c @@ -963,7 +963,7 @@ static unsigned short *kidled_get_slab_age_array(void *object) unsigned int objects = objs_per_slab_page(page->slab_cache, page); unsigned short *slab_age = NULL; - if (!kidled_available_slab(page->slab_cache)) + if (!kidled_available_slab(page, page->slab_cache)) goto out; if (!cgroup_memory_nokmem) { @@ -1026,7 +1026,7 @@ int kidled_alloc_slab_age(struct page *page, struct kmem_cache *s, gfp_t flags) void *ver; int ret; - if (!kidled_available_slab(s)) + if (!kidled_available_slab(page, s)) return 0; /* void count the memory to kmem accounting when kmem enable */ diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 8fe3c898a578..be7ad9dfc63e 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3357,7 +3357,7 @@ int memcg_alloc_page_obj_cgroups(struct page *page, struct kmem_cache *s, void *vec; /* extra allocate an special pointer for cold slab */ - if (kidled_available_slab(s)) + if (kidled_available_slab(page, s)) objects += 1; gfp &= ~OBJCGS_CLEAR_MASK; diff --git a/mm/slab.h b/mm/slab.h index 255aa684f692..568762ba6f27 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -209,8 +209,12 @@ static inline int cache_vmstat_idx(struct kmem_cache *s) } #ifdef CONFIG_KIDLED -static inline bool kidled_available_slab(struct kmem_cache *s) +static inline bool kidled_available_slab(struct page *page, struct kmem_cache *s) { + /* Do not monitor kfence memory. */ + if (unlikely(PageKfence(page))) + return false; + if (!strcmp(s->name, "inode_cache") || !strcmp(s->name, "ext4_inode_cache") || !strcmp(s->name, "dentry")) @@ -225,7 +229,7 @@ static inline bool kidled_kmem_enabled(void) return !cgroup_memory_nokmem; } #else -static inline bool kidled_available_slab(struct kmem_cache *s) +static inline bool kidled_available_slab(struct page *page, struct kmem_cache *s) { return false; } @@ -289,7 +293,7 @@ static inline void memcg_free_page_obj_cgroups(struct page *page, struct kmem_ca { unsigned int objects = objs_per_slab_page(s, page); - if (kidled_available_slab(s)) { + if (kidled_available_slab(page, s)) { /* In case fail to allocate memory for cold slab */ if (likely(page_obj_cgroups(page))) kfree(page_obj_cgroups(page)[objects]); -- Gitee From 2be6a3138c5ea22f46169fb4b6310017eaa7557b Mon Sep 17 00:00:00 2001 From: Tianchen Ding Date: Tue, 6 Feb 2024 10:47:52 +0800 Subject: [PATCH 2/2] anolis: kfence: free obj_cgroups when allocating to page ANBZ: #8176 xuyu reports a bug when kmemcg is enabled: [ 272.696476] flags: 0x17fffe010001003(locked|referenced|reserved|kfence) [ 272.699713] page dumped because: VM_BUG_ON_PAGE(page->mem_cgroup) [ 272.700631] page->mem_cgroup:ffffa02000b841b1 [ 272.701312] ------------[ cut here ]------------ [ 272.702007] kernel BUG at mm/memcontrol.c:3330! This is because kfence page is allocated to an order-0 page without clearing page->obj_cgroups, which is the same offset of mem_cgroup. Clear it before allocating to order-0 page, and also before kfence pool area freeing (return to buddy system) to fix possible memory leak. Reported-by: Xu Yu Signed-off-by: Tianchen Ding --- mm/kfence/core.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index b4a7cdd47c6d..f3dd9c083847 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -677,7 +677,17 @@ static struct page *kfence_guarded_alloc_page(int node) addr = (void *)meta->addr; page = virt_to_page(addr); - __ClearPageSlab(page); + if (PageSlab(page)) { + /* + * For performance considerations, + * we clean slab info here (when allocating pages). + * So that slabs can reuse their flags and obj_cgroups + * without being cleared or freed if the previous user + * is slab too. + */ + memcg_free_page_obj_cgroups(page, page->slab_cache); + __ClearPageSlab(page); + } page->mapping = NULL; #ifdef CONFIG_DEBUG_VM atomic_set(&page->_refcount, 0); @@ -855,8 +865,11 @@ static inline void kfence_clear_page_info(unsigned long addr, unsigned long size for (i = addr; i < addr + size; i += PAGE_SIZE) { struct page *page = virt_to_page(i); + if (PageSlab(page)) { + memcg_free_page_obj_cgroups(page, page->slab_cache); + __ClearPageSlab(page); + } __ClearPageKfence(page); - __ClearPageSlab(page); page->mapping = NULL; atomic_set(&page->_refcount, 1); kfence_unprotect(i); -- Gitee