include/linux/cgroup-defs.h | 8 +++--- include/trace/events/cgroup.h | 2 +- kernel/cgroup/cgroup-internal.h | 8 +++--- kernel/cgroup/cgroup-v1.c | 12 ++++----- kernel/cgroup/cgroup.c | 46 ++++++++++++++++----------------- kernel/cgroup/debug.c | 2 +- 6 files changed, 39 insertions(+), 39 deletions(-)
From: Chen Ridong <chenridong@huawei.com>
The current cgroup subsystem limit of 16 is insufficient, as the number of
subsystems has already reached this maximum. Attempting to add new
subsystems beyond this limit results in boot failures.
This patch increases the maximum number of supported cgroup subsystems from
16 to 32, providing adequate headroom for future subsystem additions.
Signed-off-by: Chen Ridong <chenridong@huawei.com>
---
include/linux/cgroup-defs.h | 8 +++---
include/trace/events/cgroup.h | 2 +-
kernel/cgroup/cgroup-internal.h | 8 +++---
kernel/cgroup/cgroup-v1.c | 12 ++++-----
kernel/cgroup/cgroup.c | 46 ++++++++++++++++-----------------
kernel/cgroup/debug.c | 2 +-
6 files changed, 39 insertions(+), 39 deletions(-)
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index f7cc60de0058..bb92f5c169ca 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -535,10 +535,10 @@ struct cgroup {
* one which may have more subsystems enabled. Controller knobs
* are made available iff it's enabled in ->subtree_control.
*/
- u16 subtree_control;
- u16 subtree_ss_mask;
- u16 old_subtree_control;
- u16 old_subtree_ss_mask;
+ u32 subtree_control;
+ u32 subtree_ss_mask;
+ u32 old_subtree_control;
+ u32 old_subtree_ss_mask;
/* Private pointers for each registered subsystem */
struct cgroup_subsys_state __rcu *subsys[CGROUP_SUBSYS_COUNT];
diff --git a/include/trace/events/cgroup.h b/include/trace/events/cgroup.h
index ba9229af9a34..b736da06340a 100644
--- a/include/trace/events/cgroup.h
+++ b/include/trace/events/cgroup.h
@@ -16,7 +16,7 @@ DECLARE_EVENT_CLASS(cgroup_root,
TP_STRUCT__entry(
__field( int, root )
- __field( u16, ss_mask )
+ __field( u32, ss_mask )
__string( name, root->name )
),
diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h
index 22051b4f1ccb..3bfe37693d68 100644
--- a/kernel/cgroup/cgroup-internal.h
+++ b/kernel/cgroup/cgroup-internal.h
@@ -52,7 +52,7 @@ struct cgroup_fs_context {
bool cpuset_clone_children;
bool none; /* User explicitly requested empty subsystem */
bool all_ss; /* Seen 'all' option */
- u16 subsys_mask; /* Selected subsystems */
+ u32 subsys_mask; /* Selected subsystems */
char *name; /* Hierarchy name */
char *release_agent; /* Path for release notifications */
};
@@ -146,7 +146,7 @@ struct cgroup_mgctx {
struct cgroup_taskset tset;
/* subsystems affected by migration */
- u16 ss_mask;
+ u32 ss_mask;
};
#define CGROUP_TASKSET_INIT(tset) \
@@ -235,8 +235,8 @@ int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen,
void cgroup_favor_dynmods(struct cgroup_root *root, bool favor);
void cgroup_free_root(struct cgroup_root *root);
void init_cgroup_root(struct cgroup_fs_context *ctx);
-int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask);
-int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask);
+int cgroup_setup_root(struct cgroup_root *root, u32 ss_mask);
+int rebind_subsystems(struct cgroup_root *dst_root, u32 ss_mask);
int cgroup_do_get_tree(struct fs_context *fc);
int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp);
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index a9e029b570c8..724950c4b690 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -28,7 +28,7 @@
#define CGROUP_PIDLIST_DESTROY_DELAY HZ
/* Controllers blocked by the commandline in v1 */
-static u16 cgroup_no_v1_mask;
+static u32 cgroup_no_v1_mask;
/* disable named v1 mounts */
static bool cgroup_no_v1_named;
@@ -1037,13 +1037,13 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
static int check_cgroupfs_options(struct fs_context *fc)
{
struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
- u16 mask = U16_MAX;
- u16 enabled = 0;
+ u32 mask = U32_MAX;
+ u32 enabled = 0;
struct cgroup_subsys *ss;
int i;
#ifdef CONFIG_CPUSETS
- mask = ~((u16)1 << cpuset_cgrp_id);
+ mask = ~((u32)1 << cpuset_cgrp_id);
#endif
for_each_subsys(ss, i)
if (cgroup_ssid_enabled(i) && !cgroup1_ssid_disabled(i) &&
@@ -1095,7 +1095,7 @@ int cgroup1_reconfigure(struct fs_context *fc)
struct kernfs_root *kf_root = kernfs_root_from_sb(fc->root->d_sb);
struct cgroup_root *root = cgroup_root_from_kf(kf_root);
int ret = 0;
- u16 added_mask, removed_mask;
+ u32 added_mask, removed_mask;
cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp);
@@ -1343,7 +1343,7 @@ static int __init cgroup_no_v1(char *str)
continue;
if (!strcmp(token, "all")) {
- cgroup_no_v1_mask = U16_MAX;
+ cgroup_no_v1_mask = U32_MAX;
continue;
}
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 94788bd1fdf0..8af4351536cf 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -203,13 +203,13 @@ EXPORT_SYMBOL_GPL(cgrp_dfl_root);
bool cgrp_dfl_visible;
/* some controllers are not supported in the default hierarchy */
-static u16 cgrp_dfl_inhibit_ss_mask;
+static u32 cgrp_dfl_inhibit_ss_mask;
/* some controllers are implicitly enabled on the default hierarchy */
-static u16 cgrp_dfl_implicit_ss_mask;
+static u32 cgrp_dfl_implicit_ss_mask;
/* some controllers can be threaded on the default hierarchy */
-static u16 cgrp_dfl_threaded_ss_mask;
+static u32 cgrp_dfl_threaded_ss_mask;
/* The list of hierarchy roots */
LIST_HEAD(cgroup_roots);
@@ -231,10 +231,10 @@ static u64 css_serial_nr_next = 1;
* These bitmasks identify subsystems with specific features to avoid
* having to do iterative checks repeatedly.
*/
-static u16 have_fork_callback __read_mostly;
-static u16 have_exit_callback __read_mostly;
-static u16 have_release_callback __read_mostly;
-static u16 have_canfork_callback __read_mostly;
+static u32 have_fork_callback __read_mostly;
+static u32 have_exit_callback __read_mostly;
+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);
@@ -472,13 +472,13 @@ static bool cgroup_is_valid_domain(struct cgroup *cgrp)
}
/* subsystems visibly enabled on a cgroup */
-static u16 cgroup_control(struct cgroup *cgrp)
+static u32 cgroup_control(struct cgroup *cgrp)
{
struct cgroup *parent = cgroup_parent(cgrp);
- u16 root_ss_mask = cgrp->root->subsys_mask;
+ u32 root_ss_mask = cgrp->root->subsys_mask;
if (parent) {
- u16 ss_mask = parent->subtree_control;
+ u32 ss_mask = parent->subtree_control;
/* threaded cgroups can only have threaded controllers */
if (cgroup_is_threaded(cgrp))
@@ -493,12 +493,12 @@ static u16 cgroup_control(struct cgroup *cgrp)
}
/* subsystems enabled on a cgroup */
-static u16 cgroup_ss_mask(struct cgroup *cgrp)
+static u32 cgroup_ss_mask(struct cgroup *cgrp)
{
struct cgroup *parent = cgroup_parent(cgrp);
if (parent) {
- u16 ss_mask = parent->subtree_ss_mask;
+ u32 ss_mask = parent->subtree_ss_mask;
/* threaded cgroups can only have threaded controllers */
if (cgroup_is_threaded(cgrp))
@@ -1633,9 +1633,9 @@ static umode_t cgroup_file_mode(const struct cftype *cft)
* This function calculates which subsystems need to be enabled if
* @subtree_control is to be applied while restricted to @this_ss_mask.
*/
-static u16 cgroup_calc_subtree_ss_mask(u16 subtree_control, u16 this_ss_mask)
+static u32 cgroup_calc_subtree_ss_mask(u32 subtree_control, u32 this_ss_mask)
{
- u16 cur_ss_mask = subtree_control;
+ u32 cur_ss_mask = subtree_control;
struct cgroup_subsys *ss;
int ssid;
@@ -1644,7 +1644,7 @@ static u16 cgroup_calc_subtree_ss_mask(u16 subtree_control, u16 this_ss_mask)
cur_ss_mask |= cgrp_dfl_implicit_ss_mask;
while (true) {
- u16 new_ss_mask = cur_ss_mask;
+ u32 new_ss_mask = cur_ss_mask;
do_each_subsys_mask(ss, ssid, cur_ss_mask) {
new_ss_mask |= ss->depends_on;
@@ -1848,12 +1848,12 @@ static int css_populate_dir(struct cgroup_subsys_state *css)
return ret;
}
-int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
+int rebind_subsystems(struct cgroup_root *dst_root, u32 ss_mask)
{
struct cgroup *dcgrp = &dst_root->cgrp;
struct cgroup_subsys *ss;
int ssid, ret;
- u16 dfl_disable_ss_mask = 0;
+ u32 dfl_disable_ss_mask = 0;
lockdep_assert_held(&cgroup_mutex);
@@ -2149,7 +2149,7 @@ void init_cgroup_root(struct cgroup_fs_context *ctx)
set_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags);
}
-int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask)
+int cgroup_setup_root(struct cgroup_root *root, u32 ss_mask)
{
LIST_HEAD(tmp_links);
struct cgroup *root_cgrp = &root->cgrp;
@@ -3131,7 +3131,7 @@ void cgroup_procs_write_finish(struct task_struct *task,
put_task_struct(task);
}
-static void cgroup_print_ss_mask(struct seq_file *seq, u16 ss_mask)
+static void cgroup_print_ss_mask(struct seq_file *seq, u32 ss_mask)
{
struct cgroup_subsys *ss;
bool printed = false;
@@ -3496,9 +3496,9 @@ static void cgroup_finalize_control(struct cgroup *cgrp, int ret)
cgroup_apply_control_disable(cgrp);
}
-static int cgroup_vet_subtree_control_enable(struct cgroup *cgrp, u16 enable)
+static int cgroup_vet_subtree_control_enable(struct cgroup *cgrp, u32 enable)
{
- u16 domain_enable = enable & ~cgrp_dfl_threaded_ss_mask;
+ u32 domain_enable = enable & ~cgrp_dfl_threaded_ss_mask;
/* if nothing is getting enabled, nothing to worry about */
if (!enable)
@@ -3541,7 +3541,7 @@ static ssize_t cgroup_subtree_control_write(struct kernfs_open_file *of,
char *buf, size_t nbytes,
loff_t off)
{
- u16 enable = 0, disable = 0;
+ u32 enable = 0, disable = 0;
struct cgroup *cgrp, *child;
struct cgroup_subsys *ss;
char *tok;
@@ -6347,7 +6347,7 @@ int __init cgroup_init(void)
struct cgroup_subsys *ss;
int ssid;
- BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16);
+ BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 32);
BUG_ON(cgroup_init_cftypes(NULL, cgroup_base_files));
BUG_ON(cgroup_init_cftypes(NULL, cgroup_psi_files));
BUG_ON(cgroup_init_cftypes(NULL, cgroup1_base_files));
diff --git a/kernel/cgroup/debug.c b/kernel/cgroup/debug.c
index c1623d03137d..e5c7c56a0b68 100644
--- a/kernel/cgroup/debug.c
+++ b/kernel/cgroup/debug.c
@@ -230,7 +230,7 @@ static int cgroup_subsys_states_read(struct seq_file *seq, void *v)
}
static void cgroup_masks_read_one(struct seq_file *seq, const char *name,
- u16 mask)
+ u32 mask)
{
struct cgroup_subsys *ss;
int ssid;
--
2.34.1
Hi Chen, On 1/28/26 10:31 PM, Chen Ridong wrote: > From: Chen Ridong <chenridong@huawei.com> > > The current cgroup subsystem limit of 16 is insufficient, as the number of > subsystems has already reached this maximum. Attempting to add new > subsystems beyond this limit results in boot failures. > > This patch increases the maximum number of supported cgroup subsystems from > 16 to 32, providing adequate headroom for future subsystem additions. > > Signed-off-by: Chen Ridong <chenridong@huawei.com> > --- [...] I gave this a run with with 32 controllers enabled (16 pre-existing, 16 custom) and can confirm it works as expected. Tested-by: JP Kobryn <inwardvessel@gmail.com> Acked-by: JP Kobryn <inwardvessel@gmail.com>
On Thu, Jan 29, 2026 at 06:31:33AM +0000, Chen Ridong <chenridong@huaweicloud.com> wrote: > From: Chen Ridong <chenridong@huawei.com> > > The current cgroup subsystem limit of 16 is insufficient, as the number of > subsystems has already reached this maximum. Indeed. But some of them are legacy (and some novel). Do you really need one kernel image with every subsys config enabled? > Attempting to add new subsystems beyond this limit results in boot > failures. That sounds like BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16) doesn't trigger during build for you. Is the macro broken? > This patch increases the maximum number of supported cgroup subsystems from > 16 to 32, providing adequate headroom for future subsystem additions. It may be needed one day but I'd suggest binding this change with introduction of actual new controller. (As we have some CONFIG_*_V1 options that default to N, I'm thinking about switching config's default to N as well (like: CONFIG_CGROUP_CPUACCT CONFIG_CGROUP_DEVICE CONFIG_CGROUP_FREEZER CONFIG_CGROUP_DEBGU), arch/x86/configs/x86_64_defconfig is not exactly pinnacle of freshness :-/) Thanks, Michal
On 2026/1/29 17:23, Michal Koutný wrote: > On Thu, Jan 29, 2026 at 06:31:33AM +0000, Chen Ridong <chenridong@huaweicloud.com> wrote: >> From: Chen Ridong <chenridong@huawei.com> >> >> The current cgroup subsystem limit of 16 is insufficient, as the number of >> subsystems has already reached this maximum. > > Indeed. But some of them are legacy (and some novel). Do you really need > one kernel image with every subsys config enabled? > We compiled with 'make allmodconfig'. >> Attempting to add new subsystems beyond this limit results in boot >> failures. > > That sounds like BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16) doesn't trigger > during build for you. Is the macro broken? > The BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16) macro worked correctly. However, I only modified the code to allow compilation to pass, and the system subsequently failed to boot. >> This patch increases the maximum number of supported cgroup subsystems from >> 16 to 32, providing adequate headroom for future subsystem additions. > > It may be needed one day but I'd suggest binding this change with > introduction of actual new controller. > > > (As we have some CONFIG_*_V1 options that default to N, I'm thinking > about switching config's default to N as well (like: > CONFIG_CGROUP_CPUACCT CONFIG_CGROUP_DEVICE CONFIG_CGROUP_FREEZER > CONFIG_CGROUP_DEBGU), arch/x86/configs/x86_64_defconfig is not exactly > pinnacle of freshness :-/) > > Can I propose increasing the maximum number now? If we switch certain configs to default N and then a new subsystem is added later, the default configuration may work fine, but it will become a problem under allmodconfig — which some users actually rely on. Besides, this shouldn't be a major change, right? -- Best regards, Ridong
On Thu, Jan 29, 2026 at 05:51:33PM +0800, Chen Ridong <chenridong@huaweicloud.com> wrote: > We compiled with 'make allmodconfig'. A-ha. > The BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16) macro worked correctly. Good. > Can I propose increasing the maximum number now? If we switch certain configs to > default N and then a new subsystem is added later, the default configuration may > work fine, but it will become a problem under allmodconfig — which some users > actually rely on. > > Besides, this shouldn't be a major change, right? I'd like there to be gradual move away from legacy controllers code captured in config defaults. Could you adjust the commit message to stress out the allmodconfig tests? The change is OK technically. Thanks, Michal
On 2026/1/30 18:22, Michal Koutný wrote: > On Thu, Jan 29, 2026 at 05:51:33PM +0800, Chen Ridong <chenridong@huaweicloud.com> wrote: >> We compiled with 'make allmodconfig'. > > A-ha. > >> The BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16) macro worked correctly. > > Good. > >> Can I propose increasing the maximum number now? If we switch certain configs to >> default N and then a new subsystem is added later, the default configuration may >> work fine, but it will become a problem under allmodconfig — which some users >> actually rely on. >> >> Besides, this shouldn't be a major change, right? > > I'd like there to be gradual move away from legacy controllers code > captured in config defaults. > Could you adjust the commit message to stress out the allmodconfig tests? > Sure, will update. -- Best regards, Ridong
On 1/29/26 4:51 AM, Chen Ridong wrote: > > On 2026/1/29 17:23, Michal Koutný wrote: >> On Thu, Jan 29, 2026 at 06:31:33AM +0000, Chen Ridong <chenridong@huaweicloud.com> wrote: >>> From: Chen Ridong <chenridong@huawei.com> >>> >>> The current cgroup subsystem limit of 16 is insufficient, as the number of >>> subsystems has already reached this maximum. >> Indeed. But some of them are legacy (and some novel). Do you really need >> one kernel image with every subsys config enabled? >> > We compiled with 'make allmodconfig'. > >>> Attempting to add new subsystems beyond this limit results in boot >>> failures. >> That sounds like BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16) doesn't trigger >> during build for you. Is the macro broken? >> > The BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16) macro worked correctly. However, I > only modified the code to allow compilation to pass, and the system subsequently > failed to boot. > >>> This patch increases the maximum number of supported cgroup subsystems from >>> 16 to 32, providing adequate headroom for future subsystem additions. >> It may be needed one day but I'd suggest binding this change with >> introduction of actual new controller. >> (As we have some CONFIG_*_V1 options that default to N, I'm thinking >> about switching config's default to N as well (like: >> CONFIG_CGROUP_CPUACCT CONFIG_CGROUP_DEVICE CONFIG_CGROUP_FREEZER >> CONFIG_CGROUP_DEBGU), arch/x86/configs/x86_64_defconfig is not exactly >> pinnacle of freshness :-/) >> >> > Can I propose increasing the maximum number now? If we switch certain configs to > default N and then a new subsystem is added later, the default configuration may > work fine, but it will become a problem under allmodconfig — which some users > actually rely on. > > Besides, this shouldn't be a major change, right? Yes, I agreed that it is not a major change. I count the number of SUBSYS() in include/linux/cgroup_subsys.h and there are exactly 16 of them. So introduction of a new cgroup subsystem will break the current limit. I remember that there was talk about adding scheduling cgroup on the GPU side. One day, a new cgroup subsystem may be added without the awareness that the subsystem limit has to be extended causing issue down the line. So I support the idea of extending it now so that there is one less thing to worry about when a new cgroup subsystem is added in the future. Acked-by: Waiman Long <longman@redhat.com>
On 2026/1/30 2:33, Waiman Long wrote: > On 1/29/26 4:51 AM, Chen Ridong wrote: >> >> On 2026/1/29 17:23, Michal Koutný wrote: >>> On Thu, Jan 29, 2026 at 06:31:33AM +0000, Chen Ridong >>> <chenridong@huaweicloud.com> wrote: >>>> From: Chen Ridong <chenridong@huawei.com> >>>> >>>> The current cgroup subsystem limit of 16 is insufficient, as the number of >>>> subsystems has already reached this maximum. >>> Indeed. But some of them are legacy (and some novel). Do you really need >>> one kernel image with every subsys config enabled? >>> >> We compiled with 'make allmodconfig'. >> >>>> Attempting to add new subsystems beyond this limit results in boot >>>> failures. >>> That sounds like BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16) doesn't trigger >>> during build for you. Is the macro broken? >>> >> The BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16) macro worked correctly. However, I >> only modified the code to allow compilation to pass, and the system subsequently >> failed to boot. >> >>>> This patch increases the maximum number of supported cgroup subsystems from >>>> 16 to 32, providing adequate headroom for future subsystem additions. >>> It may be needed one day but I'd suggest binding this change with >>> introduction of actual new controller. >>> (As we have some CONFIG_*_V1 options that default to N, I'm thinking >>> about switching config's default to N as well (like: >>> CONFIG_CGROUP_CPUACCT CONFIG_CGROUP_DEVICE CONFIG_CGROUP_FREEZER >>> CONFIG_CGROUP_DEBGU), arch/x86/configs/x86_64_defconfig is not exactly >>> pinnacle of freshness :-/) >>> >>> >> Can I propose increasing the maximum number now? If we switch certain configs to >> default N and then a new subsystem is added later, the default configuration may >> work fine, but it will become a problem under allmodconfig — which some users >> actually rely on. >> >> Besides, this shouldn't be a major change, right? > > Yes, I agreed that it is not a major change. I count the number of SUBSYS() in > include/linux/cgroup_subsys.h and there are exactly 16 of them. So introduction > of a new cgroup subsystem will break the current limit. I remember that there > was talk about adding scheduling cgroup on the GPU side. One day, a new cgroup Thanks, Longman, Now that dmem has been added, I believe a new subsystem for GPU scheduling will be introduced soon. > subsystem may be added without the awareness that the subsystem limit has to be > extended causing issue down the line. So I support the idea of extending it now > so that there is one less thing to worry about when a new cgroup subsystem is > added in the future. > > Acked-by: Waiman Long <longman@redhat.com> > > -- Best regards, Ridong
On 2026/1/29 14:31, Chen Ridong wrote: > The current cgroup subsystem limit of 16 is insufficient, as the number of > subsystems has already reached this maximum. Attempting to add new > subsystems beyond this limit results in boot failures. We found this issue because our product includes a subsystem not present in the community version, causing the total number of subsystems to exceed 16. When all subsystems are enabled, the system fails to boot. -- Best regards, Ridong
© 2016 - 2026 Red Hat, Inc.