[RFC PATCH 4/4] sysctl: mqueue: Do not use dynamic memory
From: Alexey Gladkov
Date: Wed Jun 01 2022 - 09:21:21 EST
Dynamic memory allocation is needed to modify .data and specify the
per namespace parameter. The new sysctl API is allowed to get rid of
the need for such modification.
Signed-off-by: Alexey Gladkov <legion@xxxxxxxxxx>
---
include/linux/ipc_namespace.h | 17 -----
ipc/mq_sysctl.c | 138 +++++++++++++++++++---------------
ipc/mqueue.c | 5 --
ipc/namespace.c | 6 --
4 files changed, 79 insertions(+), 87 deletions(-)
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index 51c2c247c447..d20753093a2c 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -174,21 +174,4 @@ static inline void put_ipc_ns(struct ipc_namespace *ns)
}
#endif
-#ifdef CONFIG_POSIX_MQUEUE_SYSCTL
-
-void retire_mq_sysctls(struct ipc_namespace *ns);
-bool setup_mq_sysctls(struct ipc_namespace *ns);
-
-#else /* CONFIG_POSIX_MQUEUE_SYSCTL */
-
-static inline void retire_mq_sysctls(struct ipc_namespace *ns)
-{
-}
-
-static inline bool setup_mq_sysctls(struct ipc_namespace *ns)
-{
- return true;
-}
-
-#endif /* CONFIG_POSIX_MQUEUE_SYSCTL */
#endif
diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c
index fbf6a8b93a26..08ff7dfb721c 100644
--- a/ipc/mq_sysctl.c
+++ b/ipc/mq_sysctl.c
@@ -13,6 +13,45 @@
#include <linux/capability.h>
#include <linux/slab.h>
+static inline void *data_from_ns(struct ctl_context *ctx, struct ctl_table *table);
+
+static int mq_sys_open(struct ctl_context *ctx, struct inode *inode, struct file *file)
+{
+ ctx->ctl_data = current->nsproxy->ipc_ns;
+ return 0;
+}
+
+static ssize_t mq_sys_read(struct ctl_context *ctx, struct file *file,
+ char *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table table = *ctx->table;
+ table.data = data_from_ns(ctx, ctx->table);
+ return table.proc_handler(&table, 0, buffer, lenp, ppos);
+}
+
+static ssize_t mq_sys_write(struct ctl_context *ctx, struct file *file,
+ char *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table table = *ctx->table;
+ table.data = data_from_ns(ctx, ctx->table);
+ return table.proc_handler(&table, 1, buffer, lenp, ppos);
+}
+
+static struct ctl_fops mq_sys_fops = {
+ .open = mq_sys_open,
+ .read = mq_sys_read,
+ .write = mq_sys_write,
+};
+
+enum {
+ MQ_SYSCTL_QUEUES_MAX,
+ MQ_SYSCTL_MSG_MAX,
+ MQ_SYSCTL_MSGSIZE_MAX,
+ MQ_SYSCTL_MSG_DEFAULT,
+ MQ_SYSCTL_MSGSIZE_DEFAULT,
+ MQ_SYSCTL_COUNTS
+};
+
static int msg_max_limit_min = MIN_MSGMAX;
static int msg_max_limit_max = HARD_MSGMAX;
@@ -20,14 +59,15 @@ static int msg_maxsize_limit_min = MIN_MSGSIZEMAX;
static int msg_maxsize_limit_max = HARD_MSGSIZEMAX;
static struct ctl_table mq_sysctls[] = {
- {
+ [MQ_SYSCTL_QUEUES_MAX] = {
.procname = "queues_max",
.data = &init_ipc_ns.mq_queues_max,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
+ .ctl_fops = &mq_sys_fops,
},
- {
+ [MQ_SYSCTL_MSG_MAX] = {
.procname = "msg_max",
.data = &init_ipc_ns.mq_msg_max,
.maxlen = sizeof(int),
@@ -35,8 +75,9 @@ static struct ctl_table mq_sysctls[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = &msg_max_limit_min,
.extra2 = &msg_max_limit_max,
+ .ctl_fops = &mq_sys_fops,
},
- {
+ [MQ_SYSCTL_MSGSIZE_MAX] = {
.procname = "msgsize_max",
.data = &init_ipc_ns.mq_msgsize_max,
.maxlen = sizeof(int),
@@ -44,8 +85,9 @@ static struct ctl_table mq_sysctls[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = &msg_maxsize_limit_min,
.extra2 = &msg_maxsize_limit_max,
+ .ctl_fops = &mq_sys_fops,
},
- {
+ [MQ_SYSCTL_MSG_DEFAULT] = {
.procname = "msg_default",
.data = &init_ipc_ns.mq_msg_default,
.maxlen = sizeof(int),
@@ -53,8 +95,9 @@ static struct ctl_table mq_sysctls[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = &msg_max_limit_min,
.extra2 = &msg_max_limit_max,
+ .ctl_fops = &mq_sys_fops,
},
- {
+ [MQ_SYSCTL_MSGSIZE_DEFAULT] = {
.procname = "msgsize_default",
.data = &init_ipc_ns.mq_msgsize_default,
.maxlen = sizeof(int),
@@ -62,70 +105,47 @@ static struct ctl_table mq_sysctls[] = {
.proc_handler = proc_dointvec_minmax,
.extra1 = &msg_maxsize_limit_min,
.extra2 = &msg_maxsize_limit_max,
+ .ctl_fops = &mq_sys_fops,
},
{}
};
-static struct ctl_table_set *set_lookup(struct ctl_table_root *root)
+static inline void *data_from_ns(struct ctl_context *ctx, struct ctl_table *table)
{
- return ¤t->nsproxy->ipc_ns->mq_set;
+ struct ipc_namespace *ns = ctx->ctl_data;
+
+ switch (ctx->table - mq_sysctls) {
+ case MQ_SYSCTL_QUEUES_MAX: return &ns->mq_queues_max;
+ case MQ_SYSCTL_MSG_MAX: return &ns->mq_msg_max;
+ case MQ_SYSCTL_MSGSIZE_MAX: return &ns->mq_msgsize_max;
+ case MQ_SYSCTL_MSG_DEFAULT: return &ns->mq_msg_default;
+ case MQ_SYSCTL_MSGSIZE_DEFAULT: return &ns->mq_msgsize_default;
+ }
+ return NULL;
}
-static int set_is_seen(struct ctl_table_set *set)
-{
- return ¤t->nsproxy->ipc_ns->mq_set == set;
-}
+static struct ctl_table mq_sysctl_dir[] = {
+ {
+ .procname = "mqueue",
+ .mode = 0555,
+ .child = mq_sysctls,
+ },
+ {}
+};
-static struct ctl_table_root set_root = {
- .lookup = set_lookup,
+static struct ctl_table mq_sysctl_root[] = {
+ {
+ .procname = "fs",
+ .mode = 0555,
+ .child = mq_sysctl_dir,
+ },
+ {}
};
-bool setup_mq_sysctls(struct ipc_namespace *ns)
+static int __init mq_sysctl_init(void)
{
- struct ctl_table *tbl;
-
- 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);
- }
- if (!ns->mq_sysctls) {
- kfree(tbl);
- retire_sysctl_set(&ns->mq_set);
- return false;
- }
-
- return true;
+ register_sysctl_table(mq_sysctl_root);
+ return 0;
}
-void retire_mq_sysctls(struct ipc_namespace *ns)
-{
- 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);
-}
+device_initcall(mq_sysctl_init);
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c0f24cc9f619..ffb79a24d70b 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1711,11 +1711,6 @@ static int __init init_mqueue_fs(void)
if (mqueue_inode_cachep == NULL)
return -ENOMEM;
- if (!setup_mq_sysctls(&init_ipc_ns)) {
- pr_warn("sysctl registration failed\n");
- return -ENOMEM;
- }
-
error = register_filesystem(&mqueue_fs_type);
if (error)
goto out_sysctl;
diff --git a/ipc/namespace.c b/ipc/namespace.c
index f760243ca685..ae83f0f2651b 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -59,10 +59,6 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
if (err)
goto fail_put;
- err = -ENOMEM;
- if (!setup_mq_sysctls(ns))
- goto fail_put;
-
sem_init_ns(ns);
msg_init_ns(ns);
shm_init_ns(ns);
@@ -129,8 +125,6 @@ static void free_ipc_ns(struct ipc_namespace *ns)
msg_exit_ns(ns);
shm_exit_ns(ns);
- retire_mq_sysctls(ns);
-
dec_ipc_namespaces(ns->ucounts);
put_user_ns(ns->user_ns);
ns_free_inum(&ns->ns);
--
2.33.3