[RFC PATCH v1 15/30] sysctl: net: use sysctl_field in vsock sysctls
From: Alexey Gladkov
Date: Wed Aug 26 2026 - 15:47:02 EST
The vsock sysctl table is cloned for every non-init network namespace
only to bind the entries to that namespace's vsock state. The custom
mode handlers already derive the namespace from the data pointer, so the
table clone is just per-net storage for otherwise static descriptors.
Use sysctl_field descriptors so the data pointers are derived from the
registration context. This keeps the table const and removes the per-net
allocation, pointer patching, and free path.
Signed-off-by: Alexey Gladkov <legion@xxxxxxxxxx>
---
net/vmw_vsock/af_vsock.c | 91 ++++++++++++++++------------------------
1 file changed, 36 insertions(+), 55 deletions(-)
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index 44037b066a5f..74af67e01430 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -2875,71 +2875,52 @@ static int vsock_net_child_mode_string(const struct ctl_table *table, int write,
return 0;
}
-static struct ctl_table vsock_table[] = {
- {
- .procname = "ns_mode",
- .data = &init_net.vsock.mode,
- .maxlen = VSOCK_NET_MODE_STR_MAX,
- .mode = 0444,
- .proc_handler = vsock_net_mode_string
- },
- {
- .procname = "child_ns_mode",
- .data = &init_net.vsock.child_ns_mode,
- .maxlen = VSOCK_NET_MODE_STR_MAX,
- .mode = 0644,
- .proc_handler = vsock_net_child_mode_string
- },
- {
- .procname = "g2h_fallback",
- .data = &init_net.vsock.g2h_fallback,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = SYSCTL_ZERO,
- .extra2 = SYSCTL_ONE,
- },
-};
+#ifdef CONFIG_SYSCTL
+static void *vsock_net_mode_data(const struct sysctl_context *ctx)
+{
+ return &ctx->ns.net_ns->vsock.mode;
+}
-static int __net_init vsock_sysctl_register(struct net *net)
+static void *vsock_net_child_mode_data(const struct sysctl_context *ctx)
{
- struct ctl_table *table;
+ return &ctx->ns.net_ns->vsock.child_ns_mode;
+}
- if (net_eq(net, &init_net)) {
- table = vsock_table;
- } else {
- table = kmemdup(vsock_table, sizeof(vsock_table), GFP_KERNEL);
- if (!table)
- goto err_alloc;
+static int *vsock_g2h_fallback_data(const struct sysctl_context *ctx)
+{
+ return &ctx->ns.net_ns->vsock.g2h_fallback;
+}
- table[0].data = &net->vsock.mode;
- table[1].data = &net->vsock.child_ns_mode;
- table[2].data = &net->vsock.g2h_fallback;
- }
+static const struct sysctl_field vsock_table[] = {
+ SYSCTL_FIELD_CUSTOM("ns_mode", 0444, VSOCK_NET_MODE_STR_MAX,
+ vsock_net_mode_data, vsock_net_mode_string),
+ SYSCTL_FIELD_CUSTOM("child_ns_mode", 0644, VSOCK_NET_MODE_STR_MAX,
+ vsock_net_child_mode_data,
+ vsock_net_child_mode_string),
+ SYSCTL_FIELD_STATIC_INT_MINMAX("g2h_fallback", 0644,
+ vsock_g2h_fallback_data,
+ SYSCTL_ZERO, SYSCTL_ONE),
+};
+
+static int __net_init vsock_sysctl_register(struct net *net)
+{
+ struct sysctl_context ctx = {
+ .ns.net_ns = net,
+ };
- net->vsock.sysctl_hdr = register_net_sysctl_sz(net, "net/vsock", table,
- ARRAY_SIZE(vsock_table));
+ net->vsock.sysctl_hdr = register_sysctl_fields(&net->sysctls, "net/vsock",
+ vsock_table, &ctx);
if (!net->vsock.sysctl_hdr)
- goto err_reg;
+ return -ENOMEM;
return 0;
-
-err_reg:
- if (!net_eq(net, &init_net))
- kfree(table);
-err_alloc:
- return -ENOMEM;
}
-
-static void vsock_sysctl_unregister(struct net *net)
+#else
+static int __net_init vsock_sysctl_register(struct net *net)
{
- const struct ctl_table *table;
-
- table = net->vsock.sysctl_hdr->ctl_table_arg;
- unregister_net_sysctl_table(net->vsock.sysctl_hdr);
- if (!net_eq(net, &init_net))
- kfree(table);
+ return 0;
}
+#endif
static void vsock_net_init(struct net *net)
{
@@ -2965,7 +2946,7 @@ static __net_init int vsock_sysctl_init_net(struct net *net)
static __net_exit void vsock_sysctl_exit_net(struct net *net)
{
- vsock_sysctl_unregister(net);
+ unregister_net_sysctl_table(net->vsock.sysctl_hdr);
}
static struct pernet_operations vsock_sysctl_ops = {
--
2.55.0