Skip to content

Commit c70baaa

Browse files
Muchun Songjfvogel
authored andcommitted
mm: memcontrol: prepare objcg API for non-kmem usage
Pagecache pages are charged at the allocation time and holding a reference to the original memory cgroup until being reclaimed. Depending on the memory pressure, specific patterns of the page sharing between different cgroups and the cgroup creation and destruction rates, a large number of dying memory cgroups can be pinned by pagecache pages. It makes the page reclaim less efficient and wastes memory. We can convert LRU pages and most other raw memcg pins to the objcg direction to fix this problem, and then the page->memcg will always point to an object cgroup pointer. Therefore, the infrastructure of objcg no longer only serves CONFIG_MEMCG_KMEM. In this patch, we move the infrastructure of the objcg out of the scope of the CONFIG_MEMCG_KMEM so that the LRU pages can reuse it to charge pages. We know that the LRU pages are not accounted at the root level. But the page->memcg_data points to the root_mem_cgroup. So the page->memcg_data of the LRU pages always points to a valid pointer. But the root_mem_cgroup dose not have an object cgroup. If we use obj_cgroup APIs to charge the LRU pages, we should set the page->memcg_data to a root object cgroup. So we also allocate an object cgroup for the root_mem_cgroup. Signed-off-by: Muchun Song <[email protected]> Acked-by: Johannes Weiner <[email protected]> Reviewed-by: Michal Koutný <[email protected]> Acked-by: Roman Gushchin <[email protected]> Link: https://lore.kernel.org/all/[email protected]/ Orabug: 37405594 Conflicts: mm/memcontrol.c (Due to presence of following commits in UEK-8: i. 'commit e4dde56 mm: multi-gen LRU: per-node lru_gen_folio lists' ii. 'commit 9c94bef mm/memcontrol.c: replace cgroup_memory_nokmem with mem_cgroup_kmem_disabled()' iii. 'commit 675d6c9 mm: kmem: make memcg keep a reference to the original objcg' include/linux/memcontrol.h (Due to presence of 'commit 3a3b7fe mm: remove CONFIG_MEMCG_KMEM' - which removed the #ifdef from struct mem_cgroup, in UEK-8) Signed-off-by: Imran Khan <[email protected]> Reviewed-by: Kamalesh Babulal <[email protected]>
1 parent 95ce7f4 commit c70baaa

File tree

1 file changed

+27
-23
lines changed

1 file changed

+27
-23
lines changed

mm/memcontrol.c

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,10 @@ bool mem_cgroup_kmem_disabled(void)
128128
static void obj_cgroup_uncharge_pages(struct obj_cgroup *objcg,
129129
unsigned int nr_pages);
130130

