Linux cgroups development
 help / color / mirror / Atom feed
From: Michal Hocko <mhocko@suse.com>
To: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	Johannes Weiner <hannes@cmpxchg.org>,
	Roman Gushchin <roman.gushchin@linux.dev>,
	Muchun Song <muchun.song@linux.dev>,
	David Hildenbrand <david@kernel.org>,
	Lorenzo Stoakes <ljs@kernel.org>,
	Kairui Song <kasong@tencent.com>, Qi Zheng <qi.zheng@linux.dev>,
	Barry Song <baohua@kernel.org>,
	Axel Rasmussen <axelrasmussen@google.com>,
	Meta kernel team <kernel-team@meta.com>,
	linux-mm@kvack.org, cgroups@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/9] memcg: remove v1 soft limit reclaim
Date: Thu, 13 Aug 2026 10:24:14 +0200	[thread overview]
Message-ID: <an1_LgFQRT7oeskJ@tiehlicka> (raw)
In-Reply-To: <20260811203203.3456029-3-shakeel.butt@linux.dev>

On Tue 11-08-26 13:31:56, Shakeel Butt wrote:
> 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.
> 
> 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.
> 
> Signed-off-by: Shakeel Butt <shakeel.butt@linux.dev>

Acked-by: Michal Hocko <mhocko@suse.com>
Thanks!

> ---
>  include/linux/memcontrol.h |  12 ---
>  mm/memcontrol-v1.c         | 175 -------------------------------------
>  mm/vmscan.c                |  39 ++-------
>  3 files changed, 6 insertions(+), 220 deletions(-)
> 
> diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
> index e78bc98ab229..7b02f1b3bb88 100644
> --- a/include/linux/memcontrol.h
> +++ b/include/linux/memcontrol.h
> @@ -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;
> diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c
> index 05ef55cae4dc..b38b8d0f7f51 100644
> --- a/mm/memcontrol-v1.c
> +++ b/mm/memcontrol-v1.c
> @@ -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)
>  {
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index be6bd26e8c57..032b14793d91 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -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
> -- 
> 2.53.0-Meta

-- 
Michal Hocko
SUSE Labs

  reply	other threads:[~2026-08-13  8:24 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-11 20:31 [PATCH for-7.4 0/9] memcg: remove the v1 soft limit Shakeel Butt
2026-08-11 20:31 ` [PATCH 1/9] memcg: make the v1 soft limit knob inert Shakeel Butt
2026-08-12 22:50   ` Andrew Morton
2026-08-12 23:40     ` Shakeel Butt
2026-08-13  8:22   ` Michal Hocko
2026-08-11 20:31 ` [PATCH 2/9] memcg: remove v1 soft limit reclaim Shakeel Butt
2026-08-13  8:24   ` Michal Hocko [this message]
2026-08-11 20:31 ` [PATCH 3/9] memcg: remove mem_cgroup_shrink_node() Shakeel Butt
2026-08-13  8:24   ` Michal Hocko
2026-08-11 20:31 ` [PATCH 4/9] memcg: remove the soft limit reclaim tracepoints Shakeel Butt
2026-08-13  8:25   ` Michal Hocko
2026-08-11 20:31 ` [PATCH 5/9] memcg: remove the soft limit rbtree Shakeel Butt
2026-08-13  8:25   ` Michal Hocko
2026-08-11 20:32 ` [PATCH 6/9] memcg: remove lru_gen_soft_reclaim() Shakeel Butt
2026-08-13  8:26   ` Michal Hocko
2026-08-11 20:32 ` [PATCH 7/9] memcg: remove the per-node soft limit tree fields Shakeel Butt
2026-08-13  8:27   ` Michal Hocko
2026-08-11 20:32 ` [PATCH 8/9] memcg: remove mem_cgroup->soft_limit Shakeel Butt
2026-08-13  8:27   ` Michal Hocko
2026-08-11 20:32 ` [PATCH 9/9] memcg: simplify v1 event ratelimiting Shakeel Butt
2026-08-13  8:28   ` Michal Hocko
2026-08-13  9:27 ` [PATCH for-7.4 0/9] memcg: remove the v1 soft limit Lorenzo Stoakes (ARM)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=an1_LgFQRT7oeskJ@tiehlicka \
    --to=mhocko@suse.com \
    --cc=akpm@linux-foundation.org \
    --cc=axelrasmussen@google.com \
    --cc=baohua@kernel.org \
    --cc=cgroups@vger.kernel.org \
    --cc=david@kernel.org \
    --cc=hannes@cmpxchg.org \
    --cc=kasong@tencent.com \
    --cc=kernel-team@meta.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=ljs@kernel.org \
    --cc=muchun.song@linux.dev \
    --cc=qi.zheng@linux.dev \
    --cc=roman.gushchin@linux.dev \
    --cc=shakeel.butt@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox