All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization
@ 2026-03-25 18:39 wen.yang
  2026-03-25 18:39 ` [RFC PATCH v5 1/2] sysctl: introduce CTLTBL_ENTRY_XXX() helper macros wen.yang
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: wen.yang @ 2026-03-25 18:39 UTC (permalink / raw)
  To: Joel Granados, Kees Cook; +Cc: linux-fsdevel, linux-kernel, Wen Yang

From: Wen Yang <wen.yang@linux.dev>

Historically, changes to how struct ctl_table entries are initialized
(e.g. removing the child field, const-qualifying ctl_table) required
touching hundreds of files across all subsystems.  Such series require
the attention of many maintainers, sometimes need to be pulled into
mainline in a special way, and create lots of unnecessary churn.  With
CTLTBL_ENTRY_XXX(), future structural changes to struct ctl_table need
only update the macro definitions.

Conversion of existing call sites will proceed incrementally from
kernel/sysctl.c outward, rather than as a treewide sweep.

This series:
 1. Introduces the CTLTBL_ENTRY_XXX() macros in include/linux/sysctl.h,
    using _Generic() for automatic proc_handler selection, auto
    address-of, auto maxlen via sizeof(), and compile-time validation.
    Supported types: int, unsigned int, long, unsigned long, bool, u8.
 2. Converts kernel/sysctl-test.c as a demonstration, adding a
    parameterized KUnit test covering all macro variants (V, VM, VMR,
    VN, VNM, VNMH) across int, u8, bool, and char[] types.

Based on discussion and suggestions from:
[1] https://sysctl-dev-rtd.readthedocs.io/en/latest/notes/ctltable_entry_macro.html
[2] https://lore.kernel.org/all/psot4oeauxi3yyj2w4ajm3tfgtcsvao4rhv5sgd5s6ymmjgojk@p3vrj3qluban/

---
Changes in v5:
  - Extend __CTL_AUTO_HANDLER to support bool and u8
  - Replace individual test functions with a single parameterized KUnit
    test (KUNIT_CASE_PARAM) covering all variants and types
  - Use struct ctl_table as the expected-value container in the param
    struct, eliminating custom expected_* fields

Changes in v4:
  - Fix Wpointer-type-mismatch warnings detected by lkp:
    https://lore.kernel.org/oe-kbuild-all/202603050724.SZxrEyyu-lkp@intel.com/

Changes in v3:
  - Replace the unique macro with "capital letter approach"
  - Reduce the name further
  https://lore.kernel.org/all/rn4rsazh7kxf5byq65vw2phyqgzvwm3scczu3l5h2r4aqit2r6@znlpb24z2zuo/

Changes in v2:
  - Add lvalue check, handler type check, etc.
  https://lore.kernel.org/all/xptwb3uwbzposd4xf7khj52ifv4tchcjdgllhv7aabi6d7wgef@2msurl564v53/


Wen Yang (2):
  sysctl: introduce CTLTBL_ENTRY_XXX() helper macros
  sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX()

 include/linux/sysctl.h | 307 +++++++++++++++++++++++++++++++++++++++++
 kernel/sysctl-test.c   | 237 ++++++++++++++++++-------------
 kernel/sysctl.c        |   2 +
 3 files changed, 447 insertions(+), 99 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [RFC PATCH v5 1/2] sysctl: introduce CTLTBL_ENTRY_XXX() helper macros
  2026-03-25 18:39 [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization wen.yang
@ 2026-03-25 18:39 ` wen.yang
  2026-03-25 18:39 ` [RFC PATCH v5 2/2] sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX() wen.yang
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: wen.yang @ 2026-03-25 18:39 UTC (permalink / raw)
  To: Joel Granados, Kees Cook; +Cc: linux-fsdevel, linux-kernel, Wen Yang

From: Wen Yang <wen.yang@linux.dev>

Historically, changes to how struct ctl_table entries are initialized
(e.g. removing the child field, const-qualifying ctl_table) required
touching hundreds of files across all subsystems.  Such series require
the attention of many maintainers, sometimes need to be pulled into
mainline in a special way, and create lots of unnecessary churn.  This
will all go away with the CTLTBL_ENTRY_XXX helper macros.

Add a family of CTLTBL_ENTRY_XXX() macros that reduce the boilerplate
of initialising struct ctl_table.  The suffix letters encode the
accepted arguments: V derives .procname from the variable name, N takes
an explicit name, M an explicit mode, H an explicit handler, R enables
range checking via extra1/extra2, and L overrides .maxlen.  Unspecified
fields default to: .procname = #var, .data = &var, .maxlen = sizeof(var),
and .proc_handler selected by _Generic() from the variable type.

Auto-dispatch maps int/unsigned int to proc_dointvec/proc_douintvec,
long/unsigned long to proc_doulongvec_minmax, bool to proc_dobool, and
u8 to proc_dou8vec_minmax.  Range variants (R suffix) substitute the
corresponding _minmax handler.  char[] cannot be dispatched via
_Generic(); use CTLTBL_ENTRY_VNMH() with proc_dostring explicitly.
Pass SYSCTL_NULL as the variable argument for entries where .data must
be NULL.

No functional change.

Suggested-by: Joel Granados <joel.granados@kernel.org>
Signed-off-by: Wen Yang <wen.yang@linux.dev>
---
 include/linux/sysctl.h | 307 +++++++++++++++++++++++++++++++++++++++++
 kernel/sysctl.c        |   2 +
 2 files changed, 309 insertions(+)

diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 2886fbceb5d6..f5aa7bc319da 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -175,6 +175,313 @@ struct ctl_table {
 	void *extra2;
 } __randomize_layout;
 
+/**
+ * struct _sysctl_null_type - sentinel type for variable-less entries
+ */
+struct _sysctl_null_type { char __dummy; };
+
+/**
+ * _sysctl_null_marker - sentinel instance used by SYSCTL_NULL
+ *
+ * Passed via SYSCTL_NULL to mark entries with no associated variable.
+ * Detected by _Generic() dispatch in CTLTBL_ENTRY_XXX().
+ */
+extern const struct _sysctl_null_type _sysctl_null_marker;
+
+/**
+ * SYSCTL_NULL - pass as __var for entries with no associated variable
+ */
+#define SYSCTL_NULL (_sysctl_null_marker)
+
+/**
+ * __CTL_AUTO_HANDLER - select proc_handler based on the variable type
+ *
+ * Supported types: int, unsigned int, long, unsigned long, bool, u8.
+ * char arrays (strings) are not supported; use CTLTBL_ENTRY_VNMH() with
+ * proc_dostring instead.
+ *
+ * @__var: kernel variable (value, not address), or SYSCTL_NULL
+ */
+#define __CTL_AUTO_HANDLER(__var)					\
+	_Generic((__var),						\
+			int          : proc_dointvec,			\
+			unsigned int : proc_douintvec,			\
+			long         : proc_doulongvec_minmax,		\
+			unsigned long: proc_doulongvec_minmax,		\
+			bool         : proc_dobool,			\
+			u8           : proc_dou8vec_minmax,		\
+			default      :					\
+					0xdeadbeaf)
+
+/**
+ * __CTL_AUTO_HANDLER_RANGE - select proc_handler for a range-constrained entry
+ *
+ * Supported types: int, unsigned int, long, unsigned long, u8.
+ * bool is also accepted but proc_dobool ignores extra1/extra2 range bounds.
+ *
+ * @__var: kernel variable (value, not address), or SYSCTL_NULL
+ */
+#define __CTL_AUTO_HANDLER_RANGE(__var)					\
+	_Generic((__var),						\
+			int          : proc_dointvec_minmax,		\
+			unsigned int : proc_douintvec_minmax,		\
+			long         : proc_doulongvec_minmax,		\
+			unsigned long: proc_doulongvec_minmax,		\
+			bool         : proc_dobool,			\
+			u8           : proc_dou8vec_minmax,		\
+			default      :					\
+					0xdeadbeaf)
+
+/**
+ * __CTL_PROCNAME - validate and return the procname string
+ *
+ * "" __name "" enforces a string-literal argument at compile time.
+ *
+ * @__name: procname string literal
+ */
+#define __CTL_PROCNAME(__name)    ("" __name "")
+
+/**
+ * __CTL_DATA - assert __var is addressable; return its address
+ *
+ * SYSCTL_NULL -> (void *)NULL
+ * lvalue __var -> (void *)&(__var)
+ *
+ * @__var: kernel variable (without &), or SYSCTL_NULL
+ */
+#define __CTL_DATA(__var)						\
+	_Generic((__var),						\
+			struct _sysctl_null_type : (void *)NULL,	\
+			default :					\
+				 (void *)&(__var))
+
+/* Compute maxlen for NULL entries: use explicit MAXLEN if >0, else 0 */
+#define __SYSCTL_MAXLEN_NULL(__maxlen)					\
+	((__maxlen) > 0 ? (size_t)(__maxlen) : (size_t)0)
+
+/* Compute maxlen: use explicit MAXLEN if >0, else sizeof(VAR) */
+#define __SYSCTL_MAXLEN_VAR(__var, __maxlen)				\
+	((__maxlen) >= 0 ? (size_t)(__maxlen) : (size_t)sizeof(__var))
+
+/**
+ * __CTL_MAXLEN - compute the .maxlen value
+ *
+ * @__var:    kernel variable (without &), or SYSCTL_NULL
+ * @__maxlen: explicit override, or -1 for auto-sizing
+ */
+#define __CTL_MAXLEN(__var, __maxlen)					\
+	_Generic((__var),						\
+			struct _sysctl_null_type :			\
+				__SYSCTL_MAXLEN_NULL(__maxlen),		\
+			default :					\
+				__SYSCTL_MAXLEN_VAR(__var, __maxlen)	\
+		)
+
+/**
+ * __CTL_MODE - validate and return file permission bits
+ *
+ * @__mode: file permission bits (e.g. 0644)
+ */
+#define __CTL_MODE(__mode)    (0 ? (umode_t)0 : (__mode))
+
+/**
+ * __CTL_HANDLER - validate and return proc_handler
+ *
+ * @__handler: proc_handler
+ */
+#define __CTL_HANDLER(__handler) \
+	(0 ? (typeof(proc_handler) *)0 : (__handler))
+
+/* Validate PTR is pointer-compatible and return it as void* */
+#define __CTL_EXTRA(PTR) \
+		(0 ? (void *)0 : (PTR))
+
+/**
+ * Internal primitive  (single source of truth)
+ *
+ * All public macros delegate here.
+ *
+ * @_var:     kernel variable (without &), or SYSCTL_NULL
+ * @_name:    procname string literal
+ * @_mode:    file permission bits
+ * @_handler: proc_handler-compatible function pointer
+ * @_min:     lower bound pointer, or NULL
+ * @_max:     upper bound pointer, or NULL
+ * @_maxlen:  explicit .maxlen, or -1 for auto-sizing
+ */
+#define __CTLTBL_ENTRY(_var, _name, _mode, _handler, _min, _max, _maxlen) \
+{ \
+	.procname     = __CTL_PROCNAME(_name),				\
+	.data         = __CTL_DATA(_var),				\
+	.maxlen       = __CTL_MAXLEN(_var, _maxlen),			\
+	.mode         = __CTL_MODE(_mode),				\
+	.proc_handler = __CTL_HANDLER(_handler),			\
+	.poll         = NULL,						\
+	.extra1       = __CTL_EXTRA(_min),				\
+	.extra2       = __CTL_EXTRA(_max),				\
+}
+
+/**
+ * Public API
+ *
+ * Naming convention:
+ *   V  - Variable is auto-named via #__var
+ *   N  - explicit Name string
+ *   M  - explicit Mode
+ *   H  - explicit Handler
+ *   R  - Range checking (min/max, selects _minmax handler)
+ *   L  - explicit Length (.maxlen override)
+ */
+
+/**
+ * CTLTBL_ENTRY_V - read-only entry; procname == stringified variable name
+ *
+ * Proto: (T __var)
+ *
+ * .procname = #__var, .mode = 0444, .extra1 = .extra2 = NULL.
+ * proc_handler and .maxlen inferred from typeof(__var).
+ *
+ * @__var: kernel variable (without &); must be an addressable lvalue
+ */
+#define CTLTBL_ENTRY_V(__var)						\
+	__CTLTBL_ENTRY(__var, #__var, 0444,				\
+		__CTL_AUTO_HANDLER(__var), NULL, NULL, -1)
+
+/**
+ * CTLTBL_ENTRY_VM - entry with custom mode; procname == #__var
+ *
+ * Proto: (T __var, umode_t __mode)
+ *
+ * @__var:  kernel variable (without &)
+ * @__mode: file permission bits
+ */
+#define CTLTBL_ENTRY_VM(__var, __mode)					\
+	__CTLTBL_ENTRY(__var, #__var, __mode,				\
+		__CTL_AUTO_HANDLER(__var), NULL, NULL, -1)
+
+/**
+ * CTLTBL_ENTRY_VMR - custom mode with range checking; procname == #__var
+ *
+ * Proto: (T __var, umode_t __mode, T *__min, T *__max)
+ *
+ * @__var:  kernel variable (without &)
+ * @__mode: file permission bits
+ * @__min:  pointer to minimum value; typeof(*__min) must == typeof(__var)
+ * @__max:  pointer to maximum value; typeof(*__max) must == typeof(__var)
+ */
+#define CTLTBL_ENTRY_VMR(__var, __mode, __min, __max)			\
+	__CTLTBL_ENTRY(__var, #__var, __mode,				\
+		__CTL_AUTO_HANDLER_RANGE(__var), __min, __max, -1)
+
+/**
+ * CTLTBL_ENTRY_VN - read-only entry with explicit procname
+ *
+ * Proto: (T __var, const char *__name)
+ *
+ * @__var:  kernel variable (without &)
+ * @__name: procname string literal
+ */
+#define CTLTBL_ENTRY_VN(__var, __name)					\
+	__CTLTBL_ENTRY(__var, __name, 0444,				\
+		__CTL_AUTO_HANDLER(__var), NULL, NULL, -1)
+
+/**
+ * CTLTBL_ENTRY_VNM - entry with explicit procname and mode
+ *
+ * Proto: (T __var, const char *__name, umode_t __mode)
+ *
+ * @__var:  kernel variable (without &)
+ * @__name: procname string literal
+ * @__mode: file permission bits
+ */
+#define CTLTBL_ENTRY_VNM(__var, __name, __mode)				\
+	__CTLTBL_ENTRY(__var, __name, __mode,				\
+		__CTL_AUTO_HANDLER(__var), NULL, NULL, -1)
+
+/**
+ * CTLTBL_ENTRY_VNMH - entry with explicit procname, mode and handler
+ *
+ * Proto: (T __var, const char *__name, umode_t __mode,
+ *         proc_handler *__handler)
+ *
+ * @__var:     kernel variable (without &), or SYSCTL_NULL
+ * @__name:    procname string literal
+ * @__mode:    file permission bits
+ * @__handler: proc_handler-compatible function pointer
+ */
+#define CTLTBL_ENTRY_VNMH(__var, __name, __mode, __handler)		\
+	__CTLTBL_ENTRY(__var, __name, __mode, __handler, NULL, NULL, -1)
+
+/**
+ * CTLTBL_ENTRY_VNMR - entry with procname, mode and range checking
+ *
+ * Proto: (T __var, const char *__name, umode_t __mode,
+ *         T *__min, T *__max)
+ *
+ * @__var:  kernel variable (without &)
+ * @__name: procname string literal
+ * @__mode: file permission bits
+ * @__min:  pointer to minimum value; typeof(*__min) must == typeof(__var)
+ * @__max:  pointer to maximum value; typeof(*__max) must == typeof(__var)
+ */
+#define CTLTBL_ENTRY_VNMR(__var, __name, __mode, __min, __max)		\
+	__CTLTBL_ENTRY(__var, __name, __mode,				\
+		__CTL_AUTO_HANDLER_RANGE(__var), __min, __max, -1)
+
+/**
+ * CTLTBL_ENTRY_VNMHR - entry with explicit handler and range
+ *
+ * Proto: (T __var, const char *__name, umode_t __mode,
+ *         proc_handler *__handler, T *__min, T *__max)
+ *
+ * @__var:     kernel variable (without &), or SYSCTL_NULL
+ * @__name:    procname string literal
+ * @__mode:    file permission bits
+ * @__handler: proc_handler-compatible function pointer
+ * @__min:     pointer to minimum value for .extra1
+ * @__max:     pointer to maximum value for .extra2
+ */
+#define CTLTBL_ENTRY_VNMHR(__var, __name, __mode, __handler, __min, __max) \
+	__CTLTBL_ENTRY(__var, __name, __mode, __handler, __min, __max, -1)
+
+/**
+ * CTLTBL_ENTRY_VNMHRL - fully explicit entry
+ *
+ * Proto: (T __var, const char *__name, umode_t __mode,
+ *         proc_handler *__handler, T *__min, T *__max,
+ *         size_t __maxlen)
+ *
+ * Pass -1 for __maxlen to use sizeof(__var) / 0 (auto).
+ * Pass  0 to set .maxlen to zero explicitly.
+ *
+ * @__var:     kernel variable (without &), or SYSCTL_NULL
+ * @__name:    procname string literal
+ * @__mode:    file permission bits
+ * @__handler: proc_handler-compatible function pointer
+ * @__min:     pointer to minimum value for .extra1
+ * @__max:     pointer to maximum value for .extra2
+ * @__maxlen:  explicit value for .maxlen
+ */
+#define CTLTBL_ENTRY_VNMHRL(__var, __name, __mode, __handler,		\
+			    __min, __max, __maxlen)			\
+	__CTLTBL_ENTRY(__var, __name, __mode, __handler, __min, __max, __maxlen)
+
+/**
+ * CTLTBL_ENTRY_NMH - custom-handler entry with no associated variable
+ *
+ * Proto: (const char *__name, umode_t __mode,
+ *         proc_handler *__handler)
+ *
+ * Shorthand for CTLTBL_ENTRY_VNMH(SYSCTL_NULL, ...).
+ * .data = NULL, .maxlen = 0, .extra1 = NULL, .extra2 = NULL.
+ *
+ * @__name:    procname string literal
+ * @__mode:    file permission bits
+ * @__handler: proc_handler-compatible function pointer
+ */
+#define CTLTBL_ENTRY_NMH(__name, __mode, __handler)			\
+	CTLTBL_ENTRY_VNMH(SYSCTL_NULL, __name, __mode, __handler)
+
 struct ctl_node {
 	struct rb_node node;
 	struct ctl_table_header *header;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 9d3a666ffde1..121e743e7709 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -29,6 +29,8 @@ EXPORT_SYMBOL(sysctl_vals);
 const unsigned long sysctl_long_vals[] = { 0, 1, LONG_MAX };
 EXPORT_SYMBOL_GPL(sysctl_long_vals);
 
+const struct _sysctl_null_type _sysctl_null_marker;
+
 #if defined(CONFIG_SYSCTL)
 
 /* Constants used for minimum and maximum */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [RFC PATCH v5 2/2] sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX()
  2026-03-25 18:39 [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization wen.yang
  2026-03-25 18:39 ` [RFC PATCH v5 1/2] sysctl: introduce CTLTBL_ENTRY_XXX() helper macros wen.yang
