memcg: remove the v1 soft limit
Subsystems (8)
Shakeel Butt
maintainercover memcg: remove the v1 soft limit
Syzbot reported [1] a set_mm_walk() warning from kswapd. Soft limit reclaim is the only thing that runs shrink_lruvec() from kswapd with a target memcg set, and thus the only way kswapd can reach lru_gen_shrink_lruvec() and in turn set_mm_walk(). The offender, mem_cgroup_shrink_node(), has long carried a "Only used by soft limit reclaim. Do not reuse for anything else." comment and a priority hack, and it simply never got taught about MGLRU.
Rather than teach it, let's delete it. The v1 soft limit was deprecated in v6.12 by commit 569c4f62d84a ("memcg: initiate deprecation of v1 soft limit"). Nobody has reported depending on it in the ~21 months since, and v2 has covered the same ground for a long time with memory.low and memory.min.
Shakeel Butt (9):
memcg: make the v1 soft limit knob inert
memcg: remove v1 soft limit reclaim
memcg: remove mem_cgroup_shrink_node()
memcg: remove the soft limit reclaim tracepoints
memcg: remove the soft limit rbtree
memcg: remove lru_gen_soft_reclaim()
memcg: remove the per-node soft limit tree fields
memcg: remove mem_cgroup->soft_limit
memcg: simplify v1 event ratelimiting
.../admin-guide/cgroup-v1/memory.rst | 49 +- include/linux/memcontrol.h | 27 -- include/linux/mmzone.h | 30 +- include/trace/events/vmscan.h | 14 - mm/internal.h | 4 - mm/memcontrol-v1.c | 435 ++---------------- mm/memcontrol-v1.h | 12 +- mm/memcontrol.c | 7 +- mm/vmscan.c | 96 +--- 9 files changed, 66 insertions(+), 608 deletions(-)
Signature · 1 line
2.53.0-Meta
Shakeel Butt
maintainerPATCH 1/9 memcg: make the v1 soft limit knob inert
The v1 soft limit has been deprecated since v6.12 and nobody has reported depending on it. Start the removal by decoupling the interface from the implementation: keep memory.soft_limit_in_bytes, but ignore writes to it and always report the maximum value on read similar to what memory.kmem.limit_in_bytes already does.
Writes are still parsed, so malformed input keeps returning -EINVAL. The knob now also behaves the same everywhere: it used to return -EOPNOTSUPP on PREEMPT_RT, where soft limit reclaim has always been disabled.
This also fixes the syzbot report linked below. Soft limit reclaim is the only caller that runs shrink_lruvec() from kswapd against a specific memcg, so it is the only way to reach lru_gen_shrink_lruvec() and in turn set_mm_walk(), which warns when called from kswapd.
--- .../admin-guide/cgroup-v1/memory.rst | 49 +++---------------- mm/memcontrol-v1.c | 43 +++++++++------- 2 files changed, 32 insertions(+), 60 deletions(-)
Documentation/admin-guide/cgroup-v1/memory.rst +6 -43
@@ -47,7 +47,6 @@ Features: - pages are linked to per-memcg LRU exclusively, and there is no global LRU. - optionally, memory+swap usage can be accounted and limited. - hierarchical accounting - - soft limit - moving (recharging) account at moving a task is selectable. - usage threshold notifier - memory pressure notifier
@@ -76,10 +75,9 @@ Brief summary of control files. memory.memsw.failcnt show the number of memory+Swap hits limits memory.max_usage_in_bytes show max memory usage recorded memory.memsw.max_usage_in_bytes show max memory+Swap usage recorded - memory.soft_limit_in_bytes set/show soft limit of memory usage - This knob is not available on CONFIG_PREEMPT_RT systems. - This knob is deprecated and shouldn't be - used. + memory.soft_limit_in_bytes This knob is deprecated and has no effect. + Writes are ignored and reads always + return the maximum value. memory.stat show various statistics memory.use_hierarchy set/show hierarchical account enabled This knob is deprecated and shouldn't be
@@ -340,9 +338,6 @@ memory.kmem.usage_in_bytes, or in a separate counter when it makes sense. The main "kmem" counter is fed into the main counter, so kmem charges will also be visible from the user counter. -Currently no soft limit is implemented for kernel memory. It is future work -to trigger slab reclaim when those limits are reached. - 2.7.1 Current Kernel Memory resources accounted -----------------------------------------------
@@ -710,42 +705,10 @@ For compatibility reasons writing 1 to memory.use_hierarchy will always pass:: THIS IS DEPRECATED! -Soft limits allow for greater sharing of memory. The idea behind soft limits -is to allow control groups to use as much of the memory as needed, provided - -a. There is no memory contention -b. They do not exceed their hard limit - -When the system detects memory contention or low memory, control groups -are pushed back to their soft limits. If the soft limit of each control -group is very high, they are pushed back as much as possible to make -sure that one control group does not starve the others of memory. - -Please note that soft limits is a best-effort feature; it comes with -no guarantees, but it does its best to make sure that when memory is -heavily contended for, memory is allocated based on the soft limit -hints/setup. Currently soft limit based reclaim is set up such that -it gets invoked from balance_pgdat (kswapd). - -7.1 Interface -------------- - -Soft limits can be setup by using the following commands (in this example we -assume a soft limit of 256 MiB):: - - # echo 256M > memory.soft_limit_in_bytes - -If we want to change this to 1G, we can at any time use:: +Writing to memory.soft_limit_in_bytes has no effect and reading it will +always return the maximum value. - # echo 1G > memory.soft_limit_in_bytes - -.. note:: - Soft limits take effect over a long period of time, since they involve - reclaiming memory for balancing between memory cgroups - -.. note:: - It is recommended to set the soft limit always below the hard limit, - otherwise the hard limit will take precedence. +Use memory.low and memory.min in cgroup v2 instead. .. _cgroup-v1-memory-move-charges:
mm/memcontrol-v1.c +26 -17
73 lines not on this page · raw message
Signature · 1 line
2.53.0-Meta
Andrew Morton
maintainerRe: [PATCH 1/9] memcg: make the v1 soft limit knob inert
Quoted 11 lines · On Tue, 11 Aug 2026 13:31:55 -0700 Shakeel Butt <[email protected]> wrote:
The v1 soft limit has been deprecated since v6.12 and nobody has reported depending on it. Start the removal by decoupling the interface from the implementation: keep memory.soft_limit_in_bytes, but ignore writes to it and always report the maximum value on read similar to what memory.kmem.limit_in_bytes already does.
Writes are still parsed, so malformed input keeps returning
-EINVAL. The knob now also behaves the same everywhere: it used to return-EOPNOTSUPPonPREEMPT_RT, where soft limit reclaim has always been disabled.
Quoted 4 lines
This also fixes the syzbot report linked below. Soft limit reclaim is the only caller that runs
shrink_lruvec()from kswapd against a specific memcg, so it is the only way to reachlru_gen_shrink_lruvec()and in turnset_mm_walk(), which warns when called from kswapd.
Thanks, I'll pluck this one as a hotfix.
It's old code, yes? Are there any theories about why the sysbot issue has just popped up? Should we backport the fix?
Shakeel Butt
maintainerRe: [PATCH 1/9] memcg: make the v1 soft limit knob inert
Quoted 13 lines · Andrew Morton
Quoted 11 lines · On Tue, 11 Aug 2026 13:31:55 -0700 Shakeel Butt <[email protected]> wrote:
The v1 soft limit has been deprecated since v6.12 and nobody has reported depending on it. Start the removal by decoupling the interface from the implementation: keep memory.soft_limit_in_bytes, but ignore writes to it and always report the maximum value on read similar to what memory.kmem.limit_in_bytes already does.
Writes are still parsed, so malformed input keeps returning
-EINVAL. The knob now also behaves the same everywhere: it used to return-EOPNOTSUPPonPREEMPT_RT, where soft limit reclaim has always been disabled.
Quoted 6 lines
Quoted 4 lines
This also fixes the syzbot report linked below. Soft limit reclaim is the only caller that runs
shrink_lruvec()from kswapd against a specific memcg, so it is the only way to reachlru_gen_shrink_lruvec()and in turnset_mm_walk(), which warns when called from kswapd.Thanks, I'll pluck this one as a hotfix.
Sounds good.
Quoted 2 lines
It's old code, yes?
Yes.
Quoted 2 lines
Are there any theories about why the sysbot issue
has just popped up?
The reproducer is toggling MGLRU on and off continuosly which is not really recommended.
Quoted 1 line
Should we backport the fix?
I have no concerns in backporting this to older stable kernels.
Re: [PATCH 1/9] memcg: make the v1 soft limit knob inert
In reply to Shakeel ButtQuoted 10 lines · Shakeel Butt
The v1 soft limit has been deprecated since v6.12 and nobody has reported depending on it. Start the removal by decoupling the interface from the implementation: keep memory.soft_limit_in_bytes, but ignore writes to it and always report the maximum value on read similar to what memory.kmem.limit_in_bytes already does.
Writes are still parsed, so malformed input keeps returning
-EINVAL. The knob now also behaves the same everywhere: it used to return-EOPNOTSUPPonPREEMPT_RT, where soft limit reclaim has always been disabled.
Is there any specific reason to not return EOPNOTSUPP for everybody now?
Quoted 8 lines
This also fixes the syzbot report linked below. Soft limit reclaim is the only caller that runs
shrink_lruvec()from kswapd against a specific memcg, so it is the only way to reachlru_gen_shrink_lruvec()and in turnset_mm_walk(), which warns when called from kswapd.Reported-by [email protected]Signed-off-by Shakeel Butt <[email protected]>
Anyway
Quoted 171 lines
--- .../admin-guide/cgroup-v1/memory.rst | 49 +++---------------- mm/memcontrol-v1.c | 43 +++++++++------- 2 files changed, 32 insertions(+), 60 deletions(-)Documentation/admin-guide/cgroup-v1/memory.rst +6
-43@@ -47,7 +47,6 @@ Features: - pages are linked to per-memcg LRU exclusively, and there is no global LRU. - optionally, memory+swap usage can be accounted and limited. - hierarchical accounting - - soft limit - moving (recharging) account at moving a task is selectable. - usage threshold notifier - memory pressure notifier@@ -76,10 +75,9 @@ Brief summary of control files. memory.memsw.failcnt show the number of memory+Swap hits limits memory.max_usage_in_bytes show max memory usage recorded memory.memsw.max_usage_in_bytes show max memory+Swap usage recorded - memory.soft_limit_in_bytes set/show soft limit of memory usage - This knob is not available on CONFIG_PREEMPT_RT systems. - This knob is deprecated and shouldn't be - used. + memory.soft_limit_in_bytes This knob is deprecated and has no effect. + Writes are ignored and reads always + return the maximum value. memory.stat show various statistics memory.use_hierarchy set/show hierarchical account enabled This knob is deprecated and shouldn't be@@ -340,9 +338,6 @@ memory.kmem.usage_in_bytes, or in a separate counter when it makes sense. The main "kmem" counter is fed into the main counter, so kmem charges will also be visible from the user counter. -Currently no soft limit is implemented for kernel memory. It is future work -to trigger slab reclaim when those limits are reached. - 2.7.1 Current Kernel Memory resources accounted -----------------------------------------------@@ -710,42 +705,10 @@ For compatibility reasons writing 1 to memory.use_hierarchy will always pass:: THIS IS DEPRECATED! -Soft limits allow for greater sharing of memory. The idea behind soft limits -is to allow control groups to use as much of the memory as needed, provided - -a. There is no memory contention -b. They do not exceed their hard limit - -When the system detects memory contention or low memory, control groups -are pushed back to their soft limits. If the soft limit of each control -group is very high, they are pushed back as much as possible to make -sure that one control group does not starve the others of memory. - -Please note that soft limits is a best-effort feature; it comes with -no guarantees, but it does its best to make sure that when memory is -heavily contended for, memory is allocated based on the soft limit -hints/setup. Currently soft limit based reclaim is set up such that -it gets invoked from balance_pgdat (kswapd). - -7.1 Interface -------------- - -Soft limits can be setup by using the following commands (in this example we -assume a soft limit of 256 MiB):: - - # echo 256M > memory.soft_limit_in_bytes - -If we want to change this to 1G, we can at any time use:: +Writing to memory.soft_limit_in_bytes has no effect and reading it will +always return the maximum value. - # echo 1G > memory.soft_limit_in_bytes - -.. note:: - Soft limits take effect over a long period of time, since they involve - reclaiming memory for balancing between memory cgroups - -.. note:: - It is recommended to set the soft limit always below the hard limit, - otherwise the hard limit will take precedence. +Use memory.low and memory.min in cgroup v2 instead. .. _cgroup-v1-memory-move-charges:mm/memcontrol-v1.c +26
-17@@ -96,7 +96,6 @@ enum {RES_LIMIT ,RES_MAX_USAGE , RES_FAILCNT, - RES_SOFT_LIMIT, };#ifdef CONFIG_LOCKDEP @@ -1888,6 +1887,30 @@ static int mem_cgroup_hierarchy_write(struct cgroup_subsys_state *css,return -EINVAL ; } +static u64 mem_cgroup_soft_limit_read (struct cgroup_subsys_state *css, +struct cftype *cft) +{ +return (u64 )PAGE_COUNTER_MAX *PAGE_SIZE ; +} + +static ssize_t mem_cgroup_soft_limit_write (struct kernfs_open_file *of, +char *buf,size_t nbytes,loff_t off) +{ +unsigned long nr_pages; +int ret; + + ret =page_counter_memparse (strstrip (buf),"-1" , &nr_pages); +if (ret) +return ret; + +pr_warn_once ("soft_limit_in_bytes is deprecated and will be removed. " +"Writing any value to this file has no effect. " +"Please report your usecase to [email protected] if you " +"depend on this functionality.\n" ); + +return nbytes; +} +static u64 mem_cgroup_read_u64 (struct cgroup_subsys_state *css,struct cftype *cft) {@@ -1924,8 +1947,6 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,return (u64 )counter->watermark *PAGE_SIZE ;case RES_FAILCNT :return counter->failcnt; -case RES_SOFT_LIMIT : -return (u64 )READ_ONCE (memcg->soft_limit) *PAGE_SIZE ;default :BUG (); }@@ -2020,17 +2041,6 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of,break ; }break ; -case RES_SOFT_LIMIT : -if (IS_ENABLED (CONFIG_PREEMPT_RT )) { - ret = -EOPNOTSUPP ; - }else { -pr_warn_once ("soft_limit_in_bytes is deprecated and will be removed. " -"Please report your usecase to [email protected] if you " -"depend on this functionality.\n" ); -WRITE_ONCE (memcg->soft_limit, nr_pages); - ret =0 ; - } -break ; }return ret ?: nbytes; }@@ -2384,9 +2394,8 @@ struct cftype mem_cgroup_legacy_files[] = { }, { .name = "soft_limit_in_bytes", - .private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT), - .write = mem_cgroup_write, - .read_u64 = mem_cgroup_read_u64, + .write = mem_cgroup_soft_limit_write, + .read_u64 = mem_cgroup_soft_limit_read, }, { .name = "failcnt",Signature · 1 line
2.53.0-Meta
Signature · 2 lines
Michal Hocko SUSE Labs
Shakeel Butt
maintainerRe: [PATCH 1/9] memcg: make the v1 soft limit knob inert
Quoted 7 lines · Michal Hocko
Quoted 6 lines · Shakeel Butt
The v1 soft limit has been deprecated since v6.12 and nobody has reported depending on it. Start the removal by decoupling the interface from the implementation: keep memory.soft_limit_in_bytes, but ignore writes to it and always report the maximum value on read similar to what memory.kmem.limit_in_bytes already does.
Quoted 6 lines
Quoted 4 lines
Writes are still parsed, so malformed input keeps returning
-EINVAL. The knob now also behaves the same everywhere: it used to return-EOPNOTSUPPonPREEMPT_RT, where soft limit reclaim has always been disabled.Is there any specific reason to not return EOPNOTSUPP for everybody now?
I followed the memory.kmem.limit_in_bytes example. If you have strong opinion, I am ok with EOPNOTSUPP as well.
Quoted 6 lines
Quoted 6 lines
This also fixes the syzbot report linked below. Soft limit reclaim is the only caller that runs
shrink_lruvec()from kswapd against a specific memcg, so it is the only way to reachlru_gen_shrink_lruvec()and in turnset_mm_walk(), which warns when called from kswapd.
Quoted 6 lines
Quoted 3 lines
Reported-by [email protected]Signed-off-by Shakeel Butt <[email protected]>Anyway
Acked-by Michal Hocko <[email protected]>
Thanks for reviewing the series.
Shakeel Butt
maintainerPATCH 2/9 memcg: remove v1 soft limit reclaim
In reply to Shakeel ButtNothing can put a cgroup on the soft limit rbtree anymore, so the tree is always empty and both callers of memcg1_soft_limit_reclaim() are guaranteed no-ops. Remove the reclaim pass from direct reclaim and from kswapd, along with its implementation.
In shrink_zones() this leaves the global reclaim branch with a last_pgdat check that is now redundant with the identical check right below it, so drop it and move the explaining comment down to the check that remains. That check could only ever fire once last_pgdat was set, which implies first_pgdat had already been assigned, so skipping it does not change which node consider_reclaim_throttle() gets.
--- include/linux/memcontrol.h | 12 --- mm/memcontrol-v1.c | 175 ------------------------------------- mm/vmscan.c | 39 ++------- 3 files changed, 6 insertions(+), 220 deletions(-)
include/linux/memcontrol.h +0 -12
@@ -1927,10 +1927,6 @@ static inline bool mem_cgroup_zswap_writeback_enabled(struct mem_cgroup *memcg)/* Cgroup v1-related declarations */ #ifdef CONFIG_MEMCG_V1 -unsigned long memcg1_soft_limit_reclaim (pg_data_t *pgdat,int order, -gfp_t gfp_mask, -unsigned long *total_scanned); -bool mem_cgroup_oom_synchronize (bool wait);static inline bool task_in_memcg_oom (struct task_struct *p)
@@ -1951,14 +1947,6 @@ static inline void mem_cgroup_exit_user_fault(void) }#else /* CONFIG_MEMCG_V1 */ -static inline -unsigned long memcg1_soft_limit_reclaim (pg_data_t *pgdat,int order, -gfp_t gfp_mask, -unsigned long *total_scanned) -{ -return 0 ; -} -static inline bool task_in_memcg_oom (struct task_struct *p) {return false;
mm/memcontrol-v1.c +0 -175
187 lines not on this page · raw message
mm/vmscan.c +6 -33
@@ -6429,8 +6429,6 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc) {struct zoneref *z;struct zone *zone; -unsigned long nr_soft_reclaimed; -unsigned long nr_soft_scanned;gfp_t orig_mask;pg_data_t *last_pgdat =NULL ;pg_data_t *first_pgdat =NULL ;
@@ -6472,35 +6470,17 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc) sc->compaction_ready = true;continue ; } - -/* -* Shrink each node in the zonelist once. If the -* zonelist is ordered by zone (not the default) then a -* node may be shrunk multiple times but in that case -* the user prefers lower zones being preserved. -*/ -if (zone->zone_pgdat == last_pgdat) -continue ; - -/* -* This steals pages from memory cgroups over softlimit -* and returns the number of reclaimed pages and -* scanned pages. This works for global memory pressure -* and balancing, not for a memcg's limit. -*/ - nr_soft_scanned =0 ; - nr_soft_reclaimed =memcg1_soft_limit_reclaim (zone->zone_pgdat, - sc->order, sc->gfp_mask, - &nr_soft_scanned); - sc->nr_reclaimed += nr_soft_reclaimed; - sc->nr_scanned += nr_soft_scanned; -/* need some check for avoid more shrink_zone() */ }if (!first_pgdat) first_pgdat = zone->zone_pgdat; -/* See comment about same check for global reclaim above */ +/* +* Shrink each node in the zonelist once. If the zonelist is +* ordered by zone (not the default) then a node may be shrunk +* multiple times but in that case the user prefers lower zones +* being preserved. +*/ if (zone->zone_pgdat == last_pgdat)continue ; last_pgdat = zone->zone_pgdat;
@@ -7161,8 +7141,6 @@ clear_reclaim_active(pg_data_t *pgdat, int highest_zoneidx)static int balance_pgdat (pg_data_t *pgdat,int order,int highest_zoneidx) {int i; -unsigned long nr_soft_reclaimed; -unsigned long nr_soft_scanned;unsigned long pflags;unsigned long nr_boost_reclaim;unsigned long zone_boosts[MAX_NR_ZONES ] = {0 , };
@@ -7268,12 +7246,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int highest_zoneidx)*/ kswapd_age_node (pgdat, &sc); -/* Call soft limit reclaim before calling shrink_node. */ sc.nr_scanned =0 ; - nr_soft_scanned =0 ; - nr_soft_reclaimed =memcg1_soft_limit_reclaim (pgdat, sc.order, - sc.gfp_mask, &nr_soft_scanned); - sc.nr_reclaimed += nr_soft_reclaimed;/* * There should be no need to raise the scanning priority if
Signature · 1 line
2.53.0-Meta
Re: [PATCH 2/9] memcg: remove v1 soft limit reclaim
Quoted 5 lines · Shakeel Butt
Nothing can put a cgroup on the soft limit rbtree anymore, so the tree is always empty and both callers of
memcg1_soft_limit_reclaim()are guaranteed no-ops. Remove the reclaim pass from direct reclaim and from kswapd, along with its implementation.
Quoted 8 lines
In
shrink_zones()this leaves the global reclaim branch with alast_pgdatcheck that is now redundant with the identical check right below it, so drop it and move the explaining comment down to the check that remains. That check could only ever fire oncelast_pgdatwas set, which impliesfirst_pgdathad already been assigned, so skipping it does not change which nodeconsider_reclaim_throttle()gets.Signed-off-by Shakeel Butt <[email protected]>
Thanks!
Quoted 308 lines
--- include/linux/memcontrol.h | 12 --- mm/memcontrol-v1.c | 175 ------------------------------------- mm/vmscan.c | 39 ++------- 3 files changed, 6 insertions(+), 220 deletions(-)include/linux/memcontrol.h +0
-12@@ -1927,10 +1927,6 @@ static inline bool mem_cgroup_zswap_writeback_enabled(struct mem_cgroup *memcg)/* Cgroup v1-related declarations */ #ifdef CONFIG_MEMCG_V1 -unsigned long memcg1_soft_limit_reclaim (pg_data_t *pgdat,int order, -gfp_t gfp_mask, -unsigned long *total_scanned); -bool mem_cgroup_oom_synchronize (bool wait);static inline bool task_in_memcg_oom (struct task_struct *p)@@ -1951,14 +1947,6 @@ static inline void mem_cgroup_exit_user_fault(void) }#else /* CONFIG_MEMCG_V1 */ -static inline -unsigned long memcg1_soft_limit_reclaim (pg_data_t *pgdat,int order, -gfp_t gfp_mask, -unsigned long *total_scanned) -{ -return 0 ; -} -static inline bool task_in_memcg_oom (struct task_struct *p) {return false;mm/memcontrol-v1.c +0
-175@@ -34,13 +34,6 @@ struct mem_cgroup_tree {static struct mem_cgroup_tree soft_limit_tree__read_mostly ; -/* -* Maximum loops in mem_cgroup_soft_reclaim(), used for soft -* limit reclaim to prevent infinite loops, if they ever occur. -*/ -#define MEM_CGROUP_MAX_RECLAIM_LOOPS 100 -#define MEM_CGROUP_MAX_SOFT_LIMIT_RECLAIM_LOOPS 2 -/* for OOM */ struct mem_cgroup_eventfd_list {struct list_head list;@@ -233,174 +226,6 @@ void memcg1_remove_from_trees(struct mem_cgroup *memcg) } } -static struct mem_cgroup_per_node * -__mem_cgroup_largest_soft_limit_node (struct mem_cgroup_tree_per_node *mctz) -{ -struct mem_cgroup_per_node *mz; - -retry: - mz =NULL ; -if (!mctz->rb_rightmost) - goto done;/* Nothing to reclaim from */ - - mz =rb_entry (mctz->rb_rightmost, - struct mem_cgroup_per_node, tree_node); -/* -* Remove the node now but someone else can add it back, -* we will to add it back at the end of reclaim to its correct -* position in the tree. -*/ -__mem_cgroup_remove_exceeded (mz, mctz); -if (!soft_limit_excess (mz->memcg) || - !css_tryget (&mz->memcg->css)) - goto retry; -done: -return mz; -} - -static struct mem_cgroup_per_node * -mem_cgroup_largest_soft_limit_node (struct mem_cgroup_tree_per_node *mctz) -{ -struct mem_cgroup_per_node *mz; - -spin_lock_irq (&mctz->lock); - mz =__mem_cgroup_largest_soft_limit_node (mctz); -spin_unlock_irq (&mctz->lock); -return mz; -} - -static int mem_cgroup_soft_reclaim (struct mem_cgroup *root_memcg, -pg_data_t *pgdat, -gfp_t gfp_mask, -unsigned long *total_scanned) -{ -struct mem_cgroup *victim =NULL ; -int total =0 ; -int loop =0 ; -unsigned long excess; -unsigned long nr_scanned; -struct mem_cgroup_reclaim_cookie reclaim = { - .pgdat = pgdat, - }; - - excess =soft_limit_excess (root_memcg); - -while (1 ) { - victim =mem_cgroup_iter (root_memcg, victim, &reclaim); -if (!victim) { - loop++; -if (loop >=2 ) { -/* -* If we have not been able to reclaim -* anything, it might because there are -* no reclaimable pages under this hierarchy -*/ -if (!total) -break ; -/* -* We want to do more targeted reclaim. -* excess >> 2 is not to excessive so as to -* reclaim too much, nor too less that we keep -* coming back to reclaim from this cgroup -*/ -if (total >= (excess >>2 ) || - (loop >MEM_CGROUP_MAX_RECLAIM_LOOPS )) -break ; - } -continue ; - } - total +=mem_cgroup_shrink_node (victim, gfp_mask, false, - pgdat, &nr_scanned); - *total_scanned += nr_scanned; -if (!soft_limit_excess (root_memcg)) -break ; - } -mem_cgroup_iter_break (root_memcg, victim); -return total; -} - -unsigned long memcg1_soft_limit_reclaim (pg_data_t *pgdat,int order, -gfp_t gfp_mask, -unsigned long *total_scanned) -{ -unsigned long nr_reclaimed =0 ; -struct mem_cgroup_per_node *mz, *next_mz =NULL ; -unsigned long reclaimed; -int loop =0 ; -struct mem_cgroup_tree_per_node *mctz; -unsigned long excess; - -if (lru_gen_enabled ()) -return 0 ; - -if (order >0 ) -return 0 ; - - mctz = soft_limit_tree.rb_tree_per_node[pgdat->node_id]; - -/* -* Do not even bother to check the largest node if the root -* is empty. Do it lockless to prevent lock bouncing. Races -* are acceptable as soft limit is best effort anyway. -*/ -if (!mctz ||RB_EMPTY_ROOT (&mctz->rb_root)) -return 0 ; - -/* -* This loop can run a while, specially if mem_cgroup's continuously -* keep exceeding their soft limit and putting the system under -* pressure -*/ -do { -if (next_mz) - mz = next_mz; -else - mz =mem_cgroup_largest_soft_limit_node (mctz); -if (!mz) -break ; - - reclaimed =mem_cgroup_soft_reclaim (mz->memcg, pgdat, - gfp_mask, total_scanned); - nr_reclaimed += reclaimed; -spin_lock_irq (&mctz->lock); - -/* -* If we failed to reclaim anything from this memory cgroup -* it is time to move on to the next cgroup -*/ - next_mz =NULL ; -if (!reclaimed) - next_mz =__mem_cgroup_largest_soft_limit_node (mctz); - - excess =soft_limit_excess (mz->memcg); -/* -* One school of thought says that we should not add -* back the node to the tree if reclaim returns 0. -* But our reclaim could return 0, simply because due -* to priority we are exposing a smaller subset of -* memory to reclaim from. Consider this as a longer -* term TODO. -*/ -/* If excess == 0, no tree ops */ -__mem_cgroup_insert_exceeded (mz, mctz, excess); -spin_unlock_irq (&mctz->lock); -css_put (&mz->memcg->css); - loop++; -/* -* Could not reclaim anything and there are no more -* mem cgroups to try or we seem to be looping without -* reclaiming anything. -*/ -if (!nr_reclaimed && - (next_mz ==NULL || - loop >MEM_CGROUP_MAX_SOFT_LIMIT_RECLAIM_LOOPS )) -break ; - }while (!nr_reclaimed); -if (next_mz) -css_put (&next_mz->memcg->css); -return nr_reclaimed; -} -static u64 mem_cgroup_move_charge_read (struct cgroup_subsys_state *css,struct cftype *cft) {mm/vmscan.c +6
-33@@ -6429,8 +6429,6 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc) {struct zoneref *z;struct zone *zone; -unsigned long nr_soft_reclaimed; -unsigned long nr_soft_scanned;gfp_t orig_mask;pg_data_t *last_pgdat =NULL ;pg_data_t *first_pgdat =NULL ;@@ -6472,35 +6470,17 @@ static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc) sc->compaction_ready = true;continue ; } - -/* -* Shrink each node in the zonelist once. If the -* zonelist is ordered by zone (not the default) then a -* node may be shrunk multiple times but in that case -* the user prefers lower zones being preserved. -*/ -if (zone->zone_pgdat == last_pgdat) -continue ; - -/* -* This steals pages from memory cgroups over softlimit -* and returns the number of reclaimed pages and -* scanned pages. This works for global memory pressure -* and balancing, not for a memcg's limit. -*/ - nr_soft_scanned =0 ; - nr_soft_reclaimed =memcg1_soft_limit_reclaim (zone->zone_pgdat, - sc->order, sc->gfp_mask, - &nr_soft_scanned); - sc->nr_reclaimed += nr_soft_reclaimed; - sc->nr_scanned += nr_soft_scanned; -/* need some check for avoid more shrink_zone() */ }if (!first_pgdat) first_pgdat = zone->zone_pgdat; -/* See comment about same check for global reclaim above */ +/* +* Shrink each node in the zonelist once. If the zonelist is +* ordered by zone (not the default) then a node may be shrunk +* multiple times but in that case the user prefers lower zones +* being preserved. +*/ if (zone->zone_pgdat == last_pgdat)continue ; last_pgdat = zone->zone_pgdat;@@ -7161,8 +7141,6 @@ clear_reclaim_active(pg_data_t *pgdat, int highest_zoneidx)static int balance_pgdat (pg_data_t *pgdat,int order,int highest_zoneidx) {int i; -unsigned long nr_soft_reclaimed; -unsigned long nr_soft_scanned;unsigned long pflags;unsigned long nr_boost_reclaim;unsigned long zone_boosts[MAX_NR_ZONES ] = {0 , };@@ -7268,12 +7246,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int highest_zoneidx)*/ kswapd_age_node (pgdat, &sc); -/* Call soft limit reclaim before calling shrink_node. */ sc.nr_scanned =0 ; - nr_soft_scanned =0 ; - nr_soft_reclaimed =memcg1_soft_limit_reclaim (pgdat, sc.order, - sc.gfp_mask, &nr_soft_scanned); - sc.nr_reclaimed += nr_soft_reclaimed;/* * There should be no need to raise the scanning priority if Signature · 1 line
2.53.0-Meta
Signature · 2 lines
Michal Hocko SUSE Labs
Shakeel Butt
maintainerPATCH 3/9 memcg: remove mem_cgroup_shrink_node()
In reply to Shakeel ButtIts only caller was soft limit reclaim, which is gone.
--- mm/internal.h | 4 ---- mm/vmscan.c | 41 ----------------------------------------- 2 files changed, 45 deletions(-)
mm/internal.h +0 -4
@@ -85,10 +85,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,gfp_t gfp_mask, unsigned int reclaim_options, int *swappiness); -unsigned long mem_cgroup_shrink_node (struct mem_cgroup *memcg, -gfp_t gfp_mask,bool noswap, -pg_data_t *pgdat, -unsigned long *nr_scanned);#ifdef CONFIG_NUMA extern int sysctl_min_unmapped_ratio;
mm/vmscan.c +0 -41
47 lines not on this page · raw message
Signature · 1 line
2.53.0-Meta
Re: [PATCH 3/9] memcg: remove mem_cgroup_shrink_node()
Quoted 3 lines · Shakeel Butt
Its only caller was soft limit reclaim, which is gone.
Signed-off-by Shakeel Butt <[email protected]>
Thanks!
Quoted 74 lines
--- mm/internal.h | 4 ---- mm/vmscan.c | 41 ----------------------------------------- 2 files changed, 45 deletions(-)mm/internal.h +0
-4@@ -85,10 +85,6 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,gfp_t gfp_mask, unsigned int reclaim_options, int *swappiness); -unsigned long mem_cgroup_shrink_node (struct mem_cgroup *memcg, -gfp_t gfp_mask,bool noswap, -pg_data_t *pgdat, -unsigned long *nr_scanned);#ifdef CONFIG_NUMA extern int sysctl_min_unmapped_ratio;mm/vmscan.c +0
-41@@ -6795,47 +6795,6 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,#ifdef CONFIG_MEMCG -/* Only used by soft limit reclaim. Do not reuse for anything else. */ -unsigned long mem_cgroup_shrink_node (struct mem_cgroup *memcg, -gfp_t gfp_mask,bool noswap, -pg_data_t *pgdat, -unsigned long *nr_scanned) -{ -struct lruvec *lruvec =mem_cgroup_lruvec (memcg, pgdat); -struct scan_control sc = { - .nr_to_reclaim =SWAP_CLUSTER_MAX , - .target_mem_cgroup = memcg, - .may_writepage =1 , - .may_unmap =1 , - .reclaim_idx =MAX_NR_ZONES -1 , - .may_swap = !noswap, - }; - -WARN_ON_ONCE (!current->reclaim_state); - - sc.gfp_mask = (gfp_mask &GFP_RECLAIM_MASK ) | - (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK ); - -trace_mm_vmscan_memcg_softlimit_reclaim_begin (sc.gfp_mask, - sc.order, - memcg); - -/* -* NOTE: Although we can get the priority field, using it -* here is not a good idea, since it limits the pages we can scan. -* if we don't reclaim here, the shrink_node from balance_pgdat -* will pick up pages from other mem cgroup's as well. We hack -* the priority and make it zero. -*/ -shrink_lruvec (lruvec, &sc); - -trace_mm_vmscan_memcg_softlimit_reclaim_end (sc.nr_reclaimed, memcg); - - *nr_scanned = sc.nr_scanned; - -return sc.nr_reclaimed; -} - unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, unsigned long nr_pages, gfp_t gfp_mask,Signature · 1 line
2.53.0-Meta
Signature · 2 lines
Michal Hocko SUSE Labs
Shakeel Butt
maintainerPATCH 4/9 memcg: remove the soft limit reclaim tracepoints
In reply to Shakeel Buttmm_vmscan_memcg_softlimit_reclaim_begin and mm_vmscan_memcg_softlimit_reclaim_end were only emitted by mem_cgroup_shrink_node(), which is gone, so they can never fire again.
--- include/trace/events/vmscan.h | 14 -------------- 1 file changed, 14 deletions(-)
include/trace/events/vmscan.h +0 -14
@@ -214,13 +214,6 @@ DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_reclaim_beTP_ARGS (gfp_flags, order, memcg) ); - -DEFINE_EVENT (mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_softlimit_reclaim_begin, - - TP_PROTO(gfp_t gfp_flags, int order, struct mem_cgroup *memcg), - -TP_ARGS (gfp_flags, order, memcg) -);#endif /* CONFIG_MEMCG */ DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_end_template,
@@ -260,13 +253,6 @@ DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_reclaim_end,TP_ARGS (nr_reclaimed, memcg) ); - -DEFINE_EVENT (mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_softlimit_reclaim_end, - - TP_PROTO(unsigned long nr_reclaimed, struct mem_cgroup *memcg), - -TP_ARGS (nr_reclaimed, memcg) -);#endif /* CONFIG_MEMCG */ TRACE_EVENT(mm_shrink_slab_start,
Signature · 1 line
2.53.0-Meta
Re: [PATCH 4/9] memcg: remove the soft limit reclaim tracepoints
Quoted 5 lines · Shakeel Butt
mm_vmscan_memcg_softlimit_reclaim_beginandmm_vmscan_memcg_softlimit_reclaim_endwere only emitted bymem_cgroup_shrink_node(), which is gone, so they can never fire again.Signed-off-by Shakeel Butt <[email protected]>
Thanks!
Quoted 38 lines
--- include/trace/events/vmscan.h | 14 -------------- 1 file changed, 14 deletions(-)include/trace/events/vmscan.h +0
-14@@ -214,13 +214,6 @@ DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_reclaim_beTP_ARGS (gfp_flags, order, memcg) ); - -DEFINE_EVENT (mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_softlimit_reclaim_begin, - - TP_PROTO(gfp_t gfp_flags, int order, struct mem_cgroup *memcg), - -TP_ARGS (gfp_flags, order, memcg) -);#endif /* CONFIG_MEMCG */ DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_end_template,@@ -260,13 +253,6 @@ DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_reclaim_end,TP_ARGS (nr_reclaimed, memcg) ); - -DEFINE_EVENT (mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_softlimit_reclaim_end, - - TP_PROTO(unsigned long nr_reclaimed, struct mem_cgroup *memcg), - -TP_ARGS (nr_reclaimed, memcg) -);#endif /* CONFIG_MEMCG */ TRACE_EVENT(mm_shrink_slab_start,Signature · 1 line
2.53.0-Meta
Signature · 2 lines
Michal Hocko SUSE Labs
Shakeel Butt
maintainerPATCH 5/9 memcg: remove the soft limit rbtree
In reply to Shakeel ButtWith soft limit reclaim gone, the per-node rbtree of cgroups in excess has no readers left. Remove the tree, the helpers maintaining it, and the subsys_initcall that existed only to allocate it. memcg1_check_events() no longer needs to feed it, which also drops the last caller of lru_gen_soft_reclaim().
--- mm/memcontrol-v1.c | 176 +-------------------------------------------- mm/memcontrol-v1.h | 2 - mm/memcontrol.c | 1 - 3 files changed, 2 insertions(+), 177 deletions(-)
mm/memcontrol-v1.c +2 -174
@@ -17,23 +17,6 @@#include "swap_table.h" #include "memcontrol-v1.h" -/* -* Cgroups above their limits are maintained in a RB-Tree, independent of -* their hierarchy representation -*/ - -struct mem_cgroup_tree_per_node { -struct rb_root rb_root; -struct rb_node *rb_rightmost; -spinlock_t lock; -}; - -struct mem_cgroup_tree { -struct mem_cgroup_tree_per_node *rb_tree_per_node[MAX_NUMNODES ]; -}; - -static struct mem_cgroup_tree soft_limit_tree__read_mostly ; -/* for OOM */ struct mem_cgroup_eventfd_list {struct list_head list;
@@ -99,133 +82,6 @@ static struct lockdep_map memcg_oom_lock_dep_map = {DEFINE_SPINLOCK (memcg_oom_lock); -static void __mem_cgroup_insert_exceeded (struct mem_cgroup_per_node *mz, -struct mem_cgroup_tree_per_node *mctz, -unsigned long new_usage_in_excess) -{ -struct rb_node **p = &mctz->rb_root.rb_node; -struct rb_node *parent =NULL ; -struct mem_cgroup_per_node *mz_node; -bool rightmost = true; - -if (mz->on_tree) -return ; - - mz->usage_in_excess = new_usage_in_excess; -if (!mz->usage_in_excess) -return ; -while (*p) { - parent = *p; - mz_node = rb_entry(parent, struct mem_cgroup_per_node, - tree_node); -if (mz->usage_in_excess < mz_node->usage_in_excess) { - p = &(*p)->rb_left; - rightmost = false; - }else { - p = &(*p)->rb_right; - } - } - -if (rightmost) - mctz->rb_rightmost = &mz->tree_node; - -rb_link_node (&mz->tree_node, parent, p); -rb_insert_color (&mz->tree_node, &mctz->rb_root); - mz->on_tree = true; -} - -static void __mem_cgroup_remove_exceeded (struct mem_cgroup_per_node *mz, -struct mem_cgroup_tree_per_node *mctz) -{ -if (!mz->on_tree) -return ; - -if (&mz->tree_node == mctz->rb_rightmost) - mctz->rb_rightmost =rb_prev (&mz->tree_node); - -rb_erase (&mz->tree_node, &mctz->rb_root); - mz->on_tree = false; -} - -static void mem_cgroup_remove_exceeded (struct mem_cgroup_per_node *mz, -struct mem_cgroup_tree_per_node *mctz) -{ -unsigned long flags; - -spin_lock_irqsave (&mctz->lock, flags); -__mem_cgroup_remove_exceeded (mz, mctz); -spin_unlock_irqrestore (&mctz->lock, flags); -} - -static unsigned long soft_limit_excess (struct mem_cgroup *memcg) -{ -unsigned long nr_pages =page_counter_read (&memcg->memory); -unsigned long soft_limit =READ_ONCE (memcg->soft_limit); -unsigned long excess =0 ; - -if (nr_pages > soft_limit) - excess = nr_pages - soft_limit; - -return excess; -} - -static void memcg1_update_tree (struct mem_cgroup *memcg,int nid) -{ -unsigned long excess; -struct mem_cgroup_per_node *mz; -struct mem_cgroup_tree_per_node *mctz; - -if (lru_gen_enabled ()) { -if (soft_limit_excess (memcg)) -lru_gen_soft_reclaim (memcg, nid); -return ; - } - - mctz = soft_limit_tree.rb_tree_per_node[nid]; -if (!mctz) -return ; -/* -* Necessary to update all ancestors when hierarchy is used. -* because their event counter is not touched. -*/ -for (; memcg; memcg =parent_mem_cgroup (memcg)) { - mz = memcg->nodeinfo[nid]; - excess =soft_limit_excess (memcg); -/* -* We have to update the tree if mz is on RB-tree or -* mem is over its softlimit. -*/ -if (excess || mz->on_tree) { -unsigned long flags; - -spin_lock_irqsave (&mctz->lock, flags); -/* if on-tree, remove it */ -if (mz->on_tree) -__mem_cgroup_remove_exceeded (mz, mctz); -/* -* Insert again. mz->usage_in_excess will be updated. -* If excess is 0, no tree ops. -*/ -__mem_cgroup_insert_exceeded (mz, mctz, excess); -spin_unlock_irqrestore (&mctz->lock, flags); - } - } -} - -void memcg1_remove_from_trees (struct mem_cgroup *memcg) -{ -struct mem_cgroup_tree_per_node *mctz; -struct mem_cgroup_per_node *mz; -int nid; - -for_each_node (nid) { - mz = memcg->nodeinfo[nid]; - mctz = soft_limit_tree.rb_tree_per_node[nid]; -if (mctz) -mem_cgroup_remove_exceeded (mz, mctz); - } -} -static u64 mem_cgroup_move_charge_read (struct cgroup_subsys_state *css,struct cftype *cft) {
@@ -336,7 +192,7 @@ static void mem_cgroup_threshold(struct mem_cgroup *memcg) } } -/* Cgroup1: threshold notifications & softlimit tree updates */ +/* Cgroup1: threshold notifications */ /* * Per memcg event counter is incremented at every pagein/pageout. With THP,
@@ -405,17 +261,8 @@ static void memcg1_check_events(struct mem_cgroup *memcg, int nid)if (IS_ENABLED (CONFIG_PREEMPT_RT ))return ; -/* threshold event is triggered in finer grain than soft limit */ -if (unlikely (memcg1_event_ratelimit (memcg, -MEM_CGROUP_TARGET_THRESH ))) { -bool do_softlimit; - - do_softlimit =memcg1_event_ratelimit (memcg, -MEM_CGROUP_TARGET_SOFTLIMIT ); +if (unlikely (memcg1_event_ratelimit (memcg,MEM_CGROUP_TARGET_THRESH )))mem_cgroup_threshold (memcg); -if (unlikely (do_softlimit)) -memcg1_update_tree (memcg, nid); - } }void memcg1_commit_charge (struct folio *folio,struct mem_cgroup *memcg)
@@ -2391,22 +2238,3 @@ void memcg1_free_events(struct mem_cgroup *memcg) {free_percpu (memcg->events_percpu); } - -static int __init memcg1_init (void ) -{ -int node; - -for_each_node (node) { -struct mem_cgroup_tree_per_node *rtpn; - - rtpn =kzalloc_node (sizeof (*rtpn),GFP_KERNEL , node); - - rtpn->rb_root =RB_ROOT ; - rtpn->rb_rightmost =NULL ; -spin_lock_init (&rtpn->lock); - soft_limit_tree.rb_tree_per_node[node] = rtpn; - } - -return 0 ; -} -subsys_initcall (memcg1_init);
mm/memcontrol-v1.h +0 -2
@@ -41,7 +41,6 @@ bool memcg1_alloc_events(struct mem_cgroup *memcg);void memcg1_free_events (struct mem_cgroup *memcg);void memcg1_memcg_init (struct mem_cgroup *memcg); -void memcg1_remove_from_trees (struct mem_cgroup *memcg);static inline void memcg1_soft_limit_reset (struct mem_cgroup *memcg) {
@@ -98,7 +97,6 @@ static inline bool memcg1_alloc_events(struct mem_cgroup *memcg) { return true;static inline void memcg1_free_events (struct mem_cgroup *memcg) {}static inline void memcg1_memcg_init (struct mem_cgroup *memcg) {} -static inline void memcg1_remove_from_trees (struct mem_cgroup *memcg) {}static inline void memcg1_soft_limit_reset (struct mem_cgroup *memcg) {}static inline void memcg1_css_offline (struct mem_cgroup *memcg) {}
mm/memcontrol.c +0 -1
@@ -4394,7 +4394,6 @@ static void mem_cgroup_css_free(struct cgroup_subsys_state *css)vmpressure_cleanup (&memcg->vmpressure);cancel_work_sync (&memcg->high_work); -memcg1_remove_from_trees (memcg);free_shrinker_info (memcg);mem_cgroup_free (memcg); }
Signature · 1 line
2.53.0-Meta
Re: [PATCH 5/9] memcg: remove the soft limit rbtree
Quoted 7 lines · Shakeel Butt
With soft limit reclaim gone, the per-node rbtree of cgroups in excess has no readers left. Remove the tree, the helpers maintaining it, and the
subsys_initcallthat existed only to allocate it.memcg1_check_events()no longer needs to feed it, which also drops the last caller oflru_gen_soft_reclaim().Signed-off-by Shakeel Butt <[email protected]>
Thanks!
Quoted 253 lines
--- mm/memcontrol-v1.c | 176 +-------------------------------------------- mm/memcontrol-v1.h | 2 - mm/memcontrol.c | 1 - 3 files changed, 2 insertions(+), 177 deletions(-)mm/memcontrol-v1.c +2
-174@@ -17,23 +17,6 @@#include "swap_table.h" #include "memcontrol-v1.h" -/* -* Cgroups above their limits are maintained in a RB-Tree, independent of -* their hierarchy representation -*/ - -struct mem_cgroup_tree_per_node { -struct rb_root rb_root; -struct rb_node *rb_rightmost; -spinlock_t lock; -}; - -struct mem_cgroup_tree { -struct mem_cgroup_tree_per_node *rb_tree_per_node[MAX_NUMNODES ]; -}; - -static struct mem_cgroup_tree soft_limit_tree__read_mostly ; -/* for OOM */ struct mem_cgroup_eventfd_list {struct list_head list;@@ -99,133 +82,6 @@ static struct lockdep_map memcg_oom_lock_dep_map = {DEFINE_SPINLOCK (memcg_oom_lock); -static void __mem_cgroup_insert_exceeded (struct mem_cgroup_per_node *mz, -struct mem_cgroup_tree_per_node *mctz, -unsigned long new_usage_in_excess) -{ -struct rb_node **p = &mctz->rb_root.rb_node; -struct rb_node *parent =NULL ; -struct mem_cgroup_per_node *mz_node; -bool rightmost = true; - -if (mz->on_tree) -return ; - - mz->usage_in_excess = new_usage_in_excess; -if (!mz->usage_in_excess) -return ; -while (*p) { - parent = *p; - mz_node = rb_entry(parent, struct mem_cgroup_per_node, - tree_node); -if (mz->usage_in_excess < mz_node->usage_in_excess) { - p = &(*p)->rb_left; - rightmost = false; - }else { - p = &(*p)->rb_right; - } - } - -if (rightmost) - mctz->rb_rightmost = &mz->tree_node; - -rb_link_node (&mz->tree_node, parent, p); -rb_insert_color (&mz->tree_node, &mctz->rb_root); - mz->on_tree = true; -} - -static void __mem_cgroup_remove_exceeded (struct mem_cgroup_per_node *mz, -struct mem_cgroup_tree_per_node *mctz) -{ -if (!mz->on_tree) -return ; - -if (&mz->tree_node == mctz->rb_rightmost) - mctz->rb_rightmost =rb_prev (&mz->tree_node); - -rb_erase (&mz->tree_node, &mctz->rb_root); - mz->on_tree = false; -} - -static void mem_cgroup_remove_exceeded (struct mem_cgroup_per_node *mz, -struct mem_cgroup_tree_per_node *mctz) -{ -unsigned long flags; - -spin_lock_irqsave (&mctz->lock, flags); -__mem_cgroup_remove_exceeded (mz, mctz); -spin_unlock_irqrestore (&mctz->lock, flags); -} - -static unsigned long soft_limit_excess (struct mem_cgroup *memcg) -{ -unsigned long nr_pages =page_counter_read (&memcg->memory); -unsigned long soft_limit =READ_ONCE (memcg->soft_limit); -unsigned long excess =0 ; - -if (nr_pages > soft_limit) - excess = nr_pages - soft_limit; - -return excess; -} - -static void memcg1_update_tree (struct mem_cgroup *memcg,int nid) -{ -unsigned long excess; -struct mem_cgroup_per_node *mz; -struct mem_cgroup_tree_per_node *mctz; - -if (lru_gen_enabled ()) { -if (soft_limit_excess (memcg)) -lru_gen_soft_reclaim (memcg, nid); -return ; - } - - mctz = soft_limit_tree.rb_tree_per_node[nid]; -if (!mctz) -return ; -/* -* Necessary to update all ancestors when hierarchy is used. -* because their event counter is not touched. -*/ -for (; memcg; memcg =parent_mem_cgroup (memcg)) { - mz = memcg->nodeinfo[nid]; - excess =soft_limit_excess (memcg); -/* -* We have to update the tree if mz is on RB-tree or -* mem is over its softlimit. -*/ -if (excess || mz->on_tree) { -unsigned long flags; - -spin_lock_irqsave (&mctz->lock, flags); -/* if on-tree, remove it */ -if (mz->on_tree) -__mem_cgroup_remove_exceeded (mz, mctz); -/* -* Insert again. mz->usage_in_excess will be updated. -* If excess is 0, no tree ops. -*/ -__mem_cgroup_insert_exceeded (mz, mctz, excess); -spin_unlock_irqrestore (&mctz->lock, flags); - } - } -} - -void memcg1_remove_from_trees (struct mem_cgroup *memcg) -{ -struct mem_cgroup_tree_per_node *mctz; -struct mem_cgroup_per_node *mz; -int nid; - -for_each_node (nid) { - mz = memcg->nodeinfo[nid]; - mctz = soft_limit_tree.rb_tree_per_node[nid]; -if (mctz) -mem_cgroup_remove_exceeded (mz, mctz); - } -} -static u64 mem_cgroup_move_charge_read (struct cgroup_subsys_state *css,struct cftype *cft) {@@ -336,7 +192,7 @@ static void mem_cgroup_threshold(struct mem_cgroup *memcg) } } -/* Cgroup1: threshold notifications & softlimit tree updates */ +/* Cgroup1: threshold notifications */ /* * Per memcg event counter is incremented at every pagein/pageout. With THP, @@ -405,17 +261,8 @@ static void memcg1_check_events(struct mem_cgroup *memcg, int nid)if (IS_ENABLED (CONFIG_PREEMPT_RT ))return ; -/* threshold event is triggered in finer grain than soft limit */ -if (unlikely (memcg1_event_ratelimit (memcg, -MEM_CGROUP_TARGET_THRESH ))) { -bool do_softlimit; - - do_softlimit =memcg1_event_ratelimit (memcg, -MEM_CGROUP_TARGET_SOFTLIMIT ); +if (unlikely (memcg1_event_ratelimit (memcg,MEM_CGROUP_TARGET_THRESH )))mem_cgroup_threshold (memcg); -if (unlikely (do_softlimit)) -memcg1_update_tree (memcg, nid); - } }void memcg1_commit_charge (struct folio *folio,struct mem_cgroup *memcg)@@ -2391,22 +2238,3 @@ void memcg1_free_events(struct mem_cgroup *memcg) {free_percpu (memcg->events_percpu); } - -static int __init memcg1_init (void ) -{ -int node; - -for_each_node (node) { -struct mem_cgroup_tree_per_node *rtpn; - - rtpn =kzalloc_node (sizeof (*rtpn),GFP_KERNEL , node); - - rtpn->rb_root =RB_ROOT ; - rtpn->rb_rightmost =NULL ; -spin_lock_init (&rtpn->lock); - soft_limit_tree.rb_tree_per_node[node] = rtpn; - } - -return 0 ; -} -subsys_initcall (memcg1_init);mm/memcontrol-v1.h +0
-2@@ -41,7 +41,6 @@ bool memcg1_alloc_events(struct mem_cgroup *memcg);void memcg1_free_events (struct mem_cgroup *memcg);void memcg1_memcg_init (struct mem_cgroup *memcg); -void memcg1_remove_from_trees (struct mem_cgroup *memcg);static inline void memcg1_soft_limit_reset (struct mem_cgroup *memcg) {@@ -98,7 +97,6 @@ static inline bool memcg1_alloc_events(struct mem_cgroup *memcg) { return true;static inline void memcg1_free_events (struct mem_cgroup *memcg) {}static inline void memcg1_memcg_init (struct mem_cgroup *memcg) {} -static inline void memcg1_remove_from_trees (struct mem_cgroup *memcg) {}static inline void memcg1_soft_limit_reset (struct mem_cgroup *memcg) {}static inline void memcg1_css_offline (struct mem_cgroup *memcg) {}mm/memcontrol.c +0
-1@@ -4394,7 +4394,6 @@ static void mem_cgroup_css_free(struct cgroup_subsys_state *css)vmpressure_cleanup (&memcg->vmpressure);cancel_work_sync (&memcg->high_work); -memcg1_remove_from_trees (memcg);free_shrinker_info (memcg);mem_cgroup_free (memcg); }Signature · 1 line
2.53.0-Meta
Signature · 2 lines
Michal Hocko SUSE Labs
Shakeel Butt
maintainerPATCH 6/9 memcg: remove lru_gen_soft_reclaim()
In reply to Shakeel ButtThe soft limit rbtree was the only caller. Dropping it leaves MEMCG_LRU_HEAD unreachable, since nothing else ever rotates a memcg with that op, so remove the op too and update the memcg LRU comment.
--- include/linux/mmzone.h | 30 +++++++++++------------------- mm/vmscan.c | 16 ++-------------- 2 files changed, 13 insertions(+), 33 deletions(-)
include/linux/mmzone.h +11 -19
@@ -635,35 +635,32 @@ struct lru_gen_mm_walk {* For each node, memcgs are divided into two generations: the old and the * young. For each generation, memcgs are randomly sharded into multiple bins * to improve scalability. For each bin, the hlist_nulls is virtually divided -* into three segments: the head, the tail and the default. +* into two segments: the tail and the default. * * An onlining memcg is added to the tail of a random bin in the old generation. * The eviction starts at the head of a random bin in the old generation. The * per-node memcg generation counter, whose reminder (mod MEMCG_NR_GENS) indexes * the old generation, is incremented when all its bins become empty. * -* There are four operations: -* 1. MEMCG_LRU_HEAD, which moves a memcg to the head of a random bin in its -* current generation (old or young) and updates its "seg" to "head"; -* 2. MEMCG_LRU_TAIL, which moves a memcg to the tail of a random bin in its +* There are three operations: +* 1. MEMCG_LRU_TAIL, which moves a memcg to the tail of a random bin in its * current generation (old or young) and updates its "seg" to "tail"; -* 3. MEMCG_LRU_OLD, which moves a memcg to the head of a random bin in the old +* 2. MEMCG_LRU_OLD, which moves a memcg to the head of a random bin in the old * generation, updates its "gen" to "old" and resets its "seg" to "default"; -* 4. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the +* 3. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the * young generation, updates its "gen" to "young" and resets its "seg" to * "default". * * The events that trigger the above operations are: -* 1. Exceeding the soft limit, which triggers MEMCG_LRU_HEAD; -* 2. The first attempt to reclaim a memcg below low, which triggers +* 1. The first attempt to reclaim a memcg below low, which triggers * MEMCG_LRU_TAIL; -* 3. The first attempt to reclaim a memcg offlined or below reclaimable size +* 2. The first attempt to reclaim a memcg offlined or below reclaimable size * threshold, which triggers MEMCG_LRU_TAIL; -* 4. The second attempt to reclaim a memcg offlined or below reclaimable size +* 3. The second attempt to reclaim a memcg offlined or below reclaimable size * threshold, which triggers MEMCG_LRU_YOUNG; -* 5. Attempting to reclaim a memcg below min, which triggers MEMCG_LRU_YOUNG; -* 6. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG; -* 7. Offlining a memcg, which triggers MEMCG_LRU_OLD. +* 4. Attempting to reclaim a memcg below min, which triggers MEMCG_LRU_YOUNG; +* 5. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG; +* 6. Offlining a memcg, which triggers MEMCG_LRU_OLD. * * Notes: * 1. Memcg LRU only applies to global reclaim, and the round-robin incrementing
@@ -696,7 +693,6 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg);void lru_gen_online_memcg (struct mem_cgroup *memcg);void lru_gen_offline_memcg (struct mem_cgroup *memcg);void lru_gen_release_memcg (struct mem_cgroup *memcg); -void lru_gen_soft_reclaim (struct mem_cgroup *memcg,int nid);void max_lru_gen_memcg (struct mem_cgroup *memcg,int nid);bool recheck_lru_gen_max_memcg (struct mem_cgroup *memcg,int nid);void lru_gen_reparent_memcg (struct mem_cgroup *memcg,struct mem_cgroup *parent,int nid);
@@ -737,10 +733,6 @@ static inline void lru_gen_release_memcg(struct mem_cgroup *memcg) { } -static inline void lru_gen_soft_reclaim (struct mem_cgroup *memcg,int nid) -{ -} -static inline void max_lru_gen_memcg (struct mem_cgroup *memcg,int nid) { }
mm/vmscan.c +2 -14
@@ -4373,7 +4373,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr)/* see the comment on MEMCG_NR_GENS */ enum {MEMCG_LRU_NOP , -MEMCG_LRU_HEAD ,MEMCG_LRU_TAIL ,MEMCG_LRU_OLD ,MEMCG_LRU_YOUNG ,
@@ -4395,9 +4394,7 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) new = old = lruvec->lrugen.gen;/* see the comment on MEMCG_NR_GENS */ -if (op ==MEMCG_LRU_HEAD ) - seg =MEMCG_LRU_HEAD ; -else if (op ==MEMCG_LRU_TAIL ) +if (op ==MEMCG_LRU_TAIL ) seg =MEMCG_LRU_TAIL ;else if (op ==MEMCG_LRU_OLD ) new =get_memcg_gen (pgdat->memcg_lru.seq);
@@ -4411,7 +4408,7 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op)hlist_nulls_del_rcu (&lruvec->lrugen.list); -if (op ==MEMCG_LRU_HEAD || op ==MEMCG_LRU_OLD ) +if (op ==MEMCG_LRU_OLD )hlist_nulls_add_head_rcu (&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);else hlist_nulls_add_tail_rcu (&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);
@@ -4489,15 +4486,6 @@ void lru_gen_release_memcg(struct mem_cgroup *memcg) } } -void lru_gen_soft_reclaim (struct mem_cgroup *memcg,int nid) -{ -struct lruvec *lruvec =get_lruvec (memcg, nid); - -/* see the comment on MEMCG_NR_GENS */ -if (READ_ONCE (lruvec->lrugen.seg) !=MEMCG_LRU_HEAD ) -lru_gen_rotate_memcg (lruvec,MEMCG_LRU_HEAD ); -} -bool recheck_lru_gen_max_memcg (struct mem_cgroup *memcg,int nid) {struct lruvec *lruvec =get_lruvec (memcg, nid);
Signature · 1 line
2.53.0-Meta
Michal Hocko
reviewerRe: [PATCH 6/9] memcg: remove lru_gen_soft_reclaim()
Quoted 5 lines · Shakeel Butt
The soft limit rbtree was the only caller. Dropping it leaves
MEMCG_LRU_HEADunreachable, since nothing else ever rotates a memcg with that op, so remove the op too and update the memcg LRU comment.Signed-off-by Shakeel Butt <[email protected]>
I am not deeply familiar with MGLRU to give my ack but from a quick look this looks right.
Quoted 125 lines
--- include/linux/mmzone.h | 30 +++++++++++------------------- mm/vmscan.c | 16 ++-------------- 2 files changed, 13 insertions(+), 33 deletions(-)include/linux/mmzone.h +11
-19@@ -635,35 +635,32 @@ struct lru_gen_mm_walk {* For each node, memcgs are divided into two generations: the old and the * young. For each generation, memcgs are randomly sharded into multiple bins * to improve scalability. For each bin, the hlist_nulls is virtually divided -* into three segments: the head, the tail and the default. +* into two segments: the tail and the default. * * An onlining memcg is added to the tail of a random bin in the old generation. * The eviction starts at the head of a random bin in the old generation. The * per-node memcg generation counter, whose reminder (mod MEMCG_NR_GENS) indexes * the old generation, is incremented when all its bins become empty. * -* There are four operations: -* 1. MEMCG_LRU_HEAD, which moves a memcg to the head of a random bin in its -* current generation (old or young) and updates its "seg" to "head"; -* 2. MEMCG_LRU_TAIL, which moves a memcg to the tail of a random bin in its +* There are three operations: +* 1. MEMCG_LRU_TAIL, which moves a memcg to the tail of a random bin in its * current generation (old or young) and updates its "seg" to "tail"; -* 3. MEMCG_LRU_OLD, which moves a memcg to the head of a random bin in the old +* 2. MEMCG_LRU_OLD, which moves a memcg to the head of a random bin in the old * generation, updates its "gen" to "old" and resets its "seg" to "default"; -* 4. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the +* 3. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the * young generation, updates its "gen" to "young" and resets its "seg" to * "default". * * The events that trigger the above operations are: -* 1. Exceeding the soft limit, which triggers MEMCG_LRU_HEAD; -* 2. The first attempt to reclaim a memcg below low, which triggers +* 1. The first attempt to reclaim a memcg below low, which triggers * MEMCG_LRU_TAIL; -* 3. The first attempt to reclaim a memcg offlined or below reclaimable size +* 2. The first attempt to reclaim a memcg offlined or below reclaimable size * threshold, which triggers MEMCG_LRU_TAIL; -* 4. The second attempt to reclaim a memcg offlined or below reclaimable size +* 3. The second attempt to reclaim a memcg offlined or below reclaimable size * threshold, which triggers MEMCG_LRU_YOUNG; -* 5. Attempting to reclaim a memcg below min, which triggers MEMCG_LRU_YOUNG; -* 6. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG; -* 7. Offlining a memcg, which triggers MEMCG_LRU_OLD. +* 4. Attempting to reclaim a memcg below min, which triggers MEMCG_LRU_YOUNG; +* 5. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG; +* 6. Offlining a memcg, which triggers MEMCG_LRU_OLD. * * Notes: * 1. Memcg LRU only applies to global reclaim, and the round-robin incrementing @@ -696,7 +693,6 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg);void lru_gen_online_memcg (struct mem_cgroup *memcg);void lru_gen_offline_memcg (struct mem_cgroup *memcg);void lru_gen_release_memcg (struct mem_cgroup *memcg); -void lru_gen_soft_reclaim (struct mem_cgroup *memcg,int nid);void max_lru_gen_memcg (struct mem_cgroup *memcg,int nid);bool recheck_lru_gen_max_memcg (struct mem_cgroup *memcg,int nid);void lru_gen_reparent_memcg (struct mem_cgroup *memcg,struct mem_cgroup *parent,int nid);@@ -737,10 +733,6 @@ static inline void lru_gen_release_memcg(struct mem_cgroup *memcg) { } -static inline void lru_gen_soft_reclaim (struct mem_cgroup *memcg,int nid) -{ -} -static inline void max_lru_gen_memcg (struct mem_cgroup *memcg,int nid) { }mm/vmscan.c +2
-14@@ -4373,7 +4373,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr)/* see the comment on MEMCG_NR_GENS */ enum {MEMCG_LRU_NOP , -MEMCG_LRU_HEAD ,MEMCG_LRU_TAIL ,MEMCG_LRU_OLD ,MEMCG_LRU_YOUNG ,@@ -4395,9 +4394,7 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) new = old = lruvec->lrugen.gen;/* see the comment on MEMCG_NR_GENS */ -if (op ==MEMCG_LRU_HEAD ) - seg =MEMCG_LRU_HEAD ; -else if (op ==MEMCG_LRU_TAIL ) +if (op ==MEMCG_LRU_TAIL ) seg =MEMCG_LRU_TAIL ;else if (op ==MEMCG_LRU_OLD ) new =get_memcg_gen (pgdat->memcg_lru.seq);@@ -4411,7 +4408,7 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op)hlist_nulls_del_rcu (&lruvec->lrugen.list); -if (op ==MEMCG_LRU_HEAD || op ==MEMCG_LRU_OLD ) +if (op ==MEMCG_LRU_OLD )hlist_nulls_add_head_rcu (&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);else hlist_nulls_add_tail_rcu (&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);@@ -4489,15 +4486,6 @@ void lru_gen_release_memcg(struct mem_cgroup *memcg) } } -void lru_gen_soft_reclaim (struct mem_cgroup *memcg,int nid) -{ -struct lruvec *lruvec =get_lruvec (memcg, nid); - -/* see the comment on MEMCG_NR_GENS */ -if (READ_ONCE (lruvec->lrugen.seg) !=MEMCG_LRU_HEAD ) -lru_gen_rotate_memcg (lruvec,MEMCG_LRU_HEAD ); -} -bool recheck_lru_gen_max_memcg (struct mem_cgroup *memcg,int nid) {struct lruvec *lruvec =get_lruvec (memcg, nid);Signature · 1 line
2.53.0-Meta
Signature · 2 lines
Michal Hocko SUSE Labs
T.J. Mercier
Reviewed-byRe: [PATCH 6/9] memcg: remove lru_gen_soft_reclaim()
Quoted 10 lines · Michal Hocko
Quoted 5 lines · Shakeel Butt
The soft limit rbtree was the only caller. Dropping it leaves
MEMCG_LRU_HEADunreachable, since nothing else ever rotates a memcg with that op, so remove the op too and update the memcg LRU comment.Signed-off-by Shakeel Butt <[email protected]>I am not deeply familiar with MGLRU to give my ack but from a quick look this looks right.
This looks good to me.
Quoted 131 lines
Quoted 125 lines
--- include/linux/mmzone.h | 30 +++++++++++------------------- mm/vmscan.c | 16 ++-------------- 2 files changed, 13 insertions(+), 33 deletions(-)include/linux/mmzone.h +11
-19@@ -635,35 +635,32 @@ struct lru_gen_mm_walk {* For each node, memcgs are divided into two generations: the old and the * young. For each generation, memcgs are randomly sharded into multiple bins * to improve scalability. For each bin, the hlist_nulls is virtually divided -* into three segments: the head, the tail and the default. +* into two segments: the tail and the default. * * An onlining memcg is added to the tail of a random bin in the old generation. * The eviction starts at the head of a random bin in the old generation. The * per-node memcg generation counter, whose reminder (mod MEMCG_NR_GENS) indexes * the old generation, is incremented when all its bins become empty. * -* There are four operations: -* 1. MEMCG_LRU_HEAD, which moves a memcg to the head of a random bin in its -* current generation (old or young) and updates its "seg" to "head"; -* 2. MEMCG_LRU_TAIL, which moves a memcg to the tail of a random bin in its +* There are three operations: +* 1. MEMCG_LRU_TAIL, which moves a memcg to the tail of a random bin in its * current generation (old or young) and updates its "seg" to "tail"; -* 3. MEMCG_LRU_OLD, which moves a memcg to the head of a random bin in the old +* 2. MEMCG_LRU_OLD, which moves a memcg to the head of a random bin in the old * generation, updates its "gen" to "old" and resets its "seg" to "default"; -* 4. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the +* 3. MEMCG_LRU_YOUNG, which moves a memcg to the tail of a random bin in the * young generation, updates its "gen" to "young" and resets its "seg" to * "default". * * The events that trigger the above operations are: -* 1. Exceeding the soft limit, which triggers MEMCG_LRU_HEAD; -* 2. The first attempt to reclaim a memcg below low, which triggers +* 1. The first attempt to reclaim a memcg below low, which triggers * MEMCG_LRU_TAIL; -* 3. The first attempt to reclaim a memcg offlined or below reclaimable size +* 2. The first attempt to reclaim a memcg offlined or below reclaimable size * threshold, which triggers MEMCG_LRU_TAIL; -* 4. The second attempt to reclaim a memcg offlined or below reclaimable size +* 3. The second attempt to reclaim a memcg offlined or below reclaimable size * threshold, which triggers MEMCG_LRU_YOUNG; -* 5. Attempting to reclaim a memcg below min, which triggers MEMCG_LRU_YOUNG; -* 6. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG; -* 7. Offlining a memcg, which triggers MEMCG_LRU_OLD. +* 4. Attempting to reclaim a memcg below min, which triggers MEMCG_LRU_YOUNG; +* 5. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG; +* 6. Offlining a memcg, which triggers MEMCG_LRU_OLD. * * Notes: * 1. Memcg LRU only applies to global reclaim, and the round-robin incrementing @@ -696,7 +693,6 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg);void lru_gen_online_memcg (struct mem_cgroup *memcg);void lru_gen_offline_memcg (struct mem_cgroup *memcg);void lru_gen_release_memcg (struct mem_cgroup *memcg); -void lru_gen_soft_reclaim (struct mem_cgroup *memcg,int nid);void max_lru_gen_memcg (struct mem_cgroup *memcg,int nid);bool recheck_lru_gen_max_memcg (struct mem_cgroup *memcg,int nid);void lru_gen_reparent_memcg (struct mem_cgroup *memcg,struct mem_cgroup *parent,int nid);@@ -737,10 +733,6 @@ static inline void lru_gen_release_memcg(struct mem_cgroup *memcg) { } -static inline void lru_gen_soft_reclaim (struct mem_cgroup *memcg,int nid) -{ -} -static inline void max_lru_gen_memcg (struct mem_cgroup *memcg,int nid) { }mm/vmscan.c +2
-15@@ -4373,7 +4373,6 @@ bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw, unsigned int nr)/* see the comment on MEMCG_NR_GENS */ enum {MEMCG_LRU_NOP , -MEMCG_LRU_HEAD ,MEMCG_LRU_TAIL ,MEMCG_LRU_OLD ,MEMCG_LRU_YOUNG ,@@ -4395,9 +4394,7 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) new = old = lruvec->lrugen.gen;/* see the comment on MEMCG_NR_GENS */ -if (op ==MEMCG_LRU_HEAD ) - seg =MEMCG_LRU_HEAD ; -else if (op ==MEMCG_LRU_TAIL ) +if (op ==MEMCG_LRU_TAIL ) seg =MEMCG_LRU_TAIL ;else if (op ==MEMCG_LRU_OLD ) new =get_memcg_gen (pgdat->memcg_lru.seq);@@ -4411,7 +4408,7 @@ static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op)hlist_nulls_del_rcu (&lruvec->lrugen.list); -if (op ==MEMCG_LRU_HEAD || op ==MEMCG_LRU_OLD ) +if (op ==MEMCG_LRU_OLD )hlist_nulls_add_head_rcu (&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);else hlist_nulls_add_tail_rcu (&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]);@@ -4489,15 +4486,6 @@ void lru_gen_release_memcg(struct mem_cgroup *memcg) } } -void lru_gen_soft_reclaim (struct mem_cgroup *memcg,int nid) -{ -struct lruvec *lruvec =get_lruvec (memcg, nid); - -/* see the comment on MEMCG_NR_GENS */ -if (READ_ONCE (lruvec->lrugen.seg) !=MEMCG_LRU_HEAD ) -lru_gen_rotate_memcg (lruvec,MEMCG_LRU_HEAD ); -} -bool recheck_lru_gen_max_memcg (struct mem_cgroup *memcg,int nid) {struct lruvec *lruvec =get_lruvec (memcg, nid); --Quoted 1 line
2.53.0-Meta
--
Michal Hocko
SUSE Labs
Shakeel Butt
maintainerPATCH 7/9 memcg: remove the per-node soft limit tree fields
In reply to Shakeel Butttree_node, usage_in_excess and on_tree only existed for the soft limit rbtree. They also doubled as the buffer between the read-mostly head of struct mem_cgroup_per_node and its update-often tail, so replace them with the explicit padding that CONFIG_MEMCG_V1=n already used.
--- include/linux/memcontrol.h | 13 ------------- 1 file changed, 13 deletions(-)
include/linux/memcontrol.h +0 -13
@@ -95,20 +95,7 @@ struct mem_cgroup_per_node {struct lruvec_stats *lruvec_stats;struct shrinker_info __rcu *shrinker_info; -#ifdef CONFIG_MEMCG_V1 -/* -* Memcg-v1 only stuff in middle as buffer between read mostly fields -* and update often fields to avoid false sharing. If v1 stuff is -* not present, an explicit padding is needed. -*/ - -struct rb_node tree_node;/* RB tree node */ -unsigned long usage_in_excess;/* Set to the value by which */ -/* the soft limit is exceeded*/ -bool on_tree; -#else CACHELINE_PADDING (_pad1_); -#endif /* Fields which get updated often at the end. */ struct lruvec lruvec;
Signature · 1 line
2.53.0-Meta
Re: [PATCH 7/9] memcg: remove the per-node soft limit tree fields
Quoted 6 lines · Shakeel Butt
tree_node,usage_in_excessandon_treeonly existed for the soft limit rbtree. They also doubled as the buffer between the read-mostly head of structmem_cgroup_per_nodeand its update-often tail, so replace them with the explicit padding thatCONFIG_MEMCG_V1=nalready used.Signed-off-by Shakeel Butt <[email protected]>
Thanks!
Quoted 31 lines
--- include/linux/memcontrol.h | 13 ------------- 1 file changed, 13 deletions(-)include/linux/memcontrol.h +0
-13@@ -95,20 +95,7 @@ struct mem_cgroup_per_node {struct lruvec_stats *lruvec_stats;struct shrinker_info __rcu *shrinker_info; -#ifdef CONFIG_MEMCG_V1 -/* -* Memcg-v1 only stuff in middle as buffer between read mostly fields -* and update often fields to avoid false sharing. If v1 stuff is -* not present, an explicit padding is needed. -*/ - -struct rb_node tree_node;/* RB tree node */ -unsigned long usage_in_excess;/* Set to the value by which */ -/* the soft limit is exceeded*/ -bool on_tree; -#else CACHELINE_PADDING (_pad1_); -#endif /* Fields which get updated often at the end. */ struct lruvec lruvec;Signature · 1 line
2.53.0-Meta
Signature · 2 lines
Michal Hocko SUSE Labs
Shakeel Butt
maintainerPATCH 8/9 memcg: remove mem_cgroup->soft_limit
In reply to Shakeel ButtNothing reads it anymore, so the field and the helper that reset it on css alloc and css reset can go.
--- include/linux/memcontrol.h | 2 -- mm/memcontrol-v1.h | 6 ------ mm/memcontrol.c | 2 -- 3 files changed, 10 deletions(-)
include/linux/memcontrol.h +0 -2
@@ -275,8 +275,6 @@ struct mem_cgroup {struct memcg1_events_percpu __percpu *events_percpu; -unsigned long soft_limit; -/* protected by memcg_oom_lock */ bool oom_lock;int under_oom;
mm/memcontrol-v1.h +0 -6
@@ -42,11 +42,6 @@ void memcg1_free_events(struct mem_cgroup *memcg);void memcg1_memcg_init (struct mem_cgroup *memcg); -static inline void memcg1_soft_limit_reset (struct mem_cgroup *memcg) -{ -WRITE_ONCE (memcg->soft_limit,PAGE_COUNTER_MAX ); -} -struct cgroup_taskset ;void memcg1_css_offline (struct mem_cgroup *memcg);
@@ -97,7 +92,6 @@ static inline bool memcg1_alloc_events(struct mem_cgroup *memcg) { return true;static inline void memcg1_free_events (struct mem_cgroup *memcg) {}static inline void memcg1_memcg_init (struct mem_cgroup *memcg) {} -static inline void memcg1_soft_limit_reset (struct mem_cgroup *memcg) {}static inline void memcg1_css_offline (struct mem_cgroup *memcg) {}static inline bool memcg1_oom_prepare (struct mem_cgroup *memcg,bool *locked)
mm/memcontrol.c +0 -2
@@ -4222,7 +4222,6 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)return ERR_CAST (memcg);page_counter_set_high (&memcg->memory,PAGE_COUNTER_MAX ); -memcg1_soft_limit_reset (memcg);#ifdef CONFIG_ZSWAP memcg->zswap_max =PAGE_COUNTER_MAX ;WRITE_ONCE (memcg->zswap_writeback, true);
@@ -4429,7 +4428,6 @@ static void mem_cgroup_css_reset(struct cgroup_subsys_state *css)page_counter_set_min (&memcg->memory,0 );page_counter_set_low (&memcg->memory,0 );page_counter_set_high (&memcg->memory,PAGE_COUNTER_MAX ); -memcg1_soft_limit_reset (memcg);page_counter_set_high (&memcg->swap,PAGE_COUNTER_MAX );memcg_wb_domain_size_changed (memcg); }
Signature · 1 line
2.53.0-Meta
Re: [PATCH 8/9] memcg: remove mem_cgroup->soft_limit
Quoted 4 lines · Shakeel Butt
Nothing reads it anymore, so the field and the helper that reset it on css alloc and css reset can go.
Signed-off-by Shakeel Butt <[email protected]>
Thanks!
Quoted 65 lines
--- include/linux/memcontrol.h | 2 -- mm/memcontrol-v1.h | 6 ------ mm/memcontrol.c | 2 -- 3 files changed, 10 deletions(-)include/linux/memcontrol.h +0
-2@@ -275,8 +275,6 @@ struct mem_cgroup {struct memcg1_events_percpu __percpu *events_percpu; -unsigned long soft_limit; -/* protected by memcg_oom_lock */ bool oom_lock;int under_oom;mm/memcontrol-v1.h +0
-6@@ -42,11 +42,6 @@ void memcg1_free_events(struct mem_cgroup *memcg);void memcg1_memcg_init (struct mem_cgroup *memcg); -static inline void memcg1_soft_limit_reset (struct mem_cgroup *memcg) -{ -WRITE_ONCE (memcg->soft_limit,PAGE_COUNTER_MAX ); -} -struct cgroup_taskset ;void memcg1_css_offline (struct mem_cgroup *memcg);@@ -97,7 +92,6 @@ static inline bool memcg1_alloc_events(struct mem_cgroup *memcg) { return true;static inline void memcg1_free_events (struct mem_cgroup *memcg) {}static inline void memcg1_memcg_init (struct mem_cgroup *memcg) {} -static inline void memcg1_soft_limit_reset (struct mem_cgroup *memcg) {}static inline void memcg1_css_offline (struct mem_cgroup *memcg) {}static inline bool memcg1_oom_prepare (struct mem_cgroup *memcg,bool *locked)mm/memcontrol.c +0
-2@@ -4222,7 +4222,6 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)return ERR_CAST (memcg);page_counter_set_high (&memcg->memory,PAGE_COUNTER_MAX ); -memcg1_soft_limit_reset (memcg);#ifdef CONFIG_ZSWAP memcg->zswap_max =PAGE_COUNTER_MAX ;WRITE_ONCE (memcg->zswap_writeback, true);@@ -4429,7 +4428,6 @@ static void mem_cgroup_css_reset(struct cgroup_subsys_state *css)page_counter_set_min (&memcg->memory,0 );page_counter_set_low (&memcg->memory,0 );page_counter_set_high (&memcg->memory,PAGE_COUNTER_MAX ); -memcg1_soft_limit_reset (memcg);page_counter_set_high (&memcg->swap,PAGE_COUNTER_MAX );memcg_wb_domain_size_changed (memcg); }Signature · 1 line
2.53.0-Meta
Signature · 2 lines
Michal Hocko SUSE Labs
Shakeel Butt
maintainerPATCH 9/9 memcg: simplify v1 event ratelimiting
In reply to Shakeel ButtThresholds are the only periodic v1 event left, so the target enum, the per-cpu target array and the switch in memcg1_event_ratelimit() all collapse to a single counter.
memcg1_check_events() no longer needs a node id either, which lets memcg1_uncharge_batch() drop its nid argument and struct uncharge_gather drop the field feeding it.
--- mm/memcontrol-v1.c | 43 +++++++++++-------------------------------- mm/memcontrol-v1.h | 4 ++-- mm/memcontrol.c | 4 +--- 3 files changed, 14 insertions(+), 37 deletions(-)
mm/memcontrol-v1.c +11 -32
@@ -200,15 +200,9 @@ static void mem_cgroup_threshold(struct mem_cgroup *memcg)* to trigger some periodic events. This is straightforward and better * than using jiffies etc. to handle periodic memcg event. */ -enum mem_cgroup_events_target { -MEM_CGROUP_TARGET_THRESH , -MEM_CGROUP_TARGET_SOFTLIMIT , -MEM_CGROUP_NTARGETS , -}; -struct memcg1_events_percpu {unsigned long nr_page_events; -unsigned long targets[MEM_CGROUP_NTARGETS ]; +unsigned long threshold_target; };static void memcg1_charge_statistics (struct mem_cgroup *memcg,int nr_pages)
@@ -225,43 +219,28 @@ static void memcg1_charge_statistics(struct mem_cgroup *memcg, int nr_pages) }#define THRESHOLDS_EVENTS_TARGET 128 -#define SOFTLIMIT_EVENTS_TARGET 1024 -static bool memcg1_event_ratelimit (struct mem_cgroup *memcg, -enum mem_cgroup_events_target target) +static bool memcg1_event_ratelimit (struct mem_cgroup *memcg) {unsigned long val, next; val =__this_cpu_read (memcg->events_percpu->nr_page_events); - next =__this_cpu_read (memcg->events_percpu->targets[target]); + next =__this_cpu_read (memcg->events_percpu->threshold_target);/* from time_after() in jiffies.h */ if ((long )(next - val) <0 ) { -switch (target) { -case MEM_CGROUP_TARGET_THRESH : - next = val +THRESHOLDS_EVENTS_TARGET ; -break ; -case MEM_CGROUP_TARGET_SOFTLIMIT : - next = val +SOFTLIMIT_EVENTS_TARGET ; -break ; -default : -break ; - } -__this_cpu_write (memcg->events_percpu->targets[target], next); +__this_cpu_write (memcg->events_percpu->threshold_target, + val +THRESHOLDS_EVENTS_TARGET );return true; }return false; } -/* -* Check events in order. -* -*/ -static void memcg1_check_events (struct mem_cgroup *memcg,int nid) +static void memcg1_check_events (struct mem_cgroup *memcg) {if (IS_ENABLED (CONFIG_PREEMPT_RT ))return ; -if (unlikely (memcg1_event_ratelimit (memcg,MEM_CGROUP_TARGET_THRESH ))) +if (unlikely (memcg1_event_ratelimit (memcg)))mem_cgroup_threshold (memcg); }
@@ -271,7 +250,7 @@ void memcg1_commit_charge(struct folio *folio, struct mem_cgroup *memcg)local_irq_save (flags);memcg1_charge_statistics (memcg,folio_nr_pages (folio)); -memcg1_check_events (memcg,folio_nid (folio)); +memcg1_check_events (memcg);local_irq_restore (flags); }
@@ -344,7 +323,7 @@ void __memcg1_swapout(struct folio *folio, struct swap_cluster_info *ci)VM_WARN_ON_IRQS_ENABLED ();memcg1_charge_statistics (memcg, -folio_nr_pages (folio));preempt_enable_nested (); -memcg1_check_events (memcg,folio_nid (folio)); +memcg1_check_events (memcg);rcu_read_unlock ();obj_cgroup_put (objcg);
@@ -398,14 +377,14 @@ void memcg1_swapin(struct folio *folio)#endif void memcg1_uncharge_batch (struct mem_cgroup *memcg,unsigned long pgpgout, -unsigned long nr_memory,int nid) +unsigned long nr_memory) {unsigned long flags;local_irq_save (flags);count_memcg_events (memcg,PGPGOUT , pgpgout);__this_cpu_add (memcg->events_percpu->nr_page_events, nr_memory); -memcg1_check_events (memcg, nid); +memcg1_check_events (memcg);local_irq_restore (flags); }
mm/memcontrol-v1.h +2 -2
@@ -59,7 +59,7 @@ void memcg1_oom_recover(struct mem_cgroup *memcg);void memcg1_commit_charge (struct folio *folio,struct mem_cgroup *memcg);void memcg1_uncharge_batch (struct mem_cgroup *memcg,unsigned long pgpgout, -unsigned long nr_memory,int nid); +unsigned long nr_memory);void memcg1_stat_format (struct mem_cgroup *memcg,struct seq_buf *s);void reparent_memcg1_state_local (struct mem_cgroup *memcg,struct mem_cgroup *parent);
@@ -107,7 +107,7 @@ static inline void memcg1_commit_charge(struct folio *folio,static inline void memcg1_uncharge_batch (struct mem_cgroup *memcg,unsigned long pgpgout, -unsigned long nr_memory,int nid) {} +unsigned long nr_memory) {}static inline void memcg1_stat_format (struct mem_cgroup *memcg,struct seq_buf *s) {}
mm/memcontrol.c +1 -3
@@ -5293,7 +5293,6 @@ struct uncharge_gather {unsigned long nr_memory;unsigned long pgpgout;unsigned long nr_kmem; -int nid; };static inline void uncharge_gather_clear (struct uncharge_gather *ug)
@@ -5316,7 +5315,7 @@ static void uncharge_batch(const struct uncharge_gather *ug)memcg1_oom_recover (memcg); } -memcg1_uncharge_batch (memcg, ug->pgpgout, ug->nr_memory, ug->nid); +memcg1_uncharge_batch (memcg, ug->pgpgout, ug->nr_memory);rcu_read_unlock ();/* drop reference from uncharge_folio */
@@ -5345,7 +5344,6 @@ static void uncharge_folio(struct folio *folio, struct uncharge_gather *ug)uncharge_gather_clear (ug); } ug->objcg = objcg; - ug->nid =folio_nid (folio);/* pairs with obj_cgroup_put in uncharge_batch */ obj_cgroup_get (objcg);
Signature · 1 line
2.53.0-Meta
Re: [PATCH 9/9] memcg: simplify v1 event ratelimiting
Quoted 9 lines · Shakeel Butt
Thresholds are the only periodic v1 event left, so the target enum, the per-cpu target array and the switch in
memcg1_event_ratelimit()all collapse to a single counter.
memcg1_check_events()no longer needs a node id either, which letsmemcg1_uncharge_batch()drop its nid argument and structuncharge_gatherdrop the field feeding it.Signed-off-by Shakeel Butt <[email protected]>
Thanks!
Quoted 165 lines
--- mm/memcontrol-v1.c | 43 +++++++++++-------------------------------- mm/memcontrol-v1.h | 4 ++-- mm/memcontrol.c | 4 +--- 3 files changed, 14 insertions(+), 37 deletions(-)mm/memcontrol-v1.c +11
-32@@ -200,15 +200,9 @@ static void mem_cgroup_threshold(struct mem_cgroup *memcg)* to trigger some periodic events. This is straightforward and better * than using jiffies etc. to handle periodic memcg event. */ -enum mem_cgroup_events_target { -MEM_CGROUP_TARGET_THRESH , -MEM_CGROUP_TARGET_SOFTLIMIT , -MEM_CGROUP_NTARGETS , -}; -struct memcg1_events_percpu {unsigned long nr_page_events; -unsigned long targets[MEM_CGROUP_NTARGETS ]; +unsigned long threshold_target; };static void memcg1_charge_statistics (struct mem_cgroup *memcg,int nr_pages)@@ -225,43 +219,28 @@ static void memcg1_charge_statistics(struct mem_cgroup *memcg, int nr_pages) }#define THRESHOLDS_EVENTS_TARGET 128 -#define SOFTLIMIT_EVENTS_TARGET 1024 -static bool memcg1_event_ratelimit (struct mem_cgroup *memcg, -enum mem_cgroup_events_target target) +static bool memcg1_event_ratelimit (struct mem_cgroup *memcg) {unsigned long val, next; val =__this_cpu_read (memcg->events_percpu->nr_page_events); - next =__this_cpu_read (memcg->events_percpu->targets[target]); + next =__this_cpu_read (memcg->events_percpu->threshold_target);/* from time_after() in jiffies.h */ if ((long )(next - val) <0 ) { -switch (target) { -case MEM_CGROUP_TARGET_THRESH : - next = val +THRESHOLDS_EVENTS_TARGET ; -break ; -case MEM_CGROUP_TARGET_SOFTLIMIT : - next = val +SOFTLIMIT_EVENTS_TARGET ; -break ; -default : -break ; - } -__this_cpu_write (memcg->events_percpu->targets[target], next); +__this_cpu_write (memcg->events_percpu->threshold_target, + val +THRESHOLDS_EVENTS_TARGET );return true; }return false; } -/* -* Check events in order. -* -*/ -static void memcg1_check_events (struct mem_cgroup *memcg,int nid) +static void memcg1_check_events (struct mem_cgroup *memcg) {if (IS_ENABLED (CONFIG_PREEMPT_RT ))return ; -if (unlikely (memcg1_event_ratelimit (memcg,MEM_CGROUP_TARGET_THRESH ))) +if (unlikely (memcg1_event_ratelimit (memcg)))mem_cgroup_threshold (memcg); }@@ -271,7 +250,7 @@ void memcg1_commit_charge(struct folio *folio, struct mem_cgroup *memcg)local_irq_save (flags);memcg1_charge_statistics (memcg,folio_nr_pages (folio)); -memcg1_check_events (memcg,folio_nid (folio)); +memcg1_check_events (memcg);local_irq_restore (flags); }@@ -344,7 +323,7 @@ void __memcg1_swapout(struct folio *folio, struct swap_cluster_info *ci)VM_WARN_ON_IRQS_ENABLED ();memcg1_charge_statistics (memcg, -folio_nr_pages (folio));preempt_enable_nested (); -memcg1_check_events (memcg,folio_nid (folio)); +memcg1_check_events (memcg);rcu_read_unlock ();obj_cgroup_put (objcg);@@ -398,14 +377,14 @@ void memcg1_swapin(struct folio *folio)#endif void memcg1_uncharge_batch (struct mem_cgroup *memcg,unsigned long pgpgout, -unsigned long nr_memory,int nid) +unsigned long nr_memory) {unsigned long flags;local_irq_save (flags);count_memcg_events (memcg,PGPGOUT , pgpgout);__this_cpu_add (memcg->events_percpu->nr_page_events, nr_memory); -memcg1_check_events (memcg, nid); +memcg1_check_events (memcg);local_irq_restore (flags); }mm/memcontrol-v1.h +2
-2@@ -59,7 +59,7 @@ void memcg1_oom_recover(struct mem_cgroup *memcg);void memcg1_commit_charge (struct folio *folio,struct mem_cgroup *memcg);void memcg1_uncharge_batch (struct mem_cgroup *memcg,unsigned long pgpgout, -unsigned long nr_memory,int nid); +unsigned long nr_memory);void memcg1_stat_format (struct mem_cgroup *memcg,struct seq_buf *s);void reparent_memcg1_state_local (struct mem_cgroup *memcg,struct mem_cgroup *parent);@@ -107,7 +107,7 @@ static inline void memcg1_commit_charge(struct folio *folio,static inline void memcg1_uncharge_batch (struct mem_cgroup *memcg,unsigned long pgpgout, -unsigned long nr_memory,int nid) {} +unsigned long nr_memory) {}static inline void memcg1_stat_format (struct mem_cgroup *memcg,struct seq_buf *s) {}mm/memcontrol.c +1
-3@@ -5293,7 +5293,6 @@ struct uncharge_gather {unsigned long nr_memory;unsigned long pgpgout;unsigned long nr_kmem; -int nid; };static inline void uncharge_gather_clear (struct uncharge_gather *ug)@@ -5316,7 +5315,7 @@ static void uncharge_batch(const struct uncharge_gather *ug)memcg1_oom_recover (memcg); } -memcg1_uncharge_batch (memcg, ug->pgpgout, ug->nr_memory, ug->nid); +memcg1_uncharge_batch (memcg, ug->pgpgout, ug->nr_memory);rcu_read_unlock ();/* drop reference from uncharge_folio */ @@ -5345,7 +5344,6 @@ static void uncharge_folio(struct folio *folio, struct uncharge_gather *ug)uncharge_gather_clear (ug); } ug->objcg = objcg; - ug->nid =folio_nid (folio);/* pairs with obj_cgroup_put in uncharge_batch */ obj_cgroup_get (objcg);Signature · 1 line
2.53.0-Meta
Signature · 2 lines
Michal Hocko SUSE Labs
Quoted 27 lines · Shakeel Butt
Syzbot reported [1] a
set_mm_walk()warning from kswapd. Soft limit reclaim is the only thing that runsshrink_lruvec()from kswapd with a target memcg set, and thus the only way kswapd can reachlru_gen_shrink_lruvec()and in turnset_mm_walk(). The offender,mem_cgroup_shrink_node(), has long carried a "Only used by soft limit reclaim. Do not reuse for anything else." comment and a priority hack, and it simply never got taught about MGLRU.Rather than teach it, let's delete it. The v1 soft limit was deprecated in v6.12 by commit
569c4f62d84a("memcg: initiate deprecation of v1 soft limit"). Nobody has reported depending on it in the ~21 months since, and v2 has covered the same ground for a long time with memory.low and memory.min.Shakeel Butt (9):
memcg: make the v1 soft limit knob inert
memcg: remove v1 soft limit reclaim
memcg: removemem_cgroup_shrink_node()
memcg: remove the soft limit reclaim tracepoints
memcg: remove the soft limit rbtree
memcg: removelru_gen_soft_reclaim()
memcg: remove the per-node soft limit tree fields
memcg: removemem_cgroup->soft_limit
memcg: simplify v1 event ratelimiting
Quoted 10 lines
.../admin-guide/cgroup-v1/memory.rst | 49 +- include/linux/memcontrol.h | 27 -- include/linux/mmzone.h | 30 +- include/trace/events/vmscan.h | 14 - mm/internal.h | 4 - mm/memcontrol-v1.c | 435 ++---------------- mm/memcontrol-v1.h | 12 +- mm/memcontrol.c | 7 +- mm/vmscan.c | 96 +--- 9 files changed, 66 insertions(+), 608 deletions(-)
This is a gorgeous diffstat :)
Obviously not my area but looking over it, all LGTM so feel free to add:
To the whole series!
Quoted 4 lines
--
2.53.0-Meta
--
Cheers, Lorenzo
Shakeel Butt
maintainerQuoted 39 lines · Lorenzo Stoakes (ARM)
Quoted 27 lines · Shakeel Butt
Syzbot reported [1] a
set_mm_walk()warning from kswapd. Soft limit reclaim is the only thing that runsshrink_lruvec()from kswapd with a target memcg set, and thus the only way kswapd can reachlru_gen_shrink_lruvec()and in turnset_mm_walk(). The offender,mem_cgroup_shrink_node(), has long carried a "Only used by soft limit reclaim. Do not reuse for anything else." comment and a priority hack, and it simply never got taught about MGLRU.Rather than teach it, let's delete it. The v1 soft limit was deprecated in v6.12 by commit
569c4f62d84a("memcg: initiate deprecation of v1 soft limit"). Nobody has reported depending on it in the ~21 months since, and v2 has covered the same ground for a long time with memory.low and memory.min.Shakeel Butt (9):
memcg: make the v1 soft limit knob inert
memcg: remove v1 soft limit reclaim
memcg: removemem_cgroup_shrink_node()
memcg: remove the soft limit reclaim tracepoints
memcg: remove the soft limit rbtree
memcg: removelru_gen_soft_reclaim()
memcg: remove the per-node soft limit tree fields
memcg: removemem_cgroup->soft_limit
memcg: simplify v1 event ratelimitingQuoted 10 lines
.../admin-guide/cgroup-v1/memory.rst | 49 +- include/linux/memcontrol.h | 27 -- include/linux/mmzone.h | 30 +- include/trace/events/vmscan.h | 14 - mm/internal.h | 4 - mm/memcontrol-v1.c | 435 ++---------------- mm/memcontrol-v1.h | 12 +- mm/memcontrol.c | 7 +- mm/vmscan.c | 96 +--- 9 files changed, 66 insertions(+), 608 deletions(-)
Quoted 7 lines
This is a gorgeous diffstat :)
Obviously not my area but looking over it, all LGTM so feel free to add:
To the whole series!
Thanks for the review.
Shakeel Butt
maintainerQuoted 8 lines · Shakeel Butt
Syzbot reported [1] a
set_mm_walk()warning from kswapd. Soft limit reclaim is the only thing that runsshrink_lruvec()from kswapd with a target memcg set, and thus the only way kswapd can reachlru_gen_shrink_lruvec()and in turnset_mm_walk(). The offender,mem_cgroup_shrink_node(), has long carried a "Only used by soft limit reclaim. Do not reuse for anything else." comment and a priority hack, and it simply never got taught about MGLRU.
Quoted 7 lines
Rather than teach it, let's delete it. The v1 soft limit was deprecated in v6.12 by commit
569c4f62d84a("memcg: initiate deprecation of v1 soft limit"). Nobody has reported depending on it in the ~21 months since, and v2 has covered the same ground for a long time with memory.low and memory.min.
Andrew, should I resend this series (without the first patch) or will you pick it up?
Quoted 26 lines
Shakeel Butt (9):
memcg: make the v1 soft limit knob inert
memcg: remove v1 soft limit reclaim
memcg: removemem_cgroup_shrink_node()
memcg: remove the soft limit reclaim tracepoints
memcg: remove the soft limit rbtree
memcg: removelru_gen_soft_reclaim()
memcg: remove the per-node soft limit tree fields
memcg: removemem_cgroup->soft_limit
memcg: simplify v1 event ratelimiting.../admin-guide/cgroup-v1/memory.rst | 49 +- include/linux/memcontrol.h | 27 -- include/linux/mmzone.h | 30 +- include/trace/events/vmscan.h | 14 - mm/internal.h | 4 - mm/memcontrol-v1.c | 435 ++---------------- mm/memcontrol-v1.h | 12 +- mm/memcontrol.c | 7 +- mm/vmscan.c | 96 +--- 9 files changed, 66 insertions(+), 608 deletions(-)Signature · 1 line
2.53.0-Meta
Andrew Morton
maintainerQuoted 15 lines · On Fri, 28 Aug 2026 19:23:19 -0700 Shakeel Butt <[email protected]> wrote:
Quoted 14 lines · Shakeel Butt
Syzbot reported [1] a
set_mm_walk()warning from kswapd. Soft limit reclaim is the only thing that runsshrink_lruvec()from kswapd with a target memcg set, and thus the only way kswapd can reachlru_gen_shrink_lruvec()and in turnset_mm_walk(). The offender,mem_cgroup_shrink_node(), has long carried a "Only used by soft limit reclaim. Do not reuse for anything else." comment and a priority hack, and it simply never got taught about MGLRU.Rather than teach it, let's delete it. The v1 soft limit was deprecated in v6.12 by commit
569c4f62d84a("memcg: initiate deprecation of v1 soft limit"). Nobody has reported depending on it in the ~21 months since, and v2 has covered the same ground for a long time with memory.low and memory.min.
Quoted 4 lines
Quoted 1 line
Andrew, should I resend this series (without the first patch) or will you pick it up?
I added the series, thanks.
The [1/9] has already been queued in mm-hotfixes as a backportable hotfix. So I added it as an 8-patch series. Because of this the cover letter of that series is now irrelevant, so could you please prepare a brief replacement for me to paste in?
Sashiko suggests that there's more that can be removed:
https://sashiko.dev/#/patchset/[email protected]
So maybe an 8-patch v2 series is appropriate, your call.
Shakeel Butt
maintainerQuoted 29 lines · Andrew Morton
Quoted 15 lines · On Fri, 28 Aug 2026 19:23:19 -0700 Shakeel Butt <[email protected]> wrote:
Quoted 14 lines · Shakeel Butt
Syzbot reported [1] a
set_mm_walk()warning from kswapd. Soft limit reclaim is the only thing that runsshrink_lruvec()from kswapd with a target memcg set, and thus the only way kswapd can reachlru_gen_shrink_lruvec()and in turnset_mm_walk(). The offender,mem_cgroup_shrink_node(), has long carried a "Only used by soft limit reclaim. Do not reuse for anything else." comment and a priority hack, and it simply never got taught about MGLRU.Rather than teach it, let's delete it. The v1 soft limit was deprecated in v6.12 by commit
569c4f62d84a("memcg: initiate deprecation of v1 soft limit"). Nobody has reported depending on it in the ~21 months since, and v2 has covered the same ground for a long time with memory.low and memory.min.Quoted 4 lines
Quoted 1 line
Andrew, should I resend this series (without the first patch) or will you pick it up?
I added the series, thanks.
The [1/9] has already been queued in mm-hotfixes as a backportable hotfix. So I added it as an 8-patch series. Because of this the cover letter of that series is now irrelevant, so could you please prepare a brief replacement for me to paste in?
Quoted 4 lines
Sashiko suggests that there's more that can be removed:
https://sashiko.dev/#/patchset/[email protected]So maybe an 8-patch v2 series is appropriate, your call.
I will send 8-patch v2 series with Sashiko's comments resolved by next week.