[RFC PATCH v1 07/30] sysctl: use sysctl_field in pid sysctls
From: Alexey Gladkov
Date: Wed Aug 26 2026 - 15:47:11 EST
The pid namespace sysctl registration allocates a private ctl_table copy
only to replace the static pid_max data pointer with the value from the
registered namespace. This keeps otherwise shared sysctl metadata
writable at registration time and requires per-namespace table lifetime
management.
Use a sysctl_field accessor to derive pid_max from the registration
context instead. The pid sysctl table can remain static and const, while
registration no longer needs to clone, patch and free a ctl_table array.
Signed-off-by: Alexey Gladkov <legion@xxxxxxxxxx>
---
include/linux/sysctl.h | 2 ++
kernel/pid.c | 41 +++++++++++++----------------------------
2 files changed, 15 insertions(+), 28 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index e2831190e484..056d10f4ab3d 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -39,6 +39,7 @@ struct ctl_table_root;
struct ctl_table_header;
struct ctl_dir;
struct ipc_namespace;
+struct pid_namespace;
struct user_namespace;
/* Keep the same order as in fs/proc/proc_sysctl.c */
@@ -92,6 +93,7 @@ struct sysctl_context {
union {
struct user_namespace *user_ns;
struct ipc_namespace *ipc_ns;
+ struct pid_namespace *pid_ns;
} ns;
};
diff --git a/kernel/pid.c b/kernel/pid.c
index fd5c2d4aa349..66991ee435fb 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -787,23 +787,15 @@ static int proc_do_cad_pid(const struct ctl_table *table, int write, void *buffe
return 0;
}
-static const struct ctl_table pid_table[] = {
- {
- .procname = "pid_max",
- .data = &init_pid_ns.pid_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &pid_max_min,
- .extra2 = &pid_max_max,
- },
+static int *pid_max_data(const struct sysctl_context *ctx)
+{
+ return &ctx->ns.pid_ns->pid_max;
+}
+
+static const struct sysctl_field pid_table[] = {
+ SYSCTL_FIELD_STATIC_INT_MINMAX("pid_max", 0644, pid_max_data, &pid_max_min, &pid_max_max),
#ifdef CONFIG_PROC_SYSCTL
- {
- .procname = "cad_pid",
- .maxlen = sizeof(int),
- .mode = 0600,
- .proc_handler = proc_do_cad_pid,
- },
+ SYSCTL_FIELD_CUSTOM("cad_pid", 0600, sizeof(int), NULL, proc_do_cad_pid),
#endif
};
#endif
@@ -811,21 +803,18 @@ static const struct ctl_table pid_table[] = {
int register_pidns_sysctls(struct pid_namespace *pidns)
{
#ifdef CONFIG_SYSCTL
- struct ctl_table *tbl;
+ struct sysctl_context ctx = {
+ .ns.pid_ns = pidns,
+ };
setup_sysctl_set(&pidns->set, &pid_table_root, set_is_seen);
- tbl = kmemdup(pid_table, sizeof(pid_table), GFP_KERNEL);
- if (!tbl)
- return -ENOMEM;
- tbl->data = &pidns->pid_max;
pidns->pid_max = min(pid_max_max, max_t(int, pidns->pid_max,
PIDS_PER_CPU_DEFAULT * num_possible_cpus()));
- pidns->sysctls = __register_sysctl_table(&pidns->set, "kernel", tbl,
- ARRAY_SIZE(pid_table));
+ pidns->sysctls = register_sysctl_fields(&pidns->set, "kernel",
+ pid_table, &ctx);
if (!pidns->sysctls) {
- kfree(tbl);
retire_sysctl_set(&pidns->set);
return -ENOMEM;
}
@@ -836,12 +825,8 @@ int register_pidns_sysctls(struct pid_namespace *pidns)
void unregister_pidns_sysctls(struct pid_namespace *pidns)
{
#ifdef CONFIG_SYSCTL
- const struct ctl_table *tbl;
-
- tbl = pidns->sysctls->ctl_table_arg;
unregister_sysctl_table(pidns->sysctls);
retire_sysctl_set(&pidns->set);
- kfree(tbl);
#endif
}
--
2.55.0