Skip to content

Commit d863574

Browse files
committed
Linux 6.11: avoid passing "end" sentinel to register_sysctl()
Signed-off-by: Rob Norris <[email protected]> Sponsored-by: https://despairlabs.com/sponsor/
1 parent 5ab5168 commit d863574

File tree

3 files changed

+66
-3
lines changed

3 files changed

+66
-3
lines changed

config/kernel-register_sysctl_table.m4

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,32 @@ AC_DEFUN([ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE], [
2626
])
2727
])
2828

29+
dnl #
30+
dnl # Linux 6.11 register_sysctl() enforces that sysctl tables no longer
31+
dnl # supply a sentinel end-of-table element. 6.6 introduces
32+
dnl # register_sysctl_sz() to enable callers to choose, so we use it if
33+
dnl # available for backward compatibility.
34+
dnl #
35+
AC_DEFUN([ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_SZ], [
36+
ZFS_LINUX_TEST_SRC([has_register_sysctl_sz], [
37+
#include <linux/sysctl.h>
38+
],[
39+
struct ctl_table test_table[] __attribute__((unused)) = {0};
40+
register_sysctl_sz("", test_table, 0);
41+
])
42+
])
43+
44+
AC_DEFUN([ZFS_AC_KERNEL_REGISTER_SYSCTL_SZ], [
45+
AC_MSG_CHECKING([whether register_sysctl_sz exists])
46+
ZFS_LINUX_TEST_RESULT([has_register_sysctl_sz], [
47+
AC_MSG_RESULT([yes])
48+
AC_DEFINE(HAVE_REGISTER_SYSCTL_SZ, 1,
49+
[register_sysctl_sz exists])
50+
],[
51+
AC_MSG_RESULT([no])
52+
])
53+
])
54+
2955
dnl #
3056
dnl # Linux 6.11 makes const the ctl_table arg of proc_handler
3157
dnl #

config/kernel.m4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
167167
ZFS_AC_KERNEL_SRC_WRITEPAGE_T
168168
ZFS_AC_KERNEL_SRC_RECLAIMED
169169
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
170+
ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_SZ
170171
ZFS_AC_KERNEL_SRC_PROC_HANDLER_CTL_TABLE_CONST
171172
ZFS_AC_KERNEL_SRC_COPY_SPLICE_READ
172173
ZFS_AC_KERNEL_SRC_SYNC_BDEV
@@ -321,6 +322,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
321322
ZFS_AC_KERNEL_WRITEPAGE_T
322323
ZFS_AC_KERNEL_RECLAIMED
323324
ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
325+
ZFS_AC_KERNEL_REGISTER_SYSCTL_SZ
324326
ZFS_AC_KERNEL_PROC_HANDLER_CTL_TABLE_CONST
325327
ZFS_AC_KERNEL_COPY_SPLICE_READ
326328
ZFS_AC_KERNEL_SYNC_BDEV

module/os/linux/spl/spl-proc.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
*
2323
* Solaris Porting Layer (SPL) Proc Implementation.
2424
*/
25+
/*
26+
* Copyright (c) 2024, Rob Norris <[email protected]>
27+
*/
2528

2629
#include <sys/systeminfo.h>
2730
#include <sys/kstat.h>
@@ -694,6 +697,37 @@ static void spl_proc_cleanup(void)
694697
}
695698
}
696699

700+
#ifndef HAVE_REGISTER_SYSCTL_TABLE
701+
702+
/*
703+
* Traditionally, struct ctl_table arrays have been terminated by an "empty"
704+
* sentinel element (specifically, one with .procname == NULL).
705+
*
706+
* Linux 6.6 began migrating away from this, adding register_sysctl_sz() so
707+
* that callers could provide the size directly, and redefining
708+
* register_sysctl() to just call register_sysctl_sz() with the array size. It
709+
* retained support for the terminating element so that existing callers would
710+
* continue to work.
711+
*
712+
* Linux 6.11 removed support for the terminating element, instead interpreting
713+
* it as a real malformed element, and rejecting it.
714+
*
715+
* In order to continue support older kernels, we retain the terminating
716+
* sentinel element for our sysctl tables, but instead detect availability of
717+
* register_sysctl_sz(). If it exists, we pass it the array size -1, stopping
718+
* the kernel from trying to process the terminator. For pre-6.6 kernels that
719+
* don't have register_sysctl_sz(), we just use register_sysctl(), which can
720+
* handle the terminating element as it always has.
721+
*/
722+
#ifdef HAVE_REGISTER_SYSCTL_SZ
723+
#define spl_proc_register_sysctl(p, t) \
724+
register_sysctl_sz(p, t, ARRAY_SIZE(t)-1)
725+
#else
726+
#define spl_proc_register_sysctl(p, t) \
727+
register_sysctl(p, t)
728+
#endif
729+
#endif
730+
697731
int
698732
spl_proc_init(void)
699733
{
@@ -704,16 +738,17 @@ spl_proc_init(void)
704738
if (spl_header == NULL)
705739
return (-EUNATCH);
706740
#else
707-
spl_header = register_sysctl("kernel/spl", spl_table);
741+
spl_header = spl_proc_register_sysctl("kernel/spl", spl_table);
708742
if (spl_header == NULL)
709743
return (-EUNATCH);
710744

711-
spl_kmem = register_sysctl("kernel/spl/kmem", spl_kmem_table);
745+
spl_kmem = spl_proc_register_sysctl("kernel/spl/kmem", spl_kmem_table);
712746
if (spl_kmem == NULL) {
713747
rc = -EUNATCH;
714748
goto out;
715749
}
716-
spl_kstat = register_sysctl("kernel/spl/kstat", spl_kstat_table);
750+
spl_kstat = spl_proc_register_sysctl("kernel/spl/kstat",
751+
spl_kstat_table);
717752
if (spl_kstat == NULL) {
718753
rc = -EUNATCH;
719754
goto out;

0 commit comments

Comments
 (0)