131-
static void obj_cgroup_release(struct percpu_ref *ref)
131+
static void obj_cgroup_release_bytes(struct obj_cgroup *objcg)
132132
{
133-
struct obj_cgroup *objcg = container_of(ref, struct obj_cgroup, refcnt);
134133
unsigned int nr_bytes;
135134
unsigned int nr_pages;
136-
unsigned long flags;
137135

138136
/*
139137
* At this point all allocated objects are freed, and
@@ -147,9 +145,9 @@ static void obj_cgroup_release(struct percpu_ref *ref)
147145
* 3) CPU1: a process from another memcg is allocating something,
148146
* the stock if flushed,
149147
* objcg->nr_charged_bytes = PAGE_SIZE - 92
150-
* 5) CPU0: we do release this object,
148+
* 4) CPU0: we do release this object,
151149
* 92 bytes are added to stock->nr_bytes
152-
* 6) CPU0: stock is flushed,
150+
* 5) CPU0: stock is flushed,
153151
* 92 bytes are added to objcg->nr_charged_bytes
154152
*
155153
* In the result, nr_charged_bytes == PAGE_SIZE.
@@ -161,6 +159,14 @@ static void obj_cgroup_release(struct percpu_ref *ref)
161159

162160
if (nr_pages)
163161
obj_cgroup_uncharge_pages(objcg, nr_pages);
162+
}
163+
164+
static void obj_cgroup_release(struct percpu_ref *ref)
165+
{
166+
struct obj_cgroup *objcg = container_of(ref, struct obj_cgroup, refcnt);
167+
unsigned long flags;
168+
169+
obj_cgroup_release_bytes(objcg);
164170

165171
spin_lock_irqsave(&objcg_lock, flags);
166172
list_del(&objcg->list);
@@ -189,10 +195,10 @@ static struct obj_cgroup *obj_cgroup_alloc(void)
189195
return objcg;
190196
}
191197

192-
static void memcg_reparent_objcgs(struct mem_cgroup *memcg,
193-
struct mem_cgroup *parent)
198+
static void memcg_reparent_objcgs(struct mem_cgroup *memcg)
194199
{
195200
struct obj_cgroup *objcg, *iter;
201+
struct mem_cgroup *parent = parent_mem_cgroup(memcg);
196202

197203
objcg = rcu_replace_pointer(memcg->objcg, NULL, true);
198204

@@ -3081,23 +3087,12 @@ unsigned long mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
30813087

30823088
static int memcg_online_kmem(struct mem_cgroup *memcg)
30833089
{
3084-
struct obj_cgroup *objcg;
3085-
30863090
if (mem_cgroup_kmem_disabled())
30873091
return 0;
30883092

30893093
if (unlikely(mem_cgroup_is_root(memcg)))
30903094
return 0;
30913095

3092-
objcg = obj_cgroup_alloc();
3093-
if (!objcg)
3094-
return -ENOMEM;
3095-
3096-
objcg->memcg = memcg;
3097-
rcu_assign_pointer(memcg->objcg, objcg);
3098-
obj_cgroup_get(objcg);
3099-
memcg->orig_objcg = objcg;
3100-
31013096
static_branch_enable(&memcg_kmem_online_key);
31023097

31033098
memcg->kmemcg_id = memcg->id.id;
@@ -3107,17 +3102,13 @@ static int memcg_online_kmem(struct mem_cgroup *memcg)
31073102

31083103
static void memcg_offline_kmem(struct mem_cgroup *memcg)
31093104
{
3110-
struct mem_cgroup *parent;
3111-
31123105
if (mem_cgroup_kmem_disabled())
31133106
return;
31143107

31153108
if (unlikely(mem_cgroup_is_root(memcg)))
31163109
return;
31173110

3118-
parent = parent_mem_cgroup(memcg);
3119-
memcg_reparent_objcgs(memcg, parent);
3120-
memcg_reparent_list_lrus(memcg, parent);
3111+
memcg_reparent_list_lrus(memcg, parent_mem_cgroup(memcg));
31213112
}
31223113

31233114
#ifdef CONFIG_CGROUP_WRITEBACK
@@ -3614,6 +3605,7 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
36143605
static int mem_cgroup_css_online(struct cgroup_subsys_state *css)
36153606
{
36163607
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
3608+
struct obj_cgroup *objcg;
36173609

36183610
if (memcg_online_kmem(memcg))
36193611
goto remove_id;
@@ -3631,6 +3623,15 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css)
36313623
FLUSH_TIME);
36323624
lru_gen_online_memcg(memcg);
36333625

3626+
objcg = obj_cgroup_alloc();
3627+
if (!objcg)
3628+
goto free_shrinker;
3629+
3630+
objcg->memcg = memcg;
3631+
rcu_assign_pointer(memcg->objcg, objcg);
3632+
obj_cgroup_get(objcg);
3633+
memcg->orig_objcg = objcg;
3634+
36343635
/* Online state pins memcg ID, memcg ID pins CSS */
36353636
refcount_set(&memcg->id.ref, 1);
36363637
css_get(css);
@@ -3648,6 +3649,8 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css)
36483649
xa_store(&mem_cgroup_ids, memcg->id.id, memcg, GFP_KERNEL);
36493650

36503651
return 0;
3652+
free_shrinker:
3653+
free_shrinker_info(memcg);
36513654
offline_kmem:
36523655
memcg_offline_kmem(memcg);
36533656
remove_id:
@@ -3666,6 +3669,7 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
36663669

36673670
zswap_memcg_offline_cleanup(memcg);
36683671

3672+
memcg_reparent_objcgs(memcg);
36693673
memcg_offline_kmem(memcg);
36703674
reparent_shrinker_deferred(memcg);
36713675
wb_memcg_offline(memcg);

0 commit comments

Comments
 (0)