From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-179.mta1.migadu.com (out-179.mta1.migadu.com [95.215.58.179]) (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 73A5237703C for ; Mon, 2 Mar 2026 06:32:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.179 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772433166; cv=none; b=nMvv7A5oGA5gry+50xDzzGI9puSEn2kYqOs86/xJ0k0RYlE01riZkBRSdWvRJd77CxOMLGXgy/HtAGPI/P/MQ/AxHdvd0CHZoPEdQFFB2onU2KpBud0lxLcq33cPHd7tWgycHsBUbTpn+L8Z7l3/hmuS3Wn3Ppnb3nmD56hLT2A= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772433166; c=relaxed/simple; bh=gnns7Exlrrr67r3WwczGQh0XuXl28Bgcxu6QrzuTD5o=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=AlUA1qWmMoDtCfUwk6ye74gsYYPBthsqJE6tsD1HYxJOZH9BHGe8mi/VWZ/s3jTLUhxRXDlCmdOvpnCogLv/oHqTQG/ckdw5QSq7DgjDGxosAvUwbPP3eJ/0PYi4AXdDhIsIqlpt748whQmi1v9MbhHJSLmDjZISJtbOJWulTyE= 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=QccW30lE; arc=none smtp.client-ip=95.215.58.179 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="QccW30lE" 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=1772433162; 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=ZBigN/OpihV7YZ5L4Dsi199pgrPdXeJigFT4FIfatCE=; b=QccW30lEUVutb/QPh2qa6gvhBelLSD19iSjdUM56pbhPqpoSISBs8LLhY/aEXJAiKtPW58 Tfo9fcxk5SGxP+U66hFb/hTCTipufBPD6UOaejwXYHjcHtWU2OK+87Je8i9Cq3+Tm9wcZA 2/G0omBtujFB1IngH/KsIk66s9Af5cY= From: wen.yang@linux.dev To: Joel Granados Cc: linux-kernel@vger.kernel.org, Wen Yang Subject: [RFC PATCH v3 2/2] sysctl: convert kernel/sysctl-test.c to use CTLTBL_ENTRY_XXX() Date: Mon, 2 Mar 2026 14:32:21 +0800 Message-Id: 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 Convert all struct ctl_table initializations in kernel/sysctl-test.c from direct field assignment to indirect initialization via the CTLTBL_ENTRY_XXX() macros introduced in the previous patch. This demonstrates the macros in real usage and validates their correctness against the existing test suite. The following macro variants are exercised: - CTLTBL_ENTRY_VNMR(var, name, mode, min, max) Used for the majority of test cases that initialize a standard int entry with range checking. The macro automatically selects the range-checking handler (proc_dointvec_minmax for int) based on the variable type and computes maxlen via sizeof(): Before: struct ctl_table table = { .procname = "foo", .data = &data, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE_HUNDRED, }; After: struct ctl_table table = CTLTBL_ENTRY_VNMR(data, "foo", 0644, SYSCTL_ZERO, SYSCTL_ONE_HUNDRED); - CTLTBL_ENTRY_VNMHR(var, name, mode, handler, min, max) Used for the NULL data test case, passing SYSCTL_NULL as the data argument and proc_dointvec as the explicit handler: Before: struct ctl_table null_data_table = { .procname = "foo", .data = NULL, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE_HUNDRED, }; After: struct ctl_table null_data_table = CTLTBL_ENTRY_VNMHR( SYSCTL_NULL, "foo", 0644, proc_dointvec, SYSCTL_ZERO, SYSCTL_ONE_HUNDRED); - CTLTBL_ENTRY_VNMHRL(var, name, mode, handler, min, max, maxlen) Used for the maxlen=0 test case, passing an explicit maxlen of 0 to override the default sizeof()-based value: Before: struct ctl_table data_maxlen_unset_table = { .procname = "foo", .data = &data, .maxlen = 0, .mode = 0644, .proc_handler = proc_dointvec, .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE_HUNDRED, }; After: struct ctl_table data_maxlen_unset_table = CTLTBL_ENTRY_VNMHRL( data, "foo", 0644, proc_dointvec, SYSCTL_ZERO, SYSCTL_ONE_HUNDRED, 0); New tests are added to cover the remaining macro variants: - CTLTBL_ENTRY_V(var) Verifies that the macro initializes .procname to the variable name, .mode to 0444, .data to &var, .maxlen to sizeof(var), and selects proc_dointvec as the handler for an int variable. - CTLTBL_ENTRY_VM(var, mode) Verifies that the macro initializes .procname to the variable name, .mode to 0644, .data to &var, .maxlen to sizeof(var), and selects proc_dointvec as the handler for an int variable. - CTLTBL_ENTRY_VMR(var, mode, min, max) Verifies that the macro initializes .procname to the variable name, .mode to 0644, .data to &var, .maxlen to sizeof(var), and auto-selecting proc_dointvec_minmax as the handler. - CTLTBL_ENTRY_VN(var, name) Verifies that the macro initializes .procname to the custom name while keeping .mode at 0444 and auto-selecting the handler. - CTLTBL_ENTRY_VNM(name, var, mode) Verifies that the macro initializes .procname and .mode as specified while auto-selecting the handler. - CTLTBL_ENTRY_VNMH(var, name, mode, handler) Verifies that the macro initializes all fields including an explicitly provided proc_handler. All tests pass: [13:53:49] ================ sysctl_test (16 subtests) ================= [13:53:49] [PASSED] sysctl_test_api_dointvec_null_tbl_data [13:53:49] [PASSED] sysctl_test_api_dointvec_table_maxlen_unset [13:53:49] [PASSED] sysctl_test_api_dointvec_table_len_is_zero [13:53:49] [PASSED] sysctl_test_api_dointvec_table_read_but_position_set [13:53:49] [PASSED] sysctl_test_dointvec_read_happy_single_positive [13:53:49] [PASSED] sysctl_test_dointvec_read_happy_single_negative [13:53:49] [PASSED] sysctl_test_dointvec_write_happy_single_positive [13:53:49] [PASSED] sysctl_test_dointvec_write_happy_single_negative [13:53:49] [PASSED] sysctl_test_api_dointvec_write_single_less_int_min [13:53:49] [PASSED] sysctl_test_api_dointvec_write_single_greater_int_max [13:53:49] [PASSED] sysctl_test_api_ctltbl_entry_v [13:53:49] [PASSED] sysctl_test_api_ctltbl_entry_vm [13:53:49] [PASSED] sysctl_test_api_ctltbl_entry_vmr [13:53:49] [PASSED] sysctl_test_api_ctltbl_entry_vn [13:53:49] [PASSED] sysctl_test_api_ctltbl_entry_vnm [13:53:49] [PASSED] sysctl_test_api_ctltbl_entry_vnmh [13:53:49] =================== [PASSED] sysctl_test =================== [13:53:49] ============================================================ [13:53:49] Testing complete. Ran 16 tests: passed: 16 Suggested-by: Joel Granados Signed-off-by: Wen Yang --- kernel/sysctl-test.c | 240 +++++++++++++++++++++++++------------------ 1 file changed, 141 insertions(+), 99 deletions(-) diff --git a/kernel/sysctl-test.c b/kernel/sysctl-test.c index 92f94ea28957..410e6ce32ee1 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,109 @@ static void sysctl_test_api_dointvec_write_single_greater_int_max( KUNIT_EXPECT_EQ(test, 0, *((int *)table.data)); } +/* + * Test CTLTBL_ENTRY_V: variable name used as procname, mode 0444, + * auto-selected handler (proc_dointvec for int). + */ +static void sysctl_test_api_ctltbl_entry_v(struct kunit *test) +{ + int foo = 123; + struct ctl_table table = CTLTBL_ENTRY_V(foo); + + KUNIT_EXPECT_STREQ(test, "foo", table.procname); + KUNIT_EXPECT_EQ(test, (umode_t)0444, table.mode); + KUNIT_EXPECT_PTR_EQ(test, &foo, table.data); + KUNIT_EXPECT_EQ(test, sizeof(int), table.maxlen); + KUNIT_EXPECT_PTR_EQ(test, (proc_handler *)proc_dointvec, + table.proc_handler); +} + +/* + * Test CTLTBL_ENTRY_VM: variable name used as procname, custom mode, + * auto-selected handler (proc_dointvec for int). + */ +static void sysctl_test_api_ctltbl_entry_vm(struct kunit *test) +{ + int foo = 123; + struct ctl_table table = CTLTBL_ENTRY_VM(foo, 0644); + + KUNIT_EXPECT_STREQ(test, "foo", table.procname); + KUNIT_EXPECT_EQ(test, (umode_t)0644, table.mode); + KUNIT_EXPECT_PTR_EQ(test, &foo, table.data); + KUNIT_EXPECT_EQ(test, sizeof(int), table.maxlen); + KUNIT_EXPECT_PTR_EQ(test, (proc_handler *)proc_dointvec, + table.proc_handler); +} + +/* + * Test CTLTBL_ENTRY_VMR: variable name used as procname, custom mode, + * auto-selected range checkint handler (proc_dointvec_minmax for int). + */ +static void sysctl_test_api_ctltbl_entry_vmr(struct kunit *test) +{ + int foo = 123; + struct ctl_table table = CTLTBL_ENTRY_VMR(foo, 0644, SYSCTL_ZERO, + SYSCTL_ONE_HUNDRED); + + KUNIT_EXPECT_STREQ(test, "foo", table.procname); + KUNIT_EXPECT_EQ(test, (umode_t)0644, table.mode); + KUNIT_EXPECT_PTR_EQ(test, &foo, table.data); + KUNIT_EXPECT_EQ(test, sizeof(int), table.maxlen); + KUNIT_EXPECT_PTR_EQ(test, (proc_handler *)proc_dointvec_minmax, + table.proc_handler); +} + +/* + * Test CTLTBL_ENTRY_VN: custom procname, mode 0444, + * auto-selected handler (proc_dointvec for int). + */ +static void sysctl_test_api_ctltbl_entry_vn(struct kunit *test) +{ + int data = 0; + struct ctl_table table = CTLTBL_ENTRY_VN(data, "foo"); + + KUNIT_EXPECT_STREQ(test, "foo", table.procname); + KUNIT_EXPECT_EQ(test, (umode_t)0444, table.mode); + KUNIT_EXPECT_PTR_EQ(test, &data, table.data); + KUNIT_EXPECT_EQ(test, sizeof(int), table.maxlen); + KUNIT_EXPECT_PTR_EQ(test, (proc_handler *)proc_dointvec, + table.proc_handler); +} + +/* + * Test CTLTBL_ENTRY_VNM: custom procname and mode, + * auto-selected handler (proc_dointvec for int). + */ +static void sysctl_test_api_ctltbl_entry_vnm(struct kunit *test) +{ + int data = 0; + struct ctl_table table = CTLTBL_ENTRY_VNM(data, "foo", 0644); + + KUNIT_EXPECT_STREQ(test, "foo", table.procname); + KUNIT_EXPECT_EQ(test, (umode_t)0644, table.mode); + KUNIT_EXPECT_PTR_EQ(test, &data, table.data); + KUNIT_EXPECT_EQ(test, sizeof(int), table.maxlen); + KUNIT_EXPECT_PTR_EQ(test, (proc_handler *)proc_dointvec, + table.proc_handler); +} + +/* + * Test CTLTBL_ENTRY_VNMH: custom procname, mode and explicit handler. + */ +static void sysctl_test_api_ctltbl_entry_vnmh(struct kunit *test) +{ + int data = 0; + struct ctl_table table = CTLTBL_ENTRY_VNMH(data, "foo", 0644, + proc_dointvec); + + KUNIT_EXPECT_STREQ(test, "foo", table.procname); + KUNIT_EXPECT_EQ(test, (umode_t)0644, table.mode); + KUNIT_EXPECT_PTR_EQ(test, &data, table.data); + KUNIT_EXPECT_EQ(test, sizeof(int), table.maxlen); + KUNIT_EXPECT_PTR_EQ(test, (proc_handler *)proc_dointvec, + 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 +414,12 @@ 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(sysctl_test_api_ctltbl_entry_v), + KUNIT_CASE(sysctl_test_api_ctltbl_entry_vm), + KUNIT_CASE(sysctl_test_api_ctltbl_entry_vmr), + KUNIT_CASE(sysctl_test_api_ctltbl_entry_vn), + KUNIT_CASE(sysctl_test_api_ctltbl_entry_vnm), + KUNIT_CASE(sysctl_test_api_ctltbl_entry_vnmh), {} }; -- 2.25.1