summaryrefslogtreecommitdiffstats
path: root/lib/test_sysctl.c
diff options
context:
space:
mode:
authorNiklas Cassel <cassel@kernel.org>2026-09-16 15:00:32 +0200
committerNiklas Cassel <cassel@kernel.org>2026-09-16 16:18:00 +0200
commit8d836581f9b1f57ceaa2b47654754ef1260b410b (patch)
tree1dbd4d0dfb99c2e238356cbe947e5b0be3e3a571 /lib/test_sysctl.c
downloadlinux-stable-8d836581f9b1f57ceaa2b47654754ef1260b410b.tar.gz
linux-stable-8d836581f9b1f57ceaa2b47654754ef1260b410b.zip
ata: libata-scsi: fix ata_dsm_trim_pages() kernel-docgrafted
make htmldocs fails with: Documentation/driver-api/libata:604: ./drivers/ata/libata-scsi.c:2301: ERROR: Unexpected indentation. [docutils] The Return: section of ata_dsm_trim_pages() ends its first sentence with a colon and continues with an indented bullet list. reStructuredText requires a blank line before an indented block, so docutils chokes on the list. Simply adding the missing blank line does not work either: Return: is a kernel-doc "special section", which is terminated by the first blank line, so the bullet list would end up in the Description section, detached from the sentence introducing it. Spell the two bounds out as prose instead, so that the Return: section stays self-contained. Documentation-only change. Fixes: e64e6b5dc867 ("ata: libata-scsi: scale DSM TRIM payload by MAX PAGES PER DSM COMMAND") Reported-by: Thomas Huth <thuth@redhat.com> Closes: https://lore.kernel.org/linux-ide/b0a0b8e8-cc4f-4c7b-8bc5-fee0712d405a@redhat.com/ Reviewed-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Thomas Huth <thuth@redhat.com> Link: https://lore.kernel.org/r/20260916130031.29990-2-cassel@kernel.org Signed-off-by: Niklas Cassel <cassel@kernel.org>
Diffstat (limited to 'lib/test_sysctl.c')
-rw-r--r--lib/test_sysctl.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c
new file mode 100644
index 000000000..909cfcf76
--- /dev/null
+++ b/lib/test_sysctl.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.1
+/*
+ * proc sysctl test driver
+ *
+ * Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>
+ */
+
+/*
+ * This module provides an interface to the proc sysctl interfaces. This
+ * driver requires CONFIG_SYSCTL. It will not normally be loaded by the
+ * system unless explicitly requested by name. You can also build this driver
+ * into your kernel.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/async.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+
+static int i_zero;
+static int i_one_hundred = 100;
+static int match_int_ok = 1;
+
+enum {
+ TEST_H_SETUP_NODE,
+ TEST_H_MNT,
+ TEST_H_MNTERROR,
+ TEST_H_EMPTY_ADD,
+ TEST_H_EMPTY,
+ TEST_H_U8,
+ TEST_H_SIZE /* Always at the end */
+};
+
+static struct ctl_table_header *ctl_headers[TEST_H_SIZE] = {};
+struct test_sysctl_data {
+ int int_0001;
+ int int_0002;
+ int int_0003[4];
+
+ int boot_int;
+
+ unsigned int uint_0001;
+
+ char string_0001[65];
+
+#define SYSCTL_TEST_BITMAP_SIZE 65536
+ unsigned long *bitmap_0001;
+};
+
+static struct test_sysctl_data test_data = {
+ .int_0001 = 60,
+ .int_0002 = 1,
+
+ .int_0003[0] = 0,
+ .int_0003[1] = 1,
+ .int_0003[2] = 2,
+ .int_0003[3] = 3,
+
+ .boot_int = 0,
+
+ .uint_0001 = 314,
+
+ .string_0001 = "(none)",
+};
+
+/* These are all under /proc/sys/debug/test_sysctl/ */
+static const struct ctl_table test_table[] = {
+ {
+ .procname = "int_0001",
+ .data = &test_data.int_0001,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &i_zero,
+ .extra2 = &i_one_hundred,
+ },
+ {
+ .procname = "int_0002",
+ .data = &test_data.int_0002,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "int_0003",
+ .data = &test_data.int_0003,
+ .maxlen = sizeof(test_data.int_0003),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "match_int",
+ .data = &match_int_ok,
+ .maxlen = sizeof(match_int_ok),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "boot_int",
+ .data = &test_data.boot_int,
+ .maxlen = sizeof(test_data.boot_int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_ONE,
+ },
+ {
+ .procname = "uint_0001",
+ .data = &test_data.uint_0001,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = proc_douintvec,
+ },
+ {
+ .procname = "string_0001",
+ .data = &test_data.string_0001,
+ .maxlen = sizeof(test_data.string_0001),
+ .mode = 0644,
+ .proc_handler = proc_dostring,
+ },
+ {
+ .procname = "bitmap_0001",
+ .data = &test_data.bitmap_0001,
+ .maxlen = SYSCTL_TEST_BITMAP_SIZE,
+ .mode = 0644,
+ .proc_handler = proc_do_large_bitmap,
+ },
+};
+
+static void test_sysctl_calc_match_int_ok(void)
+{
+ int i;
+
+ struct {
+ int defined;
+ int wanted;
+ } match_int[] = {
+ {.defined = *(int *)SYSCTL_ZERO, .wanted = 0},
+ {.defined = *(int *)SYSCTL_ONE, .wanted = 1},
+ {.defined = *(int *)SYSCTL_TWO, .wanted = 2},
+ {.defined = *(int *)SYSCTL_THREE, .wanted = 3},
+ {.defined = *(int *)SYSCTL_FOUR, .wanted = 4},
+ {.defined = *(int *)SYSCTL_ONE_HUNDRED, .wanted = 100},
+ {.defined = *(int *)SYSCTL_TWO_HUNDRED, .wanted = 200},
+ {.defined = *(int *)SYSCTL_ONE_THOUSAND, .wanted = 1000},
+ {.defined = *(int *)SYSCTL_THREE_THOUSAND, .wanted = 3000},
+ {.defined = *(int *)SYSCTL_INT_MAX, .wanted = INT_MAX},
+ {.defined = *(int *)SYSCTL_MAXOLDUID, .wanted = 65535},
+ {.defined = *(int *)SYSCTL_NEG_ONE, .wanted = -1},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(match_int); i++)
+ if (match_int[i].defined != match_int[i].wanted)
+ match_int_ok = 0;
+}
+
+static int test_sysctl_setup_node_tests(void)
+{
+ test_sysctl_calc_match_int_ok();
+ test_data.bitmap_0001 = kzalloc(SYSCTL_TEST_BITMAP_SIZE/8, GFP_KERNEL);
+ if (!test_data.bitmap_0001)
+ return -ENOMEM;
+ ctl_headers[TEST_H_SETUP_NODE] = register_sysctl("debug/test_sysctl", test_table);
+ if (!ctl_headers[TEST_H_SETUP_NODE]) {
+ kfree(test_data.bitmap_0001);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Used to test that unregister actually removes the directory */
+static const struct ctl_table test_table_unregister[] = {
+ {
+ .procname = "unregister_error",
+ .data = &test_data.int_0001,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ },
+};
+
+static int test_sysctl_run_unregister_nested(void)
+{
+ struct ctl_table_header *unregister;
+
+ unregister = register_sysctl("debug/test_sysctl/unregister_error",
+ test_table_unregister);
+ if (!unregister)
+ return -ENOMEM;
+
+ unregister_sysctl_table(unregister);
+ return 0;
+}
+
+static int test_sysctl_run_register_mount_point(void)
+{
+ ctl_headers[TEST_H_MNT]
+ = register_sysctl_mount_point("debug/test_sysctl/mnt");
+ if (!ctl_headers[TEST_H_MNT])
+ return -ENOMEM;
+
+ ctl_headers[TEST_H_MNTERROR]
+ = register_sysctl("debug/test_sysctl/mnt/mnt_error",
+ test_table_unregister);
+ /*
+ * Don't check the result.:
+ * If it fails (expected behavior), return 0.
+ * If successful (missbehavior of register mount point), we want to see
+ * mnt_error when we run the sysctl test script
+ */
+
+ return 0;
+}
+
+static const struct ctl_table test_table_empty[] = { };
+
+static int test_sysctl_run_register_empty(void)
+{
+ /* Tets that an empty dir can be created */
+ ctl_headers[TEST_H_EMPTY_ADD]
+ = register_sysctl("debug/test_sysctl/empty_add", test_table_empty);
+ if (!ctl_headers[TEST_H_EMPTY_ADD])
+ return -ENOMEM;
+
+ /* Test that register on top of an empty dir works */
+ ctl_headers[TEST_H_EMPTY]
+ = register_sysctl("debug/test_sysctl/empty_add/empty", test_table_empty);
+ if (!ctl_headers[TEST_H_EMPTY])
+ return -ENOMEM;
+
+ return 0;
+}
+
+static const struct ctl_table table_u8_over[] = {
+ {
+ .procname = "u8_over",
+ .data = &test_data.uint_0001,
+ .maxlen = sizeof(u8),
+ .mode = 0644,
+ .proc_handler = proc_dou8vec_minmax,
+ .extra1 = SYSCTL_FOUR,
+ .extra2 = SYSCTL_ONE_THOUSAND,
+ },
+};
+
+static const struct ctl_table table_u8_under[] = {
+ {
+ .procname = "u8_under",
+ .data = &test_data.uint_0001,
+ .maxlen = sizeof(u8),
+ .mode = 0644,
+ .proc_handler = proc_dou8vec_minmax,
+ .extra1 = SYSCTL_NEG_ONE,
+ .extra2 = SYSCTL_ONE_HUNDRED,
+ },
+};
+
+static const struct ctl_table table_u8_valid[] = {
+ {
+ .procname = "u8_valid",
+ .data = &test_data.uint_0001,
+ .maxlen = sizeof(u8),
+ .mode = 0644,
+ .proc_handler = proc_dou8vec_minmax,
+ .extra1 = SYSCTL_ZERO,
+ .extra2 = SYSCTL_TWO_HUNDRED,
+ },
+};
+
+static int test_sysctl_register_u8_extra(void)
+{
+ /* should fail because it's over */
+ ctl_headers[TEST_H_U8]
+ = register_sysctl("debug/test_sysctl", table_u8_over);
+ if (ctl_headers[TEST_H_U8])
+ return -ENOMEM;
+
+ /* should fail because it's under */
+ ctl_headers[TEST_H_U8]
+ = register_sysctl("debug/test_sysctl", table_u8_under);
+ if (ctl_headers[TEST_H_U8])
+ return -ENOMEM;
+
+ /* should not fail because it's valid */
+ ctl_headers[TEST_H_U8]
+ = register_sysctl("debug/test_sysctl", table_u8_valid);
+ if (!ctl_headers[TEST_H_U8])
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int __init test_sysctl_init(void)
+{
+ int err = 0;
+
+ int (*func_array[])(void) = {
+ test_sysctl_setup_node_tests,
+ test_sysctl_run_unregister_nested,
+ test_sysctl_run_register_mount_point,
+ test_sysctl_run_register_empty,
+ test_sysctl_register_u8_extra
+ };
+
+ for (int i = 0; !err && i < ARRAY_SIZE(func_array); i++)
+ err = func_array[i]();
+
+ return err;
+}
+module_init(test_sysctl_init);
+
+static void __exit test_sysctl_exit(void)
+{
+ kfree(test_data.bitmap_0001);
+ for (int i = 0; i < TEST_H_SIZE; i++) {
+ if (ctl_headers[i])
+ unregister_sysctl_table(ctl_headers[i]);
+ }
+}
+
+module_exit(test_sysctl_exit);
+
+MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>");
+MODULE_DESCRIPTION("proc sysctl test driver");
+MODULE_LICENSE("GPL");