The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Tao Cui <cui.tao@linux.dev>
To: liuqiqi@kylinos.cn, linux-mm@kvack.org
Cc: cui.tao@linux.dev, tj@kernel.org, mkoutny@suse.com,
	hannes@cmpxchg.org, mhocko@kernel.org, roman.gushchin@linux.dev,
	shakeel.butt@linux.dev, muchun.song@linux.dev,
	akpm@linux-foundation.org, cgroups@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH 8/8] cgroup: add memory_tiered_limits cgroup mount option
Date: Tue, 18 Aug 2026 12:56:05 +0800	[thread overview]
Message-ID: <43f12802-de69-45a2-bb97-317a6cc2ee4b@linux.dev> (raw)
In-Reply-To: <20260818023121.100613-9-liuqiqi@kylinos.cn>



在 2026/8/18 10:31, liuqiqi@kylinos.cn 写道:
> From: Qiqi Liu <liuqiqi@kylinos.cn>
> 
> Introduce the memory_tiered_limits cgroup v2 mount option to enable
> tier-aware memory control. The option follows the same pattern as
> memory_recursiveprot and memory_hugetlb_accounting.
> 
> When enabled, per-tier accounting, charging, stock batching, auto-
> derivation, and the memory.tier control file are active. When disabled
> (default), all tier-specific code is gated at entry points: no counters
> are created, no charge/uncharge occurs, and memory.tier remains empty.
> This ensures no measurable overhead for systems that do not opt in.
> 
> Usage:
>   mount -t cgroup2 none /sys/fs/cgroup -o memory_tiered_limits
> 
> Because the cgroup2 mount is owned by the init system, early-boot
> cgroups are created before userspace can specify mount options. To
> cover these boot-time cgroups, mirror the cgroup_favordynmods approach
> and add a kernel command-line parameter,
> cgroup_memory_tiered_limits=<bool>.
> This sets CGRP_ROOT_MEMORY_TIERED_LIMITS on all cgroup2 mounts by
> default. The mount option remains available for runtime, per-mount
> control.
> 
> Signed-off-by: Qiqi Liu <liuqiqi@kylinos.cn>
> ---
>  include/linux/cgroup-defs.h |  5 +++++
>  include/linux/memcontrol.h  | 12 ++++++++++++
>  kernel/cgroup/cgroup.c      | 21 +++++++++++++++++++++
>  mm/memcontrol.c             | 22 ++++++++++++++++++----
>  4 files changed, 56 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
> index de2cd6238c2a..4324d68dbce9 100644
> --- a/include/linux/cgroup-defs.h
> +++ b/include/linux/cgroup-defs.h
> @@ -129,6 +129,11 @@ enum {
>  	 * Enable legacy local pids.events.
>  	 */
>  	CGRP_ROOT_PIDS_LOCAL_EVENTS = (1 << 20),
> +
> +	/*
> +	 * Enable tier-aware limits for the memory controller.
> +	 */
> +	CGRP_ROOT_MEMORY_TIERED_LIMITS = (1 << 21),
>  };
>  
>  /* cftype->flags */
> diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
> index 8848bc5eeb24..094b9a839977 100644
> --- a/include/linux/memcontrol.h
> +++ b/include/linux/memcontrol.h
> @@ -544,6 +544,18 @@ static inline bool mem_cgroup_disabled(void)
>  	return !cgroup_subsys_enabled(memory_cgrp_subsys);
>  }
>  
> +#ifdef CONFIG_NUMA
> +static inline bool mem_cgroup_tiered_limits(void)
> +{
> +	return cgrp_dfl_root.flags & CGRP_ROOT_MEMORY_TIERED_LIMITS;
> +}
> +#else
> +static inline bool mem_cgroup_tiered_limits(void)
> +{
> +	return false;
> +}
> +#endif
> +
>  static inline void mem_cgroup_protection(struct mem_cgroup *root,
>  					 struct mem_cgroup *memcg,
>  					 unsigned long *min,
> diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
> index 38f8d9df8fbc..da94bcda0859 100644
> --- a/kernel/cgroup/cgroup.c
> +++ b/kernel/cgroup/cgroup.c
> @@ -231,6 +231,7 @@ static u32 have_release_callback __read_mostly;
>  static u32 have_canfork_callback __read_mostly;
>  
>  static bool have_favordynmods __ro_after_init = IS_ENABLED(CONFIG_CGROUP_FAVOR_DYNMODS);
> +static bool have_memory_tiered_limits __ro_after_init;
>  
>  /*
>   * Write protected by cgroup_mutex and write-lock of cgroup_threadgroup_rwsem,
> @@ -1985,6 +1986,7 @@ enum cgroup2_param {
>  	Opt_memory_recursiveprot,
>  	Opt_memory_hugetlb_accounting,
>  	Opt_pids_localevents,
> +	Opt_memory_tiered_limits,
>  	nr__cgroup2_params
>  };
>  
> @@ -1995,6 +1997,7 @@ static const struct fs_parameter_spec cgroup2_fs_parameters[] = {
>  	fsparam_flag("memory_recursiveprot",	Opt_memory_recursiveprot),
>  	fsparam_flag("memory_hugetlb_accounting", Opt_memory_hugetlb_accounting),
>  	fsparam_flag("pids_localevents",	Opt_pids_localevents),
> +	fsparam_flag("memory_tiered_limits",	Opt_memory_tiered_limits),
>  	{}
>  };
>  
> @@ -2027,6 +2030,9 @@ static int cgroup2_parse_param(struct fs_context *fc, struct fs_parameter *param
>  	case Opt_pids_localevents:
>  		ctx->flags |= CGRP_ROOT_PIDS_LOCAL_EVENTS;
>  		return 0;
> +	case Opt_memory_tiered_limits:
> +		ctx->flags |= CGRP_ROOT_MEMORY_TIERED_LIMITS;
> +		return 0;
>  	}
>  	return -EINVAL;
>  }
> @@ -2068,6 +2074,11 @@ static void apply_cgroup_root_flags(unsigned int root_flags)
>  			cgrp_dfl_root.flags |= CGRP_ROOT_PIDS_LOCAL_EVENTS;
>  		else
>  			cgrp_dfl_root.flags &= ~CGRP_ROOT_PIDS_LOCAL_EVENTS;
> +
> +		if (root_flags & CGRP_ROOT_MEMORY_TIERED_LIMITS)
> +			cgrp_dfl_root.flags |= CGRP_ROOT_MEMORY_TIERED_LIMITS;
> +		else
> +			cgrp_dfl_root.flags &= ~CGRP_ROOT_MEMORY_TIERED_LIMITS;
>  	}
>  }
>  
> @@ -2085,6 +2096,8 @@ static int cgroup_show_options(struct seq_file *seq, struct kernfs_root *kf_root
>  		seq_puts(seq, ",memory_hugetlb_accounting");
>  	if (cgrp_dfl_root.flags & CGRP_ROOT_PIDS_LOCAL_EVENTS)
>  		seq_puts(seq, ",pids_localevents");
> +	if (cgrp_dfl_root.flags & CGRP_ROOT_MEMORY_TIERED_LIMITS)
> +		seq_puts(seq, ",memory_tiered_limits");
>  	return 0;
>  }
>  
> @@ -2363,6 +2376,8 @@ static int cgroup_init_fs_context(struct fs_context *fc)
>  
>  	if (have_favordynmods)
>  		ctx->flags |= CGRP_ROOT_FAVOR_DYNMODS;
> +	if (have_memory_tiered_limits)
> +		ctx->flags |= CGRP_ROOT_MEMORY_TIERED_LIMITS;
>  
>  	return 0;
>  }
> @@ -7214,6 +7229,12 @@ static int __init cgroup_favordynmods_setup(char *str)
>  }
>  __setup("cgroup_favordynmods=", cgroup_favordynmods_setup);
>  
> +static int __init cgroup_memory_tiered_limits_setup(char *str)
> +{
> +	return (kstrtobool(str, &have_memory_tiered_limits) == 0);
> +}
> +__setup("cgroup_memory_tiered_limits=", cgroup_memory_tiered_limits_setup);
> +
>  /**
>   * css_tryget_online_from_dir - get corresponding css from a cgroup dentry
>   * @dentry: directory dentry of interest
> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
> index f39a702d2301..891051f164ff 100644
> --- a/mm/memcontrol.c
> +++ b/mm/memcontrol.c
> @@ -2462,7 +2462,7 @@ static void memcg_charge_tier_id(struct mem_cgroup *memcg, int tier_id,
>  {
>  	struct memcg_tier_counter *tc;
>  
> -	if (tier_id < 0)
> +	if (!mem_cgroup_tiered_limits() || tier_id < 0)

The cover says remount "affects newly created cgroups only", but the
gate is the live global flag on both charge and uncharge.

(same in memcg_uncharge_tier_id() and refill_tier_stock()).

>  		return;
>  	rcu_read_lock();
>  	tc = memcg_tier_counter_find(memcg, tier_id);
> @@ -2476,7 +2476,7 @@ static void memcg_uncharge_tier_id(struct mem_cgroup *memcg, int tier_id,
>  {
>  	struct memcg_tier_counter *tc;
>  
> -	if (tier_id < 0)
> +	if (!mem_cgroup_tiered_limits() || tier_id < 0)
>  		return;
>  	rcu_read_lock();
>  	tc = memcg_tier_counter_find(memcg, tier_id);
> @@ -2581,6 +2581,9 @@ static void tier_update_derived_limits(struct mem_cgroup *memcg)
>  	unsigned long total;
>  	int i, nr_entries;
>  
> +	if (!mem_cgroup_tiered_limits())
> +		return;
> +
>  	spin_lock(&tier_cap_lock);
>  	total = tier_total_capacity;
>  	nr_entries = nr_tier_entries;
> @@ -3198,6 +3201,9 @@ static void refill_tier_stock(struct mem_cgroup *memcg, int tier_id,
>  	uint8_t pages;
>  	int i;
>  
> +	if (!mem_cgroup_tiered_limits())
> +		return;
> +
>  	/* Too big to cache: direct uncharge, leave the stock untouched. */
>  	if (nr_pages > MEMCG_CHARGE_BATCH) {
>  		rcu_read_lock();
> @@ -3252,7 +3258,7 @@ static int try_charge_memcg_tier(struct mem_cgroup *memcg, gfp_t gfp_mask,
>  	bool drained = false;
>  	nodemask_t nodes, *nmp = NULL;
>  
> -	if (tier_id < 0)
> +	if (!mem_cgroup_tiered_limits() || tier_id < 0)
>  		return 0;
>  
>  	rcu_read_lock();
> @@ -4736,7 +4742,7 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
>  		page_counter_init(&memcg->memory, &parent->memory, memcg_on_dfl);
>  		page_counter_init(&memcg->swap, &parent->swap, false);
>  
> -		{
> +		if (mem_cgroup_tiered_limits()) {
>  			int nid, tid;
>  
>  			for_each_online_node(nid) {
> @@ -5459,6 +5465,8 @@ static int memory_tier_show(struct seq_file *m, void *v)
>  	struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
>  	struct memcg_tier_counter *tc;
>  
> +	if (!mem_cgroup_tiered_limits())
> +		return 0;
>  	rcu_read_lock();
>  	list_for_each_entry_rcu(tc, &memcg->tier_counters, list) {
>  		seq_printf(m, "tier%d.current=%llu\n", tc->tier_id,
> @@ -5484,6 +5492,9 @@ static ssize_t memory_tier_write(struct kernfs_open_file *of,
>  	char knob[8], *p;
>  	int tier_id, err;
>  
> +	if (!mem_cgroup_tiered_limits())
> +		return -EOPNOTSUPP;
> +
>  	buf = strstrip(buf);
>  	if (sscanf(buf, "tier%d.%7[^=]", &tier_id, knob) != 2)
>  		return -EINVAL;
> @@ -6267,6 +6278,9 @@ static int __meminit memcg_tier_hotplug_cb(struct notifier_block *self,
>  	struct mem_cgroup *memcg;
>  	int tid;
>  
> +	if (!mem_cgroup_tiered_limits())
> +		return notifier_from_errno(0);
> +
>  	switch (action) {
>  	case NODE_ADDED_FIRST_MEMORY:
>  		tid = node_to_tier_id(nn->nid);


      reply	other threads:[~2026-08-18  4:56 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-18  2:31 [RFC PATCH 0/8] mm/memcontrol: introduce per-tier memory accounting and control liuqiqi
2026-08-18  2:31 ` [RFC PATCH 1/8] mm/memory-tiers: add node_to_tier_id and tier_id_to_nodemask liuqiqi
2026-08-18  2:31 ` [RFC PATCH 2/8] mm/vmscan: add try_to_free_mem_cgroup_pages_nodemask liuqiqi
2026-08-18  2:31 ` [RFC PATCH 3/8] mm/memcontrol: add per-tier page counter infrastructure and lifecycle liuqiqi
2026-08-18  2:31 ` [RFC PATCH 4/8] mm/memcontrol: add per-tier charge and uncharge liuqiqi
2026-08-18  4:32   ` Tao Cui
2026-08-18  2:31 ` [RFC PATCH 5/8] mm/memcontrol: add per-cpu stock for tier charge/uncharge liuqiqi
2026-08-18  2:31 ` [RFC PATCH 6/8] mm/memcontrol: add memory.tier control file liuqiqi
2026-08-18  2:31 ` [RFC PATCH 7/8] mm/memcontrol: auto-derive tier high/max from memory.high/max liuqiqi
2026-08-18  4:46   ` Tao Cui
2026-08-18  2:31 ` [RFC PATCH 8/8] cgroup: add memory_tiered_limits cgroup mount option liuqiqi
2026-08-18  4:56   ` Tao Cui [this message]

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=43f12802-de69-45a2-bb97-317a6cc2ee4b@linux.dev \
    --to=cui.tao@linux.dev \
    --cc=akpm@linux-foundation.org \
    --cc=cgroups@vger.kernel.org \
    --cc=hannes@cmpxchg.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=liuqiqi@kylinos.cn \
    --cc=mhocko@kernel.org \
    --cc=mkoutny@suse.com \
    --cc=muchun.song@linux.dev \
    --cc=roman.gushchin@linux.dev \
    --cc=shakeel.butt@linux.dev \
    --cc=tj@kernel.org \
    /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