xref: /openbmc/linux/lib/test_sysctl.c (revision f2e7a626)
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