@ 2026-03-25 18:39 ` wen.yang
  2026-03-30 19:52   ` kernel test robot
  2026-04-07  7:28 ` [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization Joel Granados
  2026-06-13 15:56 ` Wen Yang
  3 siblings, 1 reply; 6+ messages in thread
From: wen.yang @ 2026-03-25 18:39 UTC (permalink / raw)
  To: Joel Granados, Kees Cook; +Cc: linux-fsdevel, linux-kernel, Wen Yang

From: Wen Yang <wen.yang@linux.dev>

Replace open-coded struct ctl_table initialisers with the
CTLTBL_ENTRY_VNMR(), CTLTBL_ENTRY_VNMHR(), and CTLTBL_ENTRY_VNMHRL()
macros introduced in the previous patch.

Add a parameterized KUnit test case exercising all CTLTBL_ENTRY_XXX()
variants (V, VM, VMR, VN, VNM, VNMH) for int, u8, and bool types.
char[] (proc_dostring) requires CTLTBL_ENTRY_VNMH() with an explicit
handler since _Generic cannot dispatch on array types.

Suggested-by: Joel Granados <joel.granados@kernel.org>
Signed-off-by: Wen Yang <wen.yang@linux.dev>
---
 kernel/sysctl-test.c | 237 +++++++++++++++++++++++++------------------
 1 file changed, 138 insertions(+), 99 deletions(-)

