1 // SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.1
3 * proc sysctl test driver
5 * Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>
9 * This module provides an interface to the proc sysctl interfaces. This
10 * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the
11 * system unless explicitly requested by name. You can also build this driver
15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17 #include <linux/init.h>
18 #include <linux/list.h>
19 #include <linux/module.h>
20 #include <linux/printk.h>
22 #include <linux/miscdevice.h>
23 #include <linux/slab.h>
24 #include <linux/uaccess.h>
25 #include <linux/async.h>
26 #include <linux/delay.h>
27 #include <linux/vmalloc.h>
30 static int i_one_hundred
= 100;
31 static int match_int_ok
= 1;
35 struct ctl_table_header
*test_h_setup_node
;
36 struct ctl_table_header
*test_h_mnt
;
37 struct ctl_table_header
*test_h_mnterror
;
38 } sysctl_test_headers
;
40 struct test_sysctl_data
{
47 unsigned int uint_0001
;
51 #define SYSCTL_TEST_BITMAP_SIZE 65536
52 unsigned long *bitmap_0001
;
55 static struct test_sysctl_data test_data
= {
68 .string_0001
= "(none)",
71 /* These are all under /proc/sys/debug/test_sysctl/ */
72 static struct ctl_table test_table
[] = {
74 .procname
= "int_0001",
75 .data
= &test_data
.int_0001
,
76 .maxlen
= sizeof(int),
78 .proc_handler
= proc_dointvec_minmax
,
80 .extra2
= &i_one_hundred
,
83 .procname
= "int_0002",
84 .data
= &test_data
.int_0002
,
85 .maxlen
= sizeof(int),
87 .proc_handler
= proc_dointvec
,
90 .procname
= "int_0003",
91 .data
= &test_data
.int_0003
,
92 .maxlen
= sizeof(test_data
.int_0003
),
94 .proc_handler
= proc_dointvec
,
97 .procname
= "match_int",
98 .data
= &match_int_ok
,
99 .maxlen
= sizeof(match_int_ok
),
101 .proc_handler
= proc_dointvec
,
104 .procname
= "boot_int",
105 .data
= &test_data
.boot_int
,
106 .maxlen
= sizeof(test_data
.boot_int
),
108 .proc_handler
= proc_dointvec
,
109 .extra1
= SYSCTL_ZERO
,
110 .extra2
= SYSCTL_ONE
,
113 .procname
= "uint_0001",
114 .data
= &test_data
.uint_0001
,
115 .maxlen
= sizeof(unsigned int),
117 .proc_handler
= proc_douintvec
,
120 .procname
= "string_0001",
121 .data
= &test_data
.string_0001
,
122 .maxlen
= sizeof(test_data
.string_0001
),
124 .proc_handler
= proc_dostring
,
127 .procname
= "bitmap_0001",
128 .data
= &test_data
.bitmap_0001
,
129 .maxlen
= SYSCTL_TEST_BITMAP_SIZE
,
131 .proc_handler
= proc_do_large_bitmap
,
136 static void test_sysctl_calc_match_int_ok(void)
144 {.defined
= *(int *)SYSCTL_ZERO
, .wanted
= 0},
145 {.defined
= *(int *)SYSCTL_ONE
, .wanted
= 1},
146 {.defined
= *(int *)SYSCTL_TWO
, .wanted
= 2},
147 {.defined
= *(int *)SYSCTL_THREE
, .wanted
= 3},
148 {.defined
= *(int *)SYSCTL_FOUR
, .wanted
= 4},
149 {.defined
= *(int *)SYSCTL_ONE_HUNDRED
, .wanted
= 100},
150 {.defined
= *(int *)SYSCTL_TWO_HUNDRED
, .wanted
= 200},
151 {.defined
= *(int *)SYSCTL_ONE_THOUSAND
, .wanted
= 1000},
152 {.defined
= *(int *)SYSCTL_THREE_THOUSAND
, .wanted
= 3000},
153 {.defined
= *(int *)SYSCTL_INT_MAX
, .wanted
= INT_MAX
},
154 {.defined
= *(int *)SYSCTL_MAXOLDUID
, .wanted
= 65535},
155 {.defined
= *(int *)SYSCTL_NEG_ONE
, .wanted
= -1},
158 for (i
= 0; i
< ARRAY_SIZE(match_int
); i
++)
159 if (match_int
[i
].defined
!= match_int
[i
].wanted
)
163 static int test_sysctl_setup_node_tests(void)
165 test_sysctl_calc_match_int_ok();
166 test_data
.bitmap_0001
= kzalloc(SYSCTL_TEST_BITMAP_SIZE
/8, GFP_KERNEL
);
167 if (!test_data
.bitmap_0001
)
169 sysctl_test_headers
.test_h_setup_node
= register_sysctl("debug/test_sysctl", test_table
);
170 if (!sysctl_test_headers
.test_h_setup_node
) {
171 kfree(test_data
.bitmap_0001
);
178 /* Used to test that unregister actually removes the directory */
179 static struct ctl_table test_table_unregister
[] = {
181 .procname
= "unregister_error",
182 .data
= &test_data
.int_0001
,
183 .maxlen
= sizeof(int),
185 .proc_handler
= proc_dointvec_minmax
,
190 static int test_sysctl_run_unregister_nested(void)
192 struct ctl_table_header
*unregister
;
194 unregister
= register_sysctl("debug/test_sysctl/unregister_error",
195 test_table_unregister
);
199 unregister_sysctl_table(unregister
);
203 static int test_sysctl_run_register_mount_point(void)
205 sysctl_test_headers
.test_h_mnt
206 = register_sysctl_mount_point("debug/test_sysctl/mnt");
207 if (!sysctl_test_headers
.test_h_mnt
)
210 sysctl_test_headers
.test_h_mnterror
211 = register_sysctl("debug/test_sysctl/mnt/mnt_error",
212 test_table_unregister
);
214 * Don't check the result.:
215 * If it fails (expected behavior), return 0.
216 * If successful (missbehavior of register mount point), we want to see
217 * mnt_error when we run the sysctl test script
223 static int __init
test_sysctl_init(void)
227 err
= test_sysctl_setup_node_tests();
231 err
= test_sysctl_run_unregister_nested();
235 err
= test_sysctl_run_register_mount_point();
240 module_init(test_sysctl_init
);
242 static void __exit
test_sysctl_exit(void)
244 kfree(test_data
.bitmap_0001
);
245 if (sysctl_test_headers
.test_h_setup_node
)
246 unregister_sysctl_table(sysctl_test_headers
.test_h_setup_node
);
247 if (sysctl_test_headers
.test_h_mnt
)
248 unregister_sysctl_table(sysctl_test_headers
.test_h_mnt
);
249 if (sysctl_test_headers
.test_h_mnterror
)
250 unregister_sysctl_table(sysctl_test_headers
.test_h_mnterror
);
253 module_exit(test_sysctl_exit
);
255 MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>");
256 MODULE_LICENSE("GPL");