16cad1ecdSLuis Chamberlain // SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.1
29308f2f9SLuis R. Rodriguez /*
39308f2f9SLuis R. Rodriguez * proc sysctl test driver
49308f2f9SLuis R. Rodriguez *
59308f2f9SLuis R. Rodriguez * Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>
69308f2f9SLuis R. Rodriguez */
79308f2f9SLuis R. Rodriguez
89308f2f9SLuis R. Rodriguez /*
92d046981SRandy Dunlap * This module provides an interface to the proc sysctl interfaces. This
109308f2f9SLuis R. Rodriguez * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the
119308f2f9SLuis R. Rodriguez * system unless explicitly requested by name. You can also build this driver
129308f2f9SLuis R. Rodriguez * into your kernel.
139308f2f9SLuis R. Rodriguez */
149308f2f9SLuis R. Rodriguez
159308f2f9SLuis R. Rodriguez #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
169308f2f9SLuis R. Rodriguez
179308f2f9SLuis R. Rodriguez #include <linux/init.h>
189308f2f9SLuis R. Rodriguez #include <linux/list.h>
199308f2f9SLuis R. Rodriguez #include <linux/module.h>
209308f2f9SLuis R. Rodriguez #include <linux/printk.h>
219308f2f9SLuis R. Rodriguez #include <linux/fs.h>
229308f2f9SLuis R. Rodriguez #include <linux/miscdevice.h>
239308f2f9SLuis R. Rodriguez #include <linux/slab.h>
249308f2f9SLuis R. Rodriguez #include <linux/uaccess.h>
259308f2f9SLuis R. Rodriguez #include <linux/async.h>
269308f2f9SLuis R. Rodriguez #include <linux/delay.h>
279308f2f9SLuis R. Rodriguez #include <linux/vmalloc.h>
289308f2f9SLuis R. Rodriguez
299308f2f9SLuis R. Rodriguez static int i_zero;
309308f2f9SLuis R. Rodriguez static int i_one_hundred = 100;
3157b19468STonghao Zhang static int match_int_ok = 1;
329308f2f9SLuis R. Rodriguez
33*f2e7a626SJoel Granados
34*f2e7a626SJoel Granados static struct {
35*f2e7a626SJoel Granados struct ctl_table_header *test_h_setup_node;
36*f2e7a626SJoel Granados struct ctl_table_header *test_h_mnt;
37*f2e7a626SJoel Granados struct ctl_table_header *test_h_mnterror;
38*f2e7a626SJoel Granados } sysctl_test_headers;
39*f2e7a626SJoel Granados
409308f2f9SLuis R. Rodriguez struct test_sysctl_data {
419308f2f9SLuis R. Rodriguez int int_0001;
42eb965edaSLuis R. Rodriguez int int_0002;
437c43a657SLuis R. Rodriguez int int_0003[4];
44eb965edaSLuis R. Rodriguez
454f2f682dSVlastimil Babka int boot_int;
464f2f682dSVlastimil Babka
472920fad3SLuis R. Rodriguez unsigned int uint_0001;
482920fad3SLuis R. Rodriguez
499308f2f9SLuis R. Rodriguez char string_0001[65];
502ea622b8SEric Sandeen
512ea622b8SEric Sandeen #define SYSCTL_TEST_BITMAP_SIZE 65536
522ea622b8SEric Sandeen unsigned long *bitmap_0001;
539308f2f9SLuis R. Rodriguez };
549308f2f9SLuis R. Rodriguez
559308f2f9SLuis R. Rodriguez static struct test_sysctl_data test_data = {
569308f2f9SLuis R. Rodriguez .int_0001 = 60,
57eb965edaSLuis R. Rodriguez .int_0002 = 1,
58eb965edaSLuis R. Rodriguez
597c43a657SLuis R. Rodriguez .int_0003[0] = 0,
607c43a657SLuis R. Rodriguez .int_0003[1] = 1,
617c43a657SLuis R. Rodriguez .int_0003[2] = 2,
627c43a657SLuis R. Rodriguez .int_0003[3] = 3,
637c43a657SLuis R. Rodriguez
644f2f682dSVlastimil Babka .boot_int = 0,
654f2f682dSVlastimil Babka
662920fad3SLuis R. Rodriguez .uint_0001 = 314,
672920fad3SLuis R. Rodriguez
689308f2f9SLuis R. Rodriguez .string_0001 = "(none)",
699308f2f9SLuis R. Rodriguez };
709308f2f9SLuis R. Rodriguez
719308f2f9SLuis R. Rodriguez /* These are all under /proc/sys/debug/test_sysctl/ */
729308f2f9SLuis R. Rodriguez static struct ctl_table test_table[] = {
739308f2f9SLuis R. Rodriguez {
749308f2f9SLuis R. Rodriguez .procname = "int_0001",
759308f2f9SLuis R. Rodriguez .data = &test_data.int_0001,
769308f2f9SLuis R. Rodriguez .maxlen = sizeof(int),
779308f2f9SLuis R. Rodriguez .mode = 0644,
789308f2f9SLuis R. Rodriguez .proc_handler = proc_dointvec_minmax,
799308f2f9SLuis R. Rodriguez .extra1 = &i_zero,
809308f2f9SLuis R. Rodriguez .extra2 = &i_one_hundred,
819308f2f9SLuis R. Rodriguez },
829308f2f9SLuis R. Rodriguez {
83eb965edaSLuis R. Rodriguez .procname = "int_0002",
84eb965edaSLuis R. Rodriguez .data = &test_data.int_0002,
85eb965edaSLuis R. Rodriguez .maxlen = sizeof(int),
86eb965edaSLuis R. Rodriguez .mode = 0644,
87eb965edaSLuis R. Rodriguez .proc_handler = proc_dointvec,
88eb965edaSLuis R. Rodriguez },
89eb965edaSLuis R. Rodriguez {
907c43a657SLuis R. Rodriguez .procname = "int_0003",
917c43a657SLuis R. Rodriguez .data = &test_data.int_0003,
927c43a657SLuis R. Rodriguez .maxlen = sizeof(test_data.int_0003),
937c43a657SLuis R. Rodriguez .mode = 0644,
947c43a657SLuis R. Rodriguez .proc_handler = proc_dointvec,
957c43a657SLuis R. Rodriguez },
967c43a657SLuis R. Rodriguez {
9757b19468STonghao Zhang .procname = "match_int",
9857b19468STonghao Zhang .data = &match_int_ok,
9957b19468STonghao Zhang .maxlen = sizeof(match_int_ok),
10057b19468STonghao Zhang .mode = 0444,
10157b19468STonghao Zhang .proc_handler = proc_dointvec,
10257b19468STonghao Zhang },
10357b19468STonghao Zhang {
1044f2f682dSVlastimil Babka .procname = "boot_int",
1054f2f682dSVlastimil Babka .data = &test_data.boot_int,
1064f2f682dSVlastimil Babka .maxlen = sizeof(test_data.boot_int),
1074f2f682dSVlastimil Babka .mode = 0644,
1084f2f682dSVlastimil Babka .proc_handler = proc_dointvec,
1094f2f682dSVlastimil Babka .extra1 = SYSCTL_ZERO,
1104f2f682dSVlastimil Babka .extra2 = SYSCTL_ONE,
1114f2f682dSVlastimil Babka },
1124f2f682dSVlastimil Babka {
1132920fad3SLuis R. Rodriguez .procname = "uint_0001",
1142920fad3SLuis R. Rodriguez .data = &test_data.uint_0001,
1152920fad3SLuis R. Rodriguez .maxlen = sizeof(unsigned int),
1162920fad3SLuis R. Rodriguez .mode = 0644,
1172920fad3SLuis R. Rodriguez .proc_handler = proc_douintvec,
1182920fad3SLuis R. Rodriguez },
1192920fad3SLuis R. Rodriguez {
1209308f2f9SLuis R. Rodriguez .procname = "string_0001",
1219308f2f9SLuis R. Rodriguez .data = &test_data.string_0001,
1229308f2f9SLuis R. Rodriguez .maxlen = sizeof(test_data.string_0001),
1239308f2f9SLuis R. Rodriguez .mode = 0644,
1249308f2f9SLuis R. Rodriguez .proc_handler = proc_dostring,
1259308f2f9SLuis R. Rodriguez },
1262ea622b8SEric Sandeen {
1272ea622b8SEric Sandeen .procname = "bitmap_0001",
1282ea622b8SEric Sandeen .data = &test_data.bitmap_0001,
1292ea622b8SEric Sandeen .maxlen = SYSCTL_TEST_BITMAP_SIZE,
1302ea622b8SEric Sandeen .mode = 0644,
1312ea622b8SEric Sandeen .proc_handler = proc_do_large_bitmap,
1322ea622b8SEric Sandeen },
1339308f2f9SLuis R. Rodriguez { }
1349308f2f9SLuis R. Rodriguez };
1359308f2f9SLuis R. Rodriguez
test_sysctl_calc_match_int_ok(void)136e009bd5eSJoel Granados static void test_sysctl_calc_match_int_ok(void)
1379308f2f9SLuis R. Rodriguez {
13857b19468STonghao Zhang int i;
13957b19468STonghao Zhang
14057b19468STonghao Zhang struct {
14157b19468STonghao Zhang int defined;
14257b19468STonghao Zhang int wanted;
14357b19468STonghao Zhang } match_int[] = {
14457b19468STonghao Zhang {.defined = *(int *)SYSCTL_ZERO, .wanted = 0},
14557b19468STonghao Zhang {.defined = *(int *)SYSCTL_ONE, .wanted = 1},
14657b19468STonghao Zhang {.defined = *(int *)SYSCTL_TWO, .wanted = 2},
14757b19468STonghao Zhang {.defined = *(int *)SYSCTL_THREE, .wanted = 3},
14857b19468STonghao Zhang {.defined = *(int *)SYSCTL_FOUR, .wanted = 4},
14957b19468STonghao Zhang {.defined = *(int *)SYSCTL_ONE_HUNDRED, .wanted = 100},
15057b19468STonghao Zhang {.defined = *(int *)SYSCTL_TWO_HUNDRED, .wanted = 200},
15157b19468STonghao Zhang {.defined = *(int *)SYSCTL_ONE_THOUSAND, .wanted = 1000},
15257b19468STonghao Zhang {.defined = *(int *)SYSCTL_THREE_THOUSAND, .wanted = 3000},
15357b19468STonghao Zhang {.defined = *(int *)SYSCTL_INT_MAX, .wanted = INT_MAX},
15457b19468STonghao Zhang {.defined = *(int *)SYSCTL_MAXOLDUID, .wanted = 65535},
15557b19468STonghao Zhang {.defined = *(int *)SYSCTL_NEG_ONE, .wanted = -1},
15657b19468STonghao Zhang };
15757b19468STonghao Zhang
15857b19468STonghao Zhang for (i = 0; i < ARRAY_SIZE(match_int); i++)
15957b19468STonghao Zhang if (match_int[i].defined != match_int[i].wanted)
16057b19468STonghao Zhang match_int_ok = 0;
161e009bd5eSJoel Granados }
16257b19468STonghao Zhang
test_sysctl_setup_node_tests(void)163e009bd5eSJoel Granados static int test_sysctl_setup_node_tests(void)
164e009bd5eSJoel Granados {
165e009bd5eSJoel Granados test_sysctl_calc_match_int_ok();
1662ea622b8SEric Sandeen test_data.bitmap_0001 = kzalloc(SYSCTL_TEST_BITMAP_SIZE/8, GFP_KERNEL);
1672ea622b8SEric Sandeen if (!test_data.bitmap_0001)
1689308f2f9SLuis R. Rodriguez return -ENOMEM;
169*f2e7a626SJoel Granados sysctl_test_headers.test_h_setup_node = register_sysctl("debug/test_sysctl", test_table);
170*f2e7a626SJoel Granados if (!sysctl_test_headers.test_h_setup_node) {
1712ea622b8SEric Sandeen kfree(test_data.bitmap_0001);
1722ea622b8SEric Sandeen return -ENOMEM;
1732ea622b8SEric Sandeen }
174e009bd5eSJoel Granados
1759308f2f9SLuis R. Rodriguez return 0;
1769308f2f9SLuis R. Rodriguez }
177e009bd5eSJoel Granados
17835576438SJoel Granados /* Used to test that unregister actually removes the directory */
17935576438SJoel Granados static struct ctl_table test_table_unregister[] = {
18035576438SJoel Granados {
18135576438SJoel Granados .procname = "unregister_error",
18235576438SJoel Granados .data = &test_data.int_0001,
18335576438SJoel Granados .maxlen = sizeof(int),
18435576438SJoel Granados .mode = 0644,
18535576438SJoel Granados .proc_handler = proc_dointvec_minmax,
18635576438SJoel Granados },
18735576438SJoel Granados {}
18835576438SJoel Granados };
18935576438SJoel Granados
test_sysctl_run_unregister_nested(void)19035576438SJoel Granados static int test_sysctl_run_unregister_nested(void)
19135576438SJoel Granados {
19235576438SJoel Granados struct ctl_table_header *unregister;
19335576438SJoel Granados
19435576438SJoel Granados unregister = register_sysctl("debug/test_sysctl/unregister_error",
19535576438SJoel Granados test_table_unregister);
19635576438SJoel Granados if (!unregister)
19735576438SJoel Granados return -ENOMEM;
19835576438SJoel Granados
19935576438SJoel Granados unregister_sysctl_table(unregister);
20035576438SJoel Granados return 0;
20135576438SJoel Granados }
20235576438SJoel Granados
test_sysctl_run_register_mount_point(void)203*f2e7a626SJoel Granados static int test_sysctl_run_register_mount_point(void)
204*f2e7a626SJoel Granados {
205*f2e7a626SJoel Granados sysctl_test_headers.test_h_mnt
206*f2e7a626SJoel Granados = register_sysctl_mount_point("debug/test_sysctl/mnt");
207*f2e7a626SJoel Granados if (!sysctl_test_headers.test_h_mnt)
208*f2e7a626SJoel Granados return -ENOMEM;
209*f2e7a626SJoel Granados
210*f2e7a626SJoel Granados sysctl_test_headers.test_h_mnterror
211*f2e7a626SJoel Granados = register_sysctl("debug/test_sysctl/mnt/mnt_error",
212*f2e7a626SJoel Granados test_table_unregister);
213*f2e7a626SJoel Granados /*
214*f2e7a626SJoel Granados * Don't check the result.:
215*f2e7a626SJoel Granados * If it fails (expected behavior), return 0.
216*f2e7a626SJoel Granados * If successful (missbehavior of register mount point), we want to see
217*f2e7a626SJoel Granados * mnt_error when we run the sysctl test script
218*f2e7a626SJoel Granados */
219*f2e7a626SJoel Granados
220*f2e7a626SJoel Granados return 0;
221*f2e7a626SJoel Granados }
222*f2e7a626SJoel Granados
test_sysctl_init(void)223e009bd5eSJoel Granados static int __init test_sysctl_init(void)
224e009bd5eSJoel Granados {
225e009bd5eSJoel Granados int err;
226e009bd5eSJoel Granados
227e009bd5eSJoel Granados err = test_sysctl_setup_node_tests();
22835576438SJoel Granados if (err)
22935576438SJoel Granados goto out;
230e009bd5eSJoel Granados
23135576438SJoel Granados err = test_sysctl_run_unregister_nested();
232*f2e7a626SJoel Granados if (err)
233*f2e7a626SJoel Granados goto out;
234*f2e7a626SJoel Granados
235*f2e7a626SJoel Granados err = test_sysctl_run_register_mount_point();
23635576438SJoel Granados
23735576438SJoel Granados out:
238e009bd5eSJoel Granados return err;
239e009bd5eSJoel Granados }
2402f56f845SMasami Hiramatsu module_init(test_sysctl_init);
2419308f2f9SLuis R. Rodriguez
test_sysctl_exit(void)2429308f2f9SLuis R. Rodriguez static void __exit test_sysctl_exit(void)
2439308f2f9SLuis R. Rodriguez {
2442ea622b8SEric Sandeen kfree(test_data.bitmap_0001);
245*f2e7a626SJoel Granados if (sysctl_test_headers.test_h_setup_node)
246*f2e7a626SJoel Granados unregister_sysctl_table(sysctl_test_headers.test_h_setup_node);
247*f2e7a626SJoel Granados if (sysctl_test_headers.test_h_mnt)
248*f2e7a626SJoel Granados unregister_sysctl_table(sysctl_test_headers.test_h_mnt);
249*f2e7a626SJoel Granados if (sysctl_test_headers.test_h_mnterror)
250*f2e7a626SJoel Granados unregister_sysctl_table(sysctl_test_headers.test_h_mnterror);
2519308f2f9SLuis R. Rodriguez }
2529308f2f9SLuis R. Rodriguez
2539308f2f9SLuis R. Rodriguez module_exit(test_sysctl_exit);
2549308f2f9SLuis R. Rodriguez
2559308f2f9SLuis R. Rodriguez MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>");
2569308f2f9SLuis R. Rodriguez MODULE_LICENSE("GPL");
257