diff --git a/kernel/sysctl-test.c b/kernel/sysctl-test.c
index 92f94ea28957..3b37bb0516e3 100644
--- a/kernel/sysctl-test.c
+++ b/kernel/sysctl-test.c
@@ -15,20 +15,14 @@
  */
 static void sysctl_test_api_dointvec_null_tbl_data(struct kunit *test)
 {
-	struct ctl_table null_data_table = {
-		.procname = "foo",
-		/*
-		 * Here we are testing that proc_dointvec behaves correctly when
-		 * we give it a NULL .data field. Normally this would point to a
-		 * piece of memory where the value would be stored.
-		 */
-		.data		= NULL,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	/*
+	 * Here we are testing that proc_dointvec behaves correctly when
+	 * we give it a NULL .data field. Normally this would point to a
+	 * piece of memory where the value would be stored.
+	 */
+	struct ctl_table null_data_table = CTLTBL_ENTRY_VNMHR(
+			SYSCTL_NULL, "foo", 0644, proc_dointvec,
+			SYSCTL_ZERO, SYSCTL_ONE_HUNDRED);
 	/*
 	 * proc_dointvec expects a buffer in user space, so we allocate one. We
 	 * also need to cast it to __user so sparse doesn't get mad.
@@ -66,19 +60,14 @@ static void sysctl_test_api_dointvec_null_tbl_data(struct kunit *test)
 static void sysctl_test_api_dointvec_table_maxlen_unset(struct kunit *test)
 {
 	int data = 0;
-	struct ctl_table data_maxlen_unset_table = {
-		.procname = "foo",
-		.data		= &data,
-		/*
-		 * So .data is no longer NULL, but we tell proc_dointvec its
-		 * length is 0, so it still shouldn't try to use it.
-		 */
-		.maxlen		= 0,
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	/*
+	 * So .data is no longer NULL, but we tell proc_dointvec its
+	 * length is 0, so it still shouldn't try to use it.
+	 */
+	struct ctl_table data_maxlen_unset_table = CTLTBL_ENTRY_VNMHRL(
+			data, "foo", 0644, proc_dointvec,
+			SYSCTL_ZERO, SYSCTL_ONE_HUNDRED, 0);
+
 	void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
 							   GFP_USER);
 	size_t len;
@@ -113,15 +102,8 @@ static void sysctl_test_api_dointvec_table_len_is_zero(struct kunit *test)
 {
 	int data = 0;
 	/* Good table. */
-	struct ctl_table table = {
-		.procname = "foo",
-		.data		= &data,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	struct ctl_table table = CTLTBL_ENTRY_VNMR(data, "foo",
+			0644, SYSCTL_ZERO, SYSCTL_ONE_HUNDRED);
 	void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
 							   GFP_USER);
 	/*
@@ -147,15 +129,8 @@ static void sysctl_test_api_dointvec_table_read_but_position_set(
 {
 	int data = 0;
 	/* Good table. */
-	struct ctl_table table = {
-		.procname = "foo",
-		.data		= &data,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	struct ctl_table table = CTLTBL_ENTRY_VNMR(data, "foo", 0644,
+			SYSCTL_ZERO, SYSCTL_ONE_HUNDRED);
 	void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
 							   GFP_USER);
 	/*
@@ -182,15 +157,8 @@ static void sysctl_test_dointvec_read_happy_single_positive(struct kunit *test)
 {
 	int data = 0;
 	/* Good table. */
-	struct ctl_table table = {
-		.procname = "foo",
-		.data		= &data,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	struct ctl_table table = CTLTBL_ENTRY_VNMR(data, "foo", 0644,
+			SYSCTL_ZERO, SYSCTL_ONE_HUNDRED);
 	size_t len = 4;
 	loff_t pos = 0;
 	char *buffer = kunit_kzalloc(test, len, GFP_USER);
@@ -213,15 +181,8 @@ static void sysctl_test_dointvec_read_happy_single_negative(struct kunit *test)
 {
 	int data = 0;
 	/* Good table. */
-	struct ctl_table table = {
-		.procname = "foo",
-		.data		= &data,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	struct ctl_table table = CTLTBL_ENTRY_VNMR(data, "foo", 0644,
+			SYSCTL_ZERO, SYSCTL_ONE_HUNDRED);
 	size_t len = 5;
 	loff_t pos = 0;
 	char *buffer = kunit_kzalloc(test, len, GFP_USER);
@@ -242,15 +203,8 @@ static void sysctl_test_dointvec_write_happy_single_positive(struct kunit *test)
 {
 	int data = 0;
 	/* Good table. */
-	struct ctl_table table = {
-		.procname = "foo",
-		.data		= &data,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	struct ctl_table table = CTLTBL_ENTRY_VNMR(data, "foo", 0644,
+			SYSCTL_ZERO, SYSCTL_ONE_HUNDRED);
 	char input[] = "9";
 	size_t len = sizeof(input) - 1;
 	loff_t pos = 0;
@@ -272,15 +226,8 @@ static void sysctl_test_dointvec_write_happy_single_positive(struct kunit *test)
 static void sysctl_test_dointvec_write_happy_single_negative(struct kunit *test)
 {
 	int data = 0;
-	struct ctl_table table = {
-		.procname = "foo",
-		.data		= &data,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	struct ctl_table table = CTLTBL_ENTRY_VNMR(data, "foo", 0644,
+			SYSCTL_ZERO, SYSCTL_ONE_HUNDRED);
 	char input[] = "-9";
 	size_t len = sizeof(input) - 1;
 	loff_t pos = 0;
@@ -304,15 +251,8 @@ static void sysctl_test_api_dointvec_write_single_less_int_min(
 		struct kunit *test)
 {
 	int data = 0;
-	struct ctl_table table = {
-		.procname = "foo",
-		.data		= &data,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	struct ctl_table table = CTLTBL_ENTRY_VNMR(data, "foo", 0644,
+			SYSCTL_ZERO, SYSCTL_ONE_HUNDRED);
 	size_t max_len = 32, len = max_len;
 	loff_t pos = 0;
 	char *buffer = kunit_kzalloc(test, max_len, GFP_USER);
@@ -342,15 +282,8 @@ static void sysctl_test_api_dointvec_write_single_greater_int_max(
 		struct kunit *test)
 {
 	int data = 0;
-	struct ctl_table table = {
-		.procname = "foo",
-		.data		= &data,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-		.extra1		= SYSCTL_ZERO,
-		.extra2         = SYSCTL_ONE_HUNDRED,
-	};
+	struct ctl_table table = CTLTBL_ENTRY_VNMR(data, "foo", 0644,
+			SYSCTL_ZERO, SYSCTL_ONE_HUNDRED);
 	size_t max_len = 32, len = max_len;
 	loff_t pos = 0;
 	char *buffer = kunit_kzalloc(test, max_len, GFP_USER);
@@ -367,6 +300,111 @@ static void sysctl_test_api_dointvec_write_single_greater_int_max(
 	KUNIT_EXPECT_EQ(test, 0, *((int *)table.data));
 }
 
+/*
+ * Test each CTLTBL_ENTRY_XXX() variant.  File-scope variables are required
+ * so that &var is a valid constant expression in a static initializer.
+ */
+static int  ctltbl_int;
+static u8   ctltbl_u8;
+static u8   ctltbl_u8_min, ctltbl_u8_max = 200;
+static bool ctltbl_bool;
+static char ctltbl_str[64];
+
+struct ctltbl_param {
+	const char       *desc;
+	struct ctl_table  table;    /* built by CTLTBL_ENTRY_XXX() */
+	struct ctl_table  expected; /* expected field values */
+};
+
+static const struct ctltbl_param ctltbl_cases[] = {
+	/* auto handler — int */
+	{
+		.desc  = "sysctl_test_api_ctltbl_entry_V_int",
+		.table = CTLTBL_ENTRY_V(ctltbl_int),
+		.expected = { .procname = "ctltbl_int", .mode = 0444,
+			      .data = &ctltbl_int, .maxlen = sizeof(int),
+			      .proc_handler = proc_dointvec },
+	},
+	{
+		.desc  = "sysctl_test_api_ctltbl_entry_VM_int",
+		.table = CTLTBL_ENTRY_VM(ctltbl_int, 0644),
+		.expected = { .procname = "ctltbl_int", .mode = 0644,
+			      .data = &ctltbl_int, .maxlen = sizeof(int),
+			      .proc_handler = proc_dointvec },
+	},
+	{
+		.desc  = "sysctl_test_api_ctltbl_entry_VMR_int",
+		.table = CTLTBL_ENTRY_VMR(ctltbl_int, 0644,
+					  SYSCTL_ZERO, SYSCTL_ONE_HUNDRED),
+		.expected = { .procname = "ctltbl_int", .mode = 0644,
+			      .data = &ctltbl_int, .maxlen = sizeof(int),
+			      .proc_handler = proc_dointvec_minmax },
+	},
+	{
+		.desc  = "sysctl_test_api_ctltbl_entry_VN_int",
+		.table = CTLTBL_ENTRY_VN(ctltbl_int, "my-sysctl"),
+		.expected = { .procname = "my-sysctl", .mode = 0444,
+			      .data = &ctltbl_int, .maxlen = sizeof(int),
+			      .proc_handler = proc_dointvec },
+	},
+	{
+		.desc  = "sysctl_test_api_ctltbl_entry_VNM_int",
+		.table = CTLTBL_ENTRY_VNM(ctltbl_int, "my-sysctl", 0644),
+		.expected = { .procname = "my-sysctl", .mode = 0644,
+			      .data = &ctltbl_int, .maxlen = sizeof(int),
+			      .proc_handler = proc_dointvec },
+	},
+	/* auto handler — u8 */
+	{
+		.desc  = "sysctl_test_api_ctltbl_entry_V_u8",
+		.table = CTLTBL_ENTRY_V(ctltbl_u8),
+		.expected = { .procname = "ctltbl_u8", .mode = 0444,
+			      .data = &ctltbl_u8, .maxlen = sizeof(u8),
+			      .proc_handler = proc_dou8vec_minmax },
+	},
+	{
+		.desc  = "sysctl_test_api_ctltbl_entry_VMR_u8",
+		.table = CTLTBL_ENTRY_VMR(ctltbl_u8, 0644,
+					  &ctltbl_u8_min, &ctltbl_u8_max),
+		.expected = { .procname = "ctltbl_u8", .mode = 0644,
+			      .data = &ctltbl_u8, .maxlen = sizeof(u8),
+			      .proc_handler = proc_dou8vec_minmax },
+	},
+	/* auto handler — bool */
+	{
+		.desc  = "sysctl_test_api_ctltbl_entry_V_bool",
+		.table = CTLTBL_ENTRY_V(ctltbl_bool),
+		.expected = { .procname = "ctltbl_bool", .mode = 0444,
+			      .data = &ctltbl_bool, .maxlen = sizeof(bool),
+			      .proc_handler = proc_dobool },
+	},
+	/* VNMH — char[] cannot be auto-dispatched by _Generic (each char[N]
+	 * is a distinct type); explicit handler is required for strings.
+	 * .maxlen must be sizeof(array), not sizeof(char *). */
+	{
+		.desc  = "sysctl_test_api_ctltbl_entry_VNMH_string",
+		.table = CTLTBL_ENTRY_VNMH(ctltbl_str, "foo", 0644,
+					   proc_dostring),
+		.expected = { .procname = "foo", .mode = 0644,
+			      .data = ctltbl_str, .maxlen = sizeof(ctltbl_str),
+			      .proc_handler = proc_dostring },
+	},
+};
+
+KUNIT_ARRAY_PARAM_DESC(ctltbl, ctltbl_cases, desc);
+
+static void sysctl_test_api_ctltbl_entry(struct kunit *test)
+{
+	const struct ctltbl_param *p = test->param_value;
+
+	KUNIT_EXPECT_STREQ(test, p->expected.procname, p->table.procname);
+	KUNIT_EXPECT_EQ(test, p->expected.mode, p->table.mode);
+	KUNIT_EXPECT_PTR_EQ(test, p->expected.data, p->table.data);
+	KUNIT_EXPECT_EQ(test, p->expected.maxlen, p->table.maxlen);
+	KUNIT_EXPECT_PTR_EQ(test, p->expected.proc_handler,
+			p->table.proc_handler);
+}
+
 static struct kunit_case sysctl_test_cases[] = {
 	KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data),
 	KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset),
@@ -378,6 +416,7 @@ static struct kunit_case sysctl_test_cases[] = {
 	KUNIT_CASE(sysctl_test_dointvec_write_happy_single_negative),
 	KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min),
 	KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max),
+	KUNIT_CASE_PARAM(sysctl_test_api_ctltbl_entry, ctltbl_gen_params),
 	{}
 };
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC PATCH v5 2/2] sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX()
  2026-03-25 18:39 ` [RFC PATCH v5 2/2] sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX() wen.yang
@ 2026-03-30 19:52   ` kernel test robot
  0 siblings, 0 replies; 6+ messages in thread
From: kernel test robot @ 2026-03-30 19:52 UTC (permalink / raw)
  To: wen.yang; +Cc: llvm, oe-kbuild-all

Hi,

[This is a private test report for your RFC patch.]
kernel test robot noticed the following build warnings:

[auto build test WARNING on sysctl/sysctl-next]
[also build test WARNING on kees/for-next/pstore kees/for-next/kspp linus/master v7.0-rc6 next-20260327]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/wen-yang-linux-dev/sysctl-introduce-CTLTBL_ENTRY_XXX-helper-macros/20260330-010040
base:   https://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl.git sysctl-next
patch link:    https://lore.kernel.org/r/d2589e4a49044b0d857ee1b9da495ca73d19ae57.1774463505.git.wen.yang%40linux.dev
patch subject: [RFC PATCH v5 2/2] sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX()
config: s390-allmodconfig (https://download.01.org/0day-ci/archive/20260331/202603310301.Ogh6kR6N-lkp@intel.com/config)
compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260331/202603310301.Ogh6kR6N-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603310301.Ogh6kR6N-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> kernel/sysctl-test.c:386:12: warning: implicit conversion from 'size_t' (aka 'unsigned long') to 'int' changes value from 18446744073709551615 to -1 [-Wconstant-conversion]
     386 |                 .table = CTLTBL_ENTRY_VNMH(ctltbl_str, "foo", 0644,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     387 |                                            proc_dostring),
         |                                            ~~~~~~~~~~~~~~
   include/linux/sysctl.h:413:2: note: expanded from macro 'CTLTBL_ENTRY_VNMH'
     413 |         __CTLTBL_ENTRY(__var, __name, __mode, __handler, NULL, NULL, -1)
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:316:18: note: expanded from macro '__CTLTBL_ENTRY'
     312 | #define __CTLTBL_ENTRY(_var, _name, _mode, _handler, _min, _max, _maxlen) \
         |                                                                           ~
     313 | { \
     314 |         .procname     = __CTL_PROCNAME(_name),                          \
     315 |         .data         = __CTL_DATA(_var),                               \
     316 |         .maxlen       = __CTL_MAXLEN(_var, _maxlen),                    \
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:277:5: note: expanded from macro '__CTL_MAXLEN'
     277 |                                 __SYSCTL_MAXLEN_VAR(__var, __maxlen)    \
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:264:21: note: expanded from macro '__SYSCTL_MAXLEN_VAR'
     264 |         ((__maxlen) >= 0 ? (size_t)(__maxlen) : (size_t)sizeof(__var))
         |                            ^~~~~~~~~~~~~~~~~~
   kernel/sysctl-test.c:376:12: warning: implicit conversion from 'size_t' (aka 'unsigned long') to 'int' changes value from 18446744073709551615 to -1 [-Wconstant-conversion]
     376 |                 .table = CTLTBL_ENTRY_V(ctltbl_bool),
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:347:2: note: expanded from macro 'CTLTBL_ENTRY_V'
     347 |         __CTLTBL_ENTRY(__var, #__var, 0444,                             \
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     348 |                 __CTL_AUTO_HANDLER(__var), NULL, NULL, -1)
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:316:18: note: expanded from macro '__CTLTBL_ENTRY'
     312 | #define __CTLTBL_ENTRY(_var, _name, _mode, _handler, _min, _max, _maxlen) \
         |                                                                           ~
     313 | { \
     314 |         .procname     = __CTL_PROCNAME(_name),                          \
     315 |         .data         = __CTL_DATA(_var),                               \
     316 |         .maxlen       = __CTL_MAXLEN(_var, _maxlen),                    \
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:277:5: note: expanded from macro '__CTL_MAXLEN'
     277 |                                 __SYSCTL_MAXLEN_VAR(__var, __maxlen)    \
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:264:21: note: expanded from macro '__SYSCTL_MAXLEN_VAR'
     264 |         ((__maxlen) >= 0 ? (size_t)(__maxlen) : (size_t)sizeof(__var))
         |                            ^~~~~~~~~~~~~~~~~~
   kernel/sysctl-test.c:367:12: warning: implicit conversion from 'size_t' (aka 'unsigned long') to 'int' changes value from 18446744073709551615 to -1 [-Wconstant-conversion]
     367 |                 .table = CTLTBL_ENTRY_VMR(ctltbl_u8, 0644,
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     368 |                                           &ctltbl_u8_min, &ctltbl_u8_max),
         |                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:373:2: note: expanded from macro 'CTLTBL_ENTRY_VMR'
     373 |         __CTLTBL_ENTRY(__var, #__var, __mode,                           \
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     374 |                 __CTL_AUTO_HANDLER_RANGE(__var), __min, __max, -1)
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:316:18: note: expanded from macro '__CTLTBL_ENTRY'
     312 | #define __CTLTBL_ENTRY(_var, _name, _mode, _handler, _min, _max, _maxlen) \
         |                                                                           ~
     313 | { \
     314 |         .procname     = __CTL_PROCNAME(_name),                          \
     315 |         .data         = __CTL_DATA(_var),                               \
     316 |         .maxlen       = __CTL_MAXLEN(_var, _maxlen),                    \
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:277:5: note: expanded from macro '__CTL_MAXLEN'
     277 |                                 __SYSCTL_MAXLEN_VAR(__var, __maxlen)    \
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:264:21: note: expanded from macro '__SYSCTL_MAXLEN_VAR'
     264 |         ((__maxlen) >= 0 ? (size_t)(__maxlen) : (size_t)sizeof(__var))
         |                            ^~~~~~~~~~~~~~~~~~
   kernel/sysctl-test.c:360:12: warning: implicit conversion from 'size_t' (aka 'unsigned long') to 'int' changes value from 18446744073709551615 to -1 [-Wconstant-conversion]
     360 |                 .table = CTLTBL_ENTRY_V(ctltbl_u8),
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:347:2: note: expanded from macro 'CTLTBL_ENTRY_V'
     347 |         __CTLTBL_ENTRY(__var, #__var, 0444,                             \
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     348 |                 __CTL_AUTO_HANDLER(__var), NULL, NULL, -1)
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:316:18: note: expanded from macro '__CTLTBL_ENTRY'
     312 | #define __CTLTBL_ENTRY(_var, _name, _mode, _handler, _min, _max, _maxlen) \
         |                                                                           ~
     313 | { \
     314 |         .procname     = __CTL_PROCNAME(_name),                          \
     315 |         .data         = __CTL_DATA(_var),                               \
     316 |         .maxlen       = __CTL_MAXLEN(_var, _maxlen),                    \
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:277:5: note: expanded from macro '__CTL_MAXLEN'
     277 |                                 __SYSCTL_MAXLEN_VAR(__var, __maxlen)    \
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:264:21: note: expanded from macro '__SYSCTL_MAXLEN_VAR'
     264 |         ((__maxlen) >= 0 ? (size_t)(__maxlen) : (size_t)sizeof(__var))
         |                            ^~~~~~~~~~~~~~~~~~
   kernel/sysctl-test.c:352:12: warning: implicit conversion from 'size_t' (aka 'unsigned long') to 'int' changes value from 18446744073709551615 to -1 [-Wconstant-conversion]
     352 |                 .table = CTLTBL_ENTRY_VNM(ctltbl_int, "my-sysctl", 0644),
         |                          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:398:2: note: expanded from macro 'CTLTBL_ENTRY_VNM'
     398 |         __CTLTBL_ENTRY(__var, __name, __mode,                           \
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     399 |                 __CTL_AUTO_HANDLER(__var), NULL, NULL, -1)
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/sysctl.h:316:18: note: expanded from macro '__CTLTBL_ENTRY'
     312 | #define __CTLTBL_ENTRY(_var, _name, _mode, _handler, _min, _max, _maxlen) \
         |                                                                           ~


vim +386 kernel/sysctl-test.c

   318	
   319	static const struct ctltbl_param ctltbl_cases[] = {
   320		/* auto handler — int */
   321		{
   322			.desc  = "sysctl_test_api_ctltbl_entry_V_int",
   323			.table = CTLTBL_ENTRY_V(ctltbl_int),
   324			.expected = { .procname = "ctltbl_int", .mode = 0444,
   325				      .data = &ctltbl_int, .maxlen = sizeof(int),
   326				      .proc_handler = proc_dointvec },
   327		},
   328		{
   329			.desc  = "sysctl_test_api_ctltbl_entry_VM_int",
   330			.table = CTLTBL_ENTRY_VM(ctltbl_int, 0644),
   331			.expected = { .procname = "ctltbl_int", .mode = 0644,
   332				      .data = &ctltbl_int, .maxlen = sizeof(int),
   333				      .proc_handler = proc_dointvec },
   334		},
   335		{
   336			.desc  = "sysctl_test_api_ctltbl_entry_VMR_int",
   337			.table = CTLTBL_ENTRY_VMR(ctltbl_int, 0644,
   338						  SYSCTL_ZERO, SYSCTL_ONE_HUNDRED),
   339			.expected = { .procname = "ctltbl_int", .mode = 0644,
   340				      .data = &ctltbl_int, .maxlen = sizeof(int),
   341				      .proc_handler = proc_dointvec_minmax },
   342		},
   343		{
   344			.desc  = "sysctl_test_api_ctltbl_entry_VN_int",
   345			.table = CTLTBL_ENTRY_VN(ctltbl_int, "my-sysctl"),
   346			.expected = { .procname = "my-sysctl", .mode = 0444,
   347				      .data = &ctltbl_int, .maxlen = sizeof(int),
   348				      .proc_handler = proc_dointvec },
   349		},
   350		{
   351			.desc  = "sysctl_test_api_ctltbl_entry_VNM_int",
   352			.table = CTLTBL_ENTRY_VNM(ctltbl_int, "my-sysctl", 0644),
   353			.expected = { .procname = "my-sysctl", .mode = 0644,
   354				      .data = &ctltbl_int, .maxlen = sizeof(int),
   355				      .proc_handler = proc_dointvec },
   356		},
   357		/* auto handler — u8 */
   358		{
   359			.desc  = "sysctl_test_api_ctltbl_entry_V_u8",
   360			.table = CTLTBL_ENTRY_V(ctltbl_u8),
   361			.expected = { .procname = "ctltbl_u8", .mode = 0444,
   362				      .data = &ctltbl_u8, .maxlen = sizeof(u8),
   363				      .proc_handler = proc_dou8vec_minmax },
   364		},
   365		{
   366			.desc  = "sysctl_test_api_ctltbl_entry_VMR_u8",
   367			.table = CTLTBL_ENTRY_VMR(ctltbl_u8, 0644,
   368						  &ctltbl_u8_min, &ctltbl_u8_max),
   369			.expected = { .procname = "ctltbl_u8", .mode = 0644,
   370				      .data = &ctltbl_u8, .maxlen = sizeof(u8),
   371				      .proc_handler = proc_dou8vec_minmax },
   372		},
   373		/* auto handler — bool */
   374		{
   375			.desc  = "sysctl_test_api_ctltbl_entry_V_bool",
   376			.table = CTLTBL_ENTRY_V(ctltbl_bool),
   377			.expected = { .procname = "ctltbl_bool", .mode = 0444,
   378				      .data = &ctltbl_bool, .maxlen = sizeof(bool),
   379				      .proc_handler = proc_dobool },
   380		},
   381		/* VNMH — char[] cannot be auto-dispatched by _Generic (each char[N]
   382		 * is a distinct type); explicit handler is required for strings.
   383		 * .maxlen must be sizeof(array), not sizeof(char *). */
   384		{
   385			.desc  = "sysctl_test_api_ctltbl_entry_VNMH_string",
 > 386			.table = CTLTBL_ENTRY_VNMH(ctltbl_str, "foo", 0644,
   387						   proc_dostring),
   388			.expected = { .procname = "foo", .mode = 0644,
   389				      .data = ctltbl_str, .maxlen = sizeof(ctltbl_str),
   390				      .proc_handler = proc_dostring },
   391		},
   392	};
   393	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization
  2026-03-25 18:39 [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization wen.yang
  2026-03-25 18:39 ` [RFC PATCH v5 1/2] sysctl: introduce CTLTBL_ENTRY_XXX() helper macros wen.yang
  2026-03-25 18:39 ` [RFC PATCH v5 2/2] sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX() wen.yang
@ 2026-04-07  7:28 ` Joel Granados
  2026-06-13 15:56 ` Wen Yang
  3 siblings, 0 replies; 6+ messages in thread
From: Joel Granados @ 2026-04-07  7:28 UTC (permalink / raw)
  To: Kees Cook; +Cc: Kees Cook, linux-fsdevel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3217 bytes --]

Hey Kees

I have been trying to avoid having to do a treewide change everytime
that the sysctl ctl_table struct are changed, it creates unnecessary
churn and requires a "review" when there is really no need for it.

This series tries to move the definitions of the struct elements into a
macro within sysctl. I was wondering if you see any red flags that
should be address before this moves forward.

Best

On Thu, Mar 26, 2026 at 02:39:14AM +0800, wen.yang@linux.dev wrote:
> From: Wen Yang <wen.yang@linux.dev>
> 
> Historically, changes to how struct ctl_table entries are initialized
> (e.g. removing the child field, const-qualifying ctl_table) required
> touching hundreds of files across all subsystems.  Such series require
> the attention of many maintainers, sometimes need to be pulled into
> mainline in a special way, and create lots of unnecessary churn.  With
> CTLTBL_ENTRY_XXX(), future structural changes to struct ctl_table need
> only update the macro definitions.
> 
> Conversion of existing call sites will proceed incrementally from
> kernel/sysctl.c outward, rather than as a treewide sweep.
> 
> This series:
>  1. Introduces the CTLTBL_ENTRY_XXX() macros in include/linux/sysctl.h,
>     using _Generic() for automatic proc_handler selection, auto
>     address-of, auto maxlen via sizeof(), and compile-time validation.
>     Supported types: int, unsigned int, long, unsigned long, bool, u8.
>  2. Converts kernel/sysctl-test.c as a demonstration, adding a
>     parameterized KUnit test covering all macro variants (V, VM, VMR,
>     VN, VNM, VNMH) across int, u8, bool, and char[] types.
> 
> Based on discussion and suggestions from:
> [1] https://sysctl-dev-rtd.readthedocs.io/en/latest/notes/ctltable_entry_macro.html
> [2] https://lore.kernel.org/all/psot4oeauxi3yyj2w4ajm3tfgtcsvao4rhv5sgd5s6ymmjgojk@p3vrj3qluban/
> 
> ---
> Changes in v5:
>   - Extend __CTL_AUTO_HANDLER to support bool and u8
>   - Replace individual test functions with a single parameterized KUnit
>     test (KUNIT_CASE_PARAM) covering all variants and types
>   - Use struct ctl_table as the expected-value container in the param
>     struct, eliminating custom expected_* fields
> 
> Changes in v4:
>   - Fix Wpointer-type-mismatch warnings detected by lkp:
>     https://lore.kernel.org/oe-kbuild-all/202603050724.SZxrEyyu-lkp@intel.com/
> 
> Changes in v3:
>   - Replace the unique macro with "capital letter approach"
>   - Reduce the name further
>   https://lore.kernel.org/all/rn4rsazh7kxf5byq65vw2phyqgzvwm3scczu3l5h2r4aqit2r6@znlpb24z2zuo/
> 
> Changes in v2:
>   - Add lvalue check, handler type check, etc.
>   https://lore.kernel.org/all/xptwb3uwbzposd4xf7khj52ifv4tchcjdgllhv7aabi6d7wgef@2msurl564v53/
> 
> 
> Wen Yang (2):
>   sysctl: introduce CTLTBL_ENTRY_XXX() helper macros
>   sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX()
> 
>  include/linux/sysctl.h | 307 +++++++++++++++++++++++++++++++++++++++++
>  kernel/sysctl-test.c   | 237 ++++++++++++++++++-------------
>  kernel/sysctl.c        |   2 +
>  3 files changed, 447 insertions(+), 99 deletions(-)
> 
> -- 
> 2.25.1
> 

-- 

Joel Granados

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization
  2026-03-25 18:39 [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization wen.yang
                   ` (2 preceding siblings ...)
  2026-04-07  7:28 ` [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization Joel Granados
@ 2026-06-13 15:56 ` Wen Yang
  3 siblings, 0 replies; 6+ messages in thread
From: Wen Yang @ 2026-06-13 15:56 UTC (permalink / raw)
  To: Joel Granados, Kees Cook; +Cc: linux-fsdevel, linux-kernel

Hi Kees, H jioel,

Gentle ping on this series. Please let me know if there are any
concerns or if further changes are needed.

The series is available at:
https://lore.kernel.org/all/x5stdwwsfp2h22zyexn5ycbxnkyc4ioxscninxsa6q7lf6djqr@jkuppwwqubkp/

Thanks for your time,
Wen


On 3/26/26 02:39, wen.yang@linux.dev wrote:
> From: Wen Yang <wen.yang@linux.dev>
> 
> Historically, changes to how struct ctl_table entries are initialized
> (e.g. removing the child field, const-qualifying ctl_table) required
> touching hundreds of files across all subsystems.  Such series require
> the attention of many maintainers, sometimes need to be pulled into
> mainline in a special way, and create lots of unnecessary churn.  With
> CTLTBL_ENTRY_XXX(), future structural changes to struct ctl_table need
> only update the macro definitions.
> 
> Conversion of existing call sites will proceed incrementally from
> kernel/sysctl.c outward, rather than as a treewide sweep.
> 
> This series:
>   1. Introduces the CTLTBL_ENTRY_XXX() macros in include/linux/sysctl.h,
>      using _Generic() for automatic proc_handler selection, auto
>      address-of, auto maxlen via sizeof(), and compile-time validation.
>      Supported types: int, unsigned int, long, unsigned long, bool, u8.
>   2. Converts kernel/sysctl-test.c as a demonstration, adding a
>      parameterized KUnit test covering all macro variants (V, VM, VMR,
>      VN, VNM, VNMH) across int, u8, bool, and char[] types.
> 
> Based on discussion and suggestions from:
> [1] https://sysctl-dev-rtd.readthedocs.io/en/latest/notes/ctltable_entry_macro.html
> [2] https://lore.kernel.org/all/psot4oeauxi3yyj2w4ajm3tfgtcsvao4rhv5sgd5s6ymmjgojk@p3vrj3qluban/
> 
> ---
> Changes in v5:
>    - Extend __CTL_AUTO_HANDLER to support bool and u8
>    - Replace individual test functions with a single parameterized KUnit
>      test (KUNIT_CASE_PARAM) covering all variants and types
>    - Use struct ctl_table as the expected-value container in the param
>      struct, eliminating custom expected_* fields
> 
> Changes in v4:
>    - Fix Wpointer-type-mismatch warnings detected by lkp:
>      https://lore.kernel.org/oe-kbuild-all/202603050724.SZxrEyyu-lkp@intel.com/
> 
> Changes in v3:
>    - Replace the unique macro with "capital letter approach"
>    - Reduce the name further
>    https://lore.kernel.org/all/rn4rsazh7kxf5byq65vw2phyqgzvwm3scczu3l5h2r4aqit2r6@znlpb24z2zuo/
> 
> Changes in v2:
>    - Add lvalue check, handler type check, etc.
>    https://lore.kernel.org/all/xptwb3uwbzposd4xf7khj52ifv4tchcjdgllhv7aabi6d7wgef@2msurl564v53/
> 
> 
> Wen Yang (2):
>    sysctl: introduce CTLTBL_ENTRY_XXX() helper macros
>    sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX()
> 
>   include/linux/sysctl.h | 307 +++++++++++++++++++++++++++++++++++++++++
>   kernel/sysctl-test.c   | 237 ++++++++++++++++++-------------
>   kernel/sysctl.c        |   2 +
>   3 files changed, 447 insertions(+), 99 deletions(-)
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-06-13 15:57 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-25 18:39 [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization wen.yang
2026-03-25 18:39 ` [RFC PATCH v5 1/2] sysctl: introduce CTLTBL_ENTRY_XXX() helper macros wen.yang
2026-03-25 18:39 ` [RFC PATCH v5 2/2] sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX() wen.yang
2026-03-30 19:52   ` kernel test robot
2026-04-07  7:28 ` [RFC PATCH v5 0/2] sysctl: add CTLTBL_ENTRY_XXX() macros for ctl_table initialization Joel Granados
2026-06-13 15:56 ` Wen Yang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.