[RFC PATCH v1 05/30] sysctl: ipc: use sysctl_field in mq_sysctl

From: Alexey Gladkov

Date: Wed Aug 26 2026 - 15:46:58 EST


Convert mq_sysctls. The table can now share one static array across ipc
namespaces instead of allocating and rewriting a ctl_table copy for each
registration.

Signed-off-by: Alexey Gladkov <legion@xxxxxxxxxx>
---
include/linux/sysctl.h | 2 +
ipc/mq_sysctl.c | 100 +++++++++--------------------------------
2 files changed, 24 insertions(+), 78 deletions(-)

diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 3c7f2ffab334..e2831190e484 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -38,6 +38,7 @@ struct nsproxy;
struct ctl_table_root;
struct ctl_table_header;
struct ctl_dir;
+struct ipc_namespace;
struct user_namespace;

/* Keep the same order as in fs/proc/proc_sysctl.c */
@@ -90,6 +91,7 @@ typedef int proc_handler(const struct ctl_table *ctl, int write, void *buffer,
struct sysctl_context {
union {
struct user_namespace *user_ns;
+ struct ipc_namespace *ipc_ns;
} ns;
};

diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c
index 0dd12e1c9f53..54e59b9901dd 100644
--- a/ipc/mq_sysctl.c
+++ b/ipc/mq_sysctl.c
@@ -11,7 +11,6 @@

#include <linux/stat.h>
#include <linux/capability.h>
-#include <linux/slab.h>
#include <linux/cred.h>

static int msg_max_limit_min = MIN_MSGMAX;
@@ -20,50 +19,24 @@ static int msg_max_limit_max = HARD_MSGMAX;
static int msg_maxsize_limit_min = MIN_MSGSIZEMAX;
static int msg_maxsize_limit_max = HARD_MSGSIZEMAX;

-static const struct ctl_table mq_sysctls[] = {
- {
- .procname = "queues_max",
- .data = &init_ipc_ns.mq_queues_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "msg_max",
- .data = &init_ipc_ns.mq_msg_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &msg_max_limit_min,
- .extra2 = &msg_max_limit_max,
- },
- {
- .procname = "msgsize_max",
- .data = &init_ipc_ns.mq_msgsize_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &msg_maxsize_limit_min,
- .extra2 = &msg_maxsize_limit_max,
- },
- {
- .procname = "msg_default",
- .data = &init_ipc_ns.mq_msg_default,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &msg_max_limit_min,
- .extra2 = &msg_max_limit_max,
- },
- {
- .procname = "msgsize_default",
- .data = &init_ipc_ns.mq_msgsize_default,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &msg_maxsize_limit_min,
- .extra2 = &msg_maxsize_limit_max,
- },
+#define MQ_SYSCTL_DATA(name, member) \
+static int *name ## _data(const struct sysctl_context *ctx) \
+{ \
+ return &ctx->ns.ipc_ns->member; \
+}
+
+MQ_SYSCTL_DATA(mq_queues_max, mq_queues_max);
+MQ_SYSCTL_DATA(mq_msg_max, mq_msg_max);
+MQ_SYSCTL_DATA(mq_msgsize_max, mq_msgsize_max);
+MQ_SYSCTL_DATA(mq_msg_default, mq_msg_default);
+MQ_SYSCTL_DATA(mq_msgsize_default, mq_msgsize_default);
+
+static const struct sysctl_field mq_sysctls[] = {
+ SYSCTL_FIELD_INT("queues_max", 0644, mq_queues_max_data),
+ SYSCTL_FIELD_STATIC_INT_MINMAX("msg_max", 0644, mq_msg_max_data, &msg_max_limit_min, &msg_max_limit_max),
+ SYSCTL_FIELD_STATIC_INT_MINMAX("msgsize_max", 0644, mq_msgsize_max_data, &msg_maxsize_limit_min, &msg_maxsize_limit_max),
+ SYSCTL_FIELD_STATIC_INT_MINMAX("msg_default", 0644, mq_msg_default_data, &msg_max_limit_min, &msg_max_limit_max),
+ SYSCTL_FIELD_STATIC_INT_MINMAX("msgsize_default", 0644, mq_msgsize_default_data, &msg_maxsize_limit_min, &msg_maxsize_limit_max),
};

static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
@@ -116,39 +89,14 @@ static struct ctl_table_root set_root = {

bool setup_mq_sysctls(struct ipc_namespace *ns)
{
- struct ctl_table *tbl;
+ struct sysctl_context ctx = {
+ .ns.ipc_ns = ns,
+ };

setup_sysctl_set(&ns->mq_set, &set_root, set_is_seen);

- tbl = kmemdup(mq_sysctls, sizeof(mq_sysctls), GFP_KERNEL);
- if (tbl) {
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mq_sysctls); i++) {
- if (tbl[i].data == &init_ipc_ns.mq_queues_max)
- tbl[i].data = &ns->mq_queues_max;
-
- else if (tbl[i].data == &init_ipc_ns.mq_msg_max)
- tbl[i].data = &ns->mq_msg_max;
-
- else if (tbl[i].data == &init_ipc_ns.mq_msgsize_max)
- tbl[i].data = &ns->mq_msgsize_max;
-
- else if (tbl[i].data == &init_ipc_ns.mq_msg_default)
- tbl[i].data = &ns->mq_msg_default;
-
- else if (tbl[i].data == &init_ipc_ns.mq_msgsize_default)
- tbl[i].data = &ns->mq_msgsize_default;
- else
- tbl[i].data = NULL;
- }
-
- ns->mq_sysctls = __register_sysctl_table(&ns->mq_set,
- "fs/mqueue", tbl,
- ARRAY_SIZE(mq_sysctls));
- }
+ ns->mq_sysctls = register_sysctl_fields(&ns->mq_set, "fs/mqueue", mq_sysctls, &ctx);
if (!ns->mq_sysctls) {
- kfree(tbl);
retire_sysctl_set(&ns->mq_set);
return false;
}
@@ -158,10 +106,6 @@ bool setup_mq_sysctls(struct ipc_namespace *ns)

void retire_mq_sysctls(struct ipc_namespace *ns)
{
- const struct ctl_table *tbl;
-
- tbl = ns->mq_sysctls->ctl_table_arg;
unregister_sysctl_table(ns->mq_sysctls);
retire_sysctl_set(&ns->mq_set);
- kfree(tbl);
}
--
2.55.0