From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-183.mta1.migadu.com (out-183.mta1.migadu.com [95.215.58.183]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9E1B3389DF4 for ; Tue, 13 Jan 2026 17:40:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.183 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768326061; cv=none; b=Mnj4XJlayBpHLJVJ/yUeqeJ1AXY/ssfPQf/8ehJoLZMMfvnlF06aJjy0DhpGXvSsyyMTI2A0763bGjA3PRKxtLV7ucstFjMJBjpcRkFMt2FaszQdvTLCFINkDkROh9YbgEMvHMPQ10NRu21a9/VA/rX6DQHEHnzRWQO6MftGJbE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768326061; c=relaxed/simple; bh=h+CWyFH79b+ck649UTadWNeq1frfKSYLW3i0Y1ktqcY=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=FYh/Nf3fgBpC1Bhc6xUFzNt1IIXOKGcsKyAFGX8p/Kj7oE65uEP7z+tnQgruMf4GMkMQWn2l/qG48I8WjdRsJX00tdvWeu+EWHdlRVGqTQuP0rrixIg/RfrLsyH080Dte3NNS7FdACApnPhx1w8THhKpc3LXGGy+WmyuGv6B8VE= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=GGXAyyCj; arc=none smtp.client-ip=95.215.58.183 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="GGXAyyCj" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1768326057; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tGPLKt/qbYWtt+2IkGYIoT8dXR/EXHgixA9v9y5+YHU=; b=GGXAyyCj635jxIejGsiwqr/Iq71TsLfTm4/40TIeDDRHyWBgwWvYb4KJUXmIxNV4EN/jsN /REiTRenvzmP98Ld7p2on4YxXMehIp/Nyrqvl+697R8Gvzn+R55xR4vaEFlrTgOpuVzIBY 9tz5z9dljhuMfc/JS88GZ6AYIbkUFWM= From: wen.yang@linux.dev To: Joel Granados Cc: linux-kernel@vger.kernel.org, Wen Yang Subject: [RFC PATCH 1/4] sysctl: add SYSCTL_ENTRY/SYSCTL_RANGE_ENTRY helpers for ctl_table init Date: Wed, 14 Jan 2026 01:40:30 +0800 Message-Id: <09f6437ba1aeb067be4d295ec79f2d51f5355ce0.1768324215.git.wen.yang@linux.dev> In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT From: Wen Yang Introduce SYSCTL_ENTRY() and SYSCTL_RANGE_ENTRY() (built on __SYSCTL_ENTRY()) to consolidate common struct ctl_table initializers in one place. This is a preparatory refactor in support of future tree-wide sysctl cleanups by making the how to build a ctl_table entry logic uniform. Also add SYSCTL_NULL for explicitly passing a NULL .data pointer through the new macros, and convert a few in-tree users (kernel/sysctl.c) to validate the new helpers. No functional change intended. Selftest were also made: [19:31:40] Starting KUnit Kernel (1/1)... [19:31:40] ============================================================ Running tests with: $ .kunit/linux kunit.filter_glob=sysctl_test kunit.enable=1 mem=1G console=tty kunit_shutdown=halt [19:31:40] ================ sysctl_test (10 subtests) ================= [19:31:40] [PASSED] sysctl_test_api_dointvec_null_tbl_data [19:31:40] [PASSED] sysctl_test_api_dointvec_table_maxlen_unset [19:31:40] [PASSED] sysctl_test_api_dointvec_table_len_is_zero [19:31:40] [PASSED] sysctl_test_api_dointvec_table_read_but_position_set [19:31:40] [PASSED] sysctl_test_dointvec_read_happy_single_positive [19:31:40] [PASSED] sysctl_test_dointvec_read_happy_single_negative [19:31:40] [PASSED] sysctl_test_dointvec_write_happy_single_positive [19:31:40] [PASSED] sysctl_test_dointvec_write_happy_single_negative [19:31:40] [PASSED] sysctl_test_api_dointvec_write_single_less_int_min [19:31:40] [PASSED] sysctl_test_api_dointvec_write_single_greater_int_max [19:31:40] =================== [PASSED] sysctl_test =================== [19:31:40] ============================================================ [19:31:40] Testing complete. Ran 10 tests: passed: 10 [19:31:40] Elapsed time: 26.755s total, 0.002s configuring, 26.632s building, 0.102s running Suggested-by: Joel Granados Link: https://lore.kernel.org/all/7mevcgca7xsd5gckrap22byjinhrgqnelu4y7hzo2r5t2cq7w4@nyaa42khwqez/#t Signed-off-by: Wen Yang --- include/linux/sysctl.h | 18 ++++++ kernel/sysctl-test.c | 131 ++++++++++------------------------------- kernel/sysctl.c | 43 ++------------ 3 files changed, 56 insertions(+), 136 deletions(-) diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 2886fbceb5d6..683422bc3e7f 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -53,6 +53,7 @@ struct ctl_dir; #define SYSCTL_MAXOLDUID ((void *)&sysctl_vals[10]) #define SYSCTL_NEG_ONE ((void *)&sysctl_vals[11]) +#define SYSCTL_NULL ((void *)NULL) extern const int sysctl_vals[]; #define SYSCTL_LONG_ZERO ((void *)&sysctl_long_vals[0]) @@ -175,6 +176,23 @@ struct ctl_table { void *extra2; } __randomize_layout; +#define __SYSCTL_ENTRY(NAME, DATA, TYPE, MODE, HANDLER, SMIN, SMAX)\ + { \ + .procname = NAME, \ + .data = DATA, \ + .maxlen = sizeof(TYPE), \ + .mode = MODE, \ + .proc_handler = HANDLER, \ + .extra1 = SMIN, \ + .extra2 = SMAX, \ + } + +#define SYSCTL_ENTRY(NAME, DATA, TYPE, MODE) \ + __SYSCTL_ENTRY(NAME, DATA, TYPE, MODE, proc_do##TYPE##vec, NULL, NULL) + +#define SYSCTL_RANGE_ENTRY(NAME, DATA, TYPE, MODE, SMIN, SMAX) \ + __SYSCTL_ENTRY(NAME, DATA, TYPE, MODE, proc_do##TYPE##vec_minmax, SMIN, SMAX) + struct ctl_node { struct rb_node node; struct ctl_table_header *header; diff --git a/kernel/sysctl-test.c b/kernel/sysctl-test.c index 92f94ea28957..7fb0e7f1e62f 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 = SYSCTL_RANGE_ENTRY("foo", \ + SYSCTL_NULL, int, 0644, 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 = SYSCTL_RANGE_ENTRY("foo", \ + &data, int, 0644, SYSCTL_ZERO, SYSCTL_ONE_HUNDRED); + data_maxlen_unset_table.maxlen = 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 = SYSCTL_RANGE_ENTRY("foo", &data, int, 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 = SYSCTL_RANGE_ENTRY("foo", &data, int, 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 = SYSCTL_RANGE_ENTRY("foo", &data, int, 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 = SYSCTL_RANGE_ENTRY("foo", &data, int, 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 = SYSCTL_RANGE_ENTRY("foo", &data, int, 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 = SYSCTL_RANGE_ENTRY("foo", &data, int, 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 = SYSCTL_RANGE_ENTRY("foo", &data, int, 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 = SYSCTL_RANGE_ENTRY("foo", &data, int, 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); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 9d3a666ffde1..2e769550b268 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1373,47 +1373,16 @@ int proc_do_static_key(const struct ctl_table *table, int dir, static const struct ctl_table sysctl_subsys_table[] = { #ifdef CONFIG_PROC_SYSCTL - { - .procname = "sysctl_writes_strict", - .data = &sysctl_writes_strict, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_NEG_ONE, - .extra2 = SYSCTL_ONE, - }, + SYSCTL_RANGE_ENTRY("sysctl_writes_strict", &sysctl_writes_strict, int, \ + 0644, SYSCTL_NEG_ONE, SYSCTL_ONE), #endif - { - .procname = "ngroups_max", - .data = (void *)&ngroups_max, - .maxlen = sizeof (int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, - { - .procname = "cap_last_cap", - .data = (void *)&cap_last_cap, - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, + SYSCTL_ENTRY("ngroups_max", (void *)&ngroups_max, int, 0444), + SYSCTL_ENTRY("cap_last_cap", (void *)&cap_last_cap, int, 0444), #ifdef CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW - { - .procname = "unaligned-trap", - .data = &unaligned_enabled, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, + SYSCTL_ENTRY("unaligned-trap", &unaligned_enabled, int, 0644), #endif #ifdef CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN - { - .procname = "ignore-unaligned-usertrap", - .data = &no_unaligned_warning, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, + SYSCTL_ENTRY("ignore-unaligned-usertrap", &no_unaligned_warning, int, 0644), #endif }; -- 2.25.1