[RFC PATCH v1 08/30] sysctl: net: use sysctl_field in unix sysctl
From: Alexey Gladkov
Date: Wed Aug 26 2026 - 15:45:02 EST
The unix sysctl table is cloned for non-init network namespaces only to
replace the data pointer with per-net storage. That keeps a mutable
ctl_table copy alive for each namespace even though the descriptor
itself is otherwise static.
Add a netns-aware sysctl_field registration helper and use it for the
unix sysctl table. The data pointer is derived from the registration
context, so the table can stay const and the per-net clone and free path
are no longer needed.
Signed-off-by: Alexey Gladkov <legion@xxxxxxxxxx>
---
include/linux/sysctl.h | 2 ++
net/unix/sysctl_net_unix.c | 48 +++++++++++---------------------------
2 files changed, 15 insertions(+), 35 deletions(-)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 056d10f4ab3d..bbdb0fcfbcd4 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 net;
struct ipc_namespace;
struct pid_namespace;
struct user_namespace;
@@ -94,6 +95,7 @@ struct sysctl_context {
struct user_namespace *user_ns;
struct ipc_namespace *ipc_ns;
struct pid_namespace *pid_ns;
+ struct net *net_ns;
} ns;
};
diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c
index e02ed6e3955c..fc6687f9eaf4 100644
--- a/net/unix/sysctl_net_unix.c
+++ b/net/unix/sysctl_net_unix.c
@@ -5,58 +5,36 @@
* Authors: Mike Shaver.
*/
-#include <linux/slab.h>
-#include <linux/string.h>
#include <linux/sysctl.h>
#include <net/af_unix.h>
#include <net/net_namespace.h>
#include "af_unix.h"
-static struct ctl_table unix_table[] = {
- {
- .procname = "max_dgram_qlen",
- .data = &init_net.unx.sysctl_max_dgram_qlen,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
+static int *unix_max_dgram_qlen_data(const struct sysctl_context *ctx)
+{
+ return &ctx->ns.net_ns->unx.sysctl_max_dgram_qlen;
+}
+
+static const struct sysctl_field unix_table[] = {
+ SYSCTL_FIELD_INT("max_dgram_qlen", 0644, unix_max_dgram_qlen_data),
};
int __net_init unix_sysctl_register(struct net *net)
{
- struct ctl_table *table;
-
- if (net_eq(net, &init_net)) {
- table = unix_table;
- } else {
- table = kmemdup(unix_table, sizeof(unix_table), GFP_KERNEL);
- if (!table)
- goto err_alloc;
+ struct sysctl_context ctx = {
+ .ns.net_ns = net,
+ };
- table[0].data = &net->unx.sysctl_max_dgram_qlen;
- }
-
- net->unx.ctl = register_net_sysctl_sz(net, "net/unix", table,
- ARRAY_SIZE(unix_table));
+ net->unx.ctl = register_sysctl_fields(&net->sysctls, "net/unix",
+ unix_table, &ctx);
if (net->unx.ctl == NULL)
- goto err_reg;
+ return -ENOMEM;
return 0;
-
-err_reg:
- if (!net_eq(net, &init_net))
- kfree(table);
-err_alloc:
- return -ENOMEM;
}
void unix_sysctl_unregister(struct net *net)
{
- const struct ctl_table *table;
-
- table = net->unx.ctl->ctl_table_arg;
unregister_net_sysctl_table(net->unx.ctl);
- if (!net_eq(net, &init_net))
- kfree(table);
}
--
2.55.0