[RFC PATCH 8/8] cgroup: add memory_tiered_limits cgroup mount option
liuqiqi-UOlijcLmZ/[email protected]
| Newsgroups | gmane.linux.kernel.cgroups,gmane.linux.kernel.mm,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Qiqi Liu <liuqiqi-UOlijcLmZ/[email protected]> 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-UOlijcLmZ/[email protected]> --- 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) 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); -- 2.43.0