brintos

brintos / linux-shallow public Read only

0
0
Text · 6.8 KiB · b6696fa Raw
285 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.12/*3 * proc sysctl test driver4 *5 * Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>6 */7 8/*9 * This module provides an interface to the proc sysctl interfaces.  This10 * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the11 * system unless explicitly requested by name. You can also build this driver12 * into your kernel.13 */14 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt16 17#include <linux/init.h>18#include <linux/list.h>19#include <linux/module.h>20#include <linux/printk.h>21#include <linux/fs.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>28 29static int i_zero;30static int i_one_hundred = 100;31static int match_int_ok = 1;32 33 34static struct {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	struct ctl_table_header *empty_add;39	struct ctl_table_header *empty;40} sysctl_test_headers;41 42struct test_sysctl_data {43	int int_0001;44	int int_0002;45	int int_0003[4];46 47	int boot_int;48 49	unsigned int uint_0001;50 51	char string_0001[65];52 53#define SYSCTL_TEST_BITMAP_SIZE	6553654	unsigned long *bitmap_0001;55};56 57static struct test_sysctl_data test_data = {58	.int_0001 = 60,59	.int_0002 = 1,60 61	.int_0003[0] = 0,62	.int_0003[1] = 1,63	.int_0003[2] = 2,64	.int_0003[3] = 3,65 66	.boot_int = 0,67 68	.uint_0001 = 314,69 70	.string_0001 = "(none)",71};72 73/* These are all under /proc/sys/debug/test_sysctl/ */74static struct ctl_table test_table[] = {75	{76		.procname	= "int_0001",77		.data		= &test_data.int_0001,78		.maxlen		= sizeof(int),79		.mode		= 0644,80		.proc_handler	= proc_dointvec_minmax,81		.extra1		= &i_zero,82		.extra2         = &i_one_hundred,83	},84	{85		.procname	= "int_0002",86		.data		= &test_data.int_0002,87		.maxlen		= sizeof(int),88		.mode		= 0644,89		.proc_handler	= proc_dointvec,90	},91	{92		.procname	= "int_0003",93		.data		= &test_data.int_0003,94		.maxlen		= sizeof(test_data.int_0003),95		.mode		= 0644,96		.proc_handler	= proc_dointvec,97	},98	{99		.procname	= "match_int",100		.data		= &match_int_ok,101		.maxlen		= sizeof(match_int_ok),102		.mode		= 0444,103		.proc_handler	= proc_dointvec,104	},105	{106		.procname	= "boot_int",107		.data		= &test_data.boot_int,108		.maxlen		= sizeof(test_data.boot_int),109		.mode		= 0644,110		.proc_handler	= proc_dointvec,111		.extra1		= SYSCTL_ZERO,112		.extra2         = SYSCTL_ONE,113	},114	{115		.procname	= "uint_0001",116		.data		= &test_data.uint_0001,117		.maxlen		= sizeof(unsigned int),118		.mode		= 0644,119		.proc_handler	= proc_douintvec,120	},121	{122		.procname	= "string_0001",123		.data		= &test_data.string_0001,124		.maxlen		= sizeof(test_data.string_0001),125		.mode		= 0644,126		.proc_handler	= proc_dostring,127	},128	{129		.procname	= "bitmap_0001",130		.data		= &test_data.bitmap_0001,131		.maxlen		= SYSCTL_TEST_BITMAP_SIZE,132		.mode		= 0644,133		.proc_handler	= proc_do_large_bitmap,134	},135};136 137static void test_sysctl_calc_match_int_ok(void)138{139	int i;140 141	struct {142		int defined;143		int wanted;144	} match_int[] = {145		{.defined = *(int *)SYSCTL_ZERO,	.wanted = 0},146		{.defined = *(int *)SYSCTL_ONE,		.wanted = 1},147		{.defined = *(int *)SYSCTL_TWO,		.wanted = 2},148		{.defined = *(int *)SYSCTL_THREE,	.wanted = 3},149		{.defined = *(int *)SYSCTL_FOUR,	.wanted = 4},150		{.defined = *(int *)SYSCTL_ONE_HUNDRED, .wanted = 100},151		{.defined = *(int *)SYSCTL_TWO_HUNDRED,	.wanted = 200},152		{.defined = *(int *)SYSCTL_ONE_THOUSAND, .wanted = 1000},153		{.defined = *(int *)SYSCTL_THREE_THOUSAND, .wanted = 3000},154		{.defined = *(int *)SYSCTL_INT_MAX,	.wanted = INT_MAX},155		{.defined = *(int *)SYSCTL_MAXOLDUID,	.wanted = 65535},156		{.defined = *(int *)SYSCTL_NEG_ONE,	.wanted = -1},157	};158 159	for (i = 0; i < ARRAY_SIZE(match_int); i++)160		if (match_int[i].defined != match_int[i].wanted)161			match_int_ok = 0;162}163 164static int test_sysctl_setup_node_tests(void)165{166	test_sysctl_calc_match_int_ok();167	test_data.bitmap_0001 = kzalloc(SYSCTL_TEST_BITMAP_SIZE/8, GFP_KERNEL);168	if (!test_data.bitmap_0001)169		return -ENOMEM;170	sysctl_test_headers.test_h_setup_node = register_sysctl("debug/test_sysctl", test_table);171	if (!sysctl_test_headers.test_h_setup_node) {172		kfree(test_data.bitmap_0001);173		return -ENOMEM;174	}175 176	return 0;177}178 179/* Used to test that unregister actually removes the directory */180static struct ctl_table test_table_unregister[] = {181	{182		.procname	= "unregister_error",183		.data		= &test_data.int_0001,184		.maxlen		= sizeof(int),185		.mode		= 0644,186		.proc_handler	= proc_dointvec_minmax,187	},188};189 190static int test_sysctl_run_unregister_nested(void)191{192	struct ctl_table_header *unregister;193 194	unregister = register_sysctl("debug/test_sysctl/unregister_error",195				   test_table_unregister);196	if (!unregister)197		return -ENOMEM;198 199	unregister_sysctl_table(unregister);200	return 0;201}202 203static int test_sysctl_run_register_mount_point(void)204{205	sysctl_test_headers.test_h_mnt206		= register_sysctl_mount_point("debug/test_sysctl/mnt");207	if (!sysctl_test_headers.test_h_mnt)208		return -ENOMEM;209 210	sysctl_test_headers.test_h_mnterror211		= register_sysctl("debug/test_sysctl/mnt/mnt_error",212				  test_table_unregister);213	/*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 see217	 * mnt_error when we run the sysctl test script218	 */219 220	return 0;221}222 223static struct ctl_table test_table_empty[] = { };224 225static int test_sysctl_run_register_empty(void)226{227	/* Tets that an empty dir can be created */228	sysctl_test_headers.empty_add229		= register_sysctl("debug/test_sysctl/empty_add", test_table_empty);230	if (!sysctl_test_headers.empty_add)231		return -ENOMEM;232 233	/* Test that register on top of an empty dir works */234	sysctl_test_headers.empty235		= register_sysctl("debug/test_sysctl/empty_add/empty", test_table_empty);236	if (!sysctl_test_headers.empty)237		return -ENOMEM;238 239	return 0;240}241 242static int __init test_sysctl_init(void)243{244	int err;245 246	err = test_sysctl_setup_node_tests();247	if (err)248		goto out;249 250	err = test_sysctl_run_unregister_nested();251	if (err)252		goto out;253 254	err = test_sysctl_run_register_mount_point();255	if (err)256		goto out;257 258	err = test_sysctl_run_register_empty();259 260out:261	return err;262}263module_init(test_sysctl_init);264 265static void __exit test_sysctl_exit(void)266{267	kfree(test_data.bitmap_0001);268	if (sysctl_test_headers.test_h_setup_node)269		unregister_sysctl_table(sysctl_test_headers.test_h_setup_node);270	if (sysctl_test_headers.test_h_mnt)271		unregister_sysctl_table(sysctl_test_headers.test_h_mnt);272	if (sysctl_test_headers.test_h_mnterror)273		unregister_sysctl_table(sysctl_test_headers.test_h_mnterror);274	if (sysctl_test_headers.empty)275		unregister_sysctl_table(sysctl_test_headers.empty);276	if (sysctl_test_headers.empty_add)277		unregister_sysctl_table(sysctl_test_headers.empty_add);278}279 280module_exit(test_sysctl_exit);281 282MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>");283MODULE_DESCRIPTION("proc sysctl test driver");284MODULE_LICENSE("GPL");285