* [RFC PATCH v1 00/30] sysctl: add context-bound field descriptors
@ 2026-08-26 19:42 Alexey Gladkov
0 siblings, 0 replies; only message in thread
From: Alexey Gladkov @ 2026-08-26 19:42 UTC (permalink / raw)
To: Linus Torvalds, Eric W . Biederman, Kees Cook, Joel Granados
Cc: LKML, linux-fsdevel
Hi,
A few years ago Linus didn't like an IPC sysctl conversion which copied each
table and rewrote its entries for every IPC namespace [1]. I remembered that :)
After that, I tried creating a different API to avoid allocating tables [2], but
nobody really liked that interface either. The discussion also pointed out that
a new interface should use self-describing, properly typed pointers rather than
adding more void pointer conventions to ctl_table.
This series is another attempt to address the underlying problem.
ctl_table works well when one static entry contains all the pointers consumed by
its proc handler. It cannot describe a static set of sysctls whose data or
limits belong to a namespace, device, or another object selected at registration
time. Such users commonly duplicate an otherwise static table and patch data,
extra1, extra2, mode, or proc_handler before registering it. Some do so by
table index, making the fixup code depend on the exact ordering of a separate
descriptor array. A table edit which misses the corresponding fixup can
silently bind a sysctl to the wrong value or limits.
The new API separates an immutable sysctl description from two levels of object
binding. One struct sysctl_context belongs to the registration as a whole and
holds the namespace or other objects shared by the entire field array. Each
struct sysctl_field then has accessors which derive the data and limits for that
particular entry from the shared context. Resolved pointers therefore do not
have to be stored in a private copy of the descriptor array. The typed field
variants also tie accessor return types to the standard proc handler selected by
the core, allowing the compiler to catch mismatches before a compatible
ctl_table entry is constructed.
The base context contains a union of typed namespace pointers. It can also be
the first member of a subsystem-specific context, for example:
struct mpls_dev_ctl_context {
struct sysctl_context context;
struct mpls_dev *mdev;
};
The whole object is copied into the ctl_table_header allocation at registration.
An accessor which needs mdev recovers the enclosing object with container_of(),
while ordinary per-net accessors use ctx->ns.net_ns directly. This keeps
subsystem-specific pointers out of the generic context, avoids an untyped
catch-all pointer, and gives the copied context the same lifetime as the
registered sysctls.
sysctl_field is analogous to ctl_table, not a replacement for it. Existing
users are unchanged. The sysctl core stores either descriptor type in
ctl_table_header and materializes a temporary ctl_table when entering the
existing proc handler, permission, or BPF interfaces. This preserves those
interfaces while allowing converted users to share one static const field array
across all instances.
The remaining patches convert the dynamic users which motivated the API,
including ucounts, IPC, PID, networking, neighbour tables, and parport. The
conversions remove per-instance table clones, offset and index fixups, and the
matching lifetime bookkeeping. The series deliberately leaves ordinary static
ctl_table users alone.
Reducing memory use is a secondary result rather than the main reason for the
change. I measured active kmalloc slab usage after creating N namespaces with:
for i in `seq 1 N`; do
unshare --ipc --mount --net --uts --user --cgroup --time --pid \
--fork --kill-child --map-root-user /pause &
done
N Unpatched Patched Saving Per namespace
100 8.51 MiB 4.80 MiB 3.71 MiB 38.00 KiB
500 73.78 MiB 55.13 MiB 18.64 MiB 38.18 KiB
1000 167.15 MiB 128.53 MiB 38.62 MiB 39.55 KiB
2000 358.81 MiB 284.55 MiB 74.27 MiB 38.02 KiB
5000 942.12 MiB 754.10 MiB 188.01 MiB 38.50 KiB
At 5000 namespaces this reduced the measured active slab footprint by
188.01 MiB, or about 38.5 KiB per namespace.
[1] https://lore.kernel.org/all/877d8kfmdp.fsf@email.froward.int.ebiederm.org/
[1] https://lore.kernel.org/all/cover.1654086665.git.legion@kernel.org/
Alexey Gladkov (30):
proc: sysctl: address table entries by index
sysctl: add unsigned int limit constants
sysctl: add typed field descriptors
The first three patches introduce a new interface, while the rest convert all
dynamic ctl_table allocations to the new interface. Without them, it was hard to
understand what was needed from the new API.
sysctl: use sysctl_field in ucounts
sysctl: ipc: use sysctl_field in mq_sysctl
sysctl: ipc: use sysctl_field in ipc_sysctl
sysctl: use sysctl_field in pid sysctls
sysctl: net: use sysctl_field in unix sysctl
sysctl: net: use sysctl_field in xfrm sysctls
sysctl: net: use sysctl_field for simple IPv4 per-net sysctls
sysctl: net: use sysctl_field in IPv4 sysctls
sysctl: net: use sysctl_field in IPv6 xfrm sysctls
sysctl: net: use sysctl_field in IPv6 fragment sysctls
sysctl: net: use sysctl_field in 6lowpan fragment sysctls
sysctl: net: use sysctl_field in vsock sysctls
sysctl: net: use sysctl_field in MPTCP sysctls
sysctl: net: use sysctl_field in SCTP sysctls
sysctl: net: use sysctl_field in core IPv6 sysctls
sysctl: net: use sysctl_field in net core per-net sysctls
sysctl: net: use sysctl_field in SMC sysctls
sysctl: net: use sysctl_field in VRF sysctls
sysctl: net: use sysctl_field in RDS sysctls
sysctl: netfilter: use sysctl_field for per-net sysctls
sysctl: ipvs: use sysctl_field for per-net sysctls
sysctl: bridge: use sysctl_field for br_netfilter sysctls
sysctl: net: use sysctl_field for MPLS sysctls
sysctl: net: use sysctl_field in IPv4 devconf sysctls
sysctl: net: use sysctl_field in IPv6 devconf sysctls
sysctl: net: use sysctl_field in neighbour sysctls
sysctl: parport: use sysctl_field for dynamic sysctls
drivers/net/vrf.c | 43 +-
drivers/parport/procfs.c | 317 ++---
fs/proc/inode.c | 2 +-
fs/proc/internal.h | 2 +-
fs/proc/proc_sysctl.c | 603 ++++++---
include/linux/parport.h | 6 +-
include/linux/sysctl.h | 283 +++-
include/net/ip_vs.h | 3 -
include/net/ipv6.h | 6 +-
include/net/neighbour.h | 1 +
ipc/ipc_sysctl.c | 256 ++--
ipc/mq_sysctl.c | 100 +-
kernel/pid.c | 41 +-
kernel/sysctl.c | 3 +
kernel/ucount.c | 83 +-
net/bridge/br_netfilter_hooks.c | 99 +-
net/core/neighbour.c | 329 +++--
net/core/sysctl_net_core.c | 241 ++--
net/ieee802154/6lowpan/reassembly.c | 84 +-
net/ipv4/devinet.c | 258 ++--
net/ipv4/ip_fragment.c | 96 +-
net/ipv4/route.c | 102 +-
net/ipv4/sysctl_net_ipv4.c | 1622 ++++++++---------------
net/ipv4/xfrm4_policy.c | 52 +-
net/ipv6/addrconf.c | 746 ++++-------
net/ipv6/icmp.c | 127 +-
net/ipv6/netfilter/nf_conntrack_reasm.c | 77 +-
net/ipv6/reassembly.c | 77 +-
net/ipv6/route.c | 173 +--
net/ipv6/sysctl_net_ipv6.c | 322 ++---
net/ipv6/xfrm6_policy.c | 48 +-
net/mpls/af_mpls.c | 154 +--
net/mptcp/ctrl.c | 205 ++-
net/netfilter/ipvs/ip_vs_ctl.c | 533 ++++----
net/netfilter/ipvs/ip_vs_lblc.c | 49 +-
net/netfilter/ipvs/ip_vs_lblcr.c | 50 +-
net/netfilter/nf_conntrack_standalone.c | 743 +++++------
net/netfilter/nf_hooks_lwtunnel.c | 40 +-
net/netfilter/nf_log.c | 90 +-
net/rds/tcp.c | 129 +-
net/rds/tcp.h | 1 -
net/sctp/sysctl.c | 505 +++----
net/smc/smc_sysctl.c | 208 ++-
net/unix/sysctl_net_unix.c | 48 +-
net/vmw_vsock/af_vsock.c | 91 +-
net/xfrm/xfrm_sysctl.c | 77 +-
46 files changed, 3964 insertions(+), 5161 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-08-26 19:43 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-26 19:42 [RFC PATCH v1 00/30] sysctl: add context-bound field descriptors Alexey Gladkov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox