xref: /aosp_15_r20/external/ltp/testcases/kernel/device-drivers/block/block_dev_kernel/ltp_block_dev.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
4  *
5  * Only those functions are tested here which are declared in <linux/fs.h>
6  *
7  * Changes:
8  * 16 Jan 2009  0.2  Added "tc" parameter to run test cases separately
9  * 11 Jan 2009  0.1  First release
10  */
11 
12 #include <linux/module.h>
13 #include <linux/device.h>
14 #include <linux/fs.h>
15 #include <linux/genhd.h>
16 #include <linux/blkdev.h>
17 
18 MODULE_AUTHOR("Márton Németh <[email protected]>");
19 MODULE_AUTHOR("Copyright (c) 2013 Oracle and/or its affiliates");
20 MODULE_DESCRIPTION("Test block drivers");
21 MODULE_LICENSE("GPL");
22 
23 #define BLK_DEV_NAME		"ltp_block_dev"
24 #define MAX_MAJOR		255
25 
26 #define prk_err(fmt, ...) \
27 	pr_err(BLK_DEV_NAME ": " fmt, ##__VA_ARGS__)
28 #define prk_info(fmt, ...) \
29 	pr_info(BLK_DEV_NAME ": " fmt, ##__VA_ARGS__)
30 #define prk_debug(fmt, ...) \
31 	pr_debug(BLK_DEV_NAME ": " fmt, ##__VA_ARGS__)
32 
33 /*
34  * Analysis of "int register_blkdev(unsigned int major, const char *name)"
35  *
36  * Equivalence classes:
37  *
38  *  Parameter  | Values                   | Valid?  | Covered in
39  *  -----------+--------------------------+---------+-------------
40  *  major      | [0]                      | valid   | tc01, tc02
41  *             |--------------------------+---------+-------------
42  *             | [1..255]                 | valid   | tc03
43  *             |--------------------------+---------+-------------
44  *             | [256..511]               | valid   | tc04
45  *             | [512..UINT_MAX]          | invalid | tc05
46  *  -----------+--------------------------+---------+-------------
47  *  name       | [valid pointer to a zero |         |
48  *             |  terminated string]      | valid   | tc01, tc02
49  *             |--------------------------+---------+-------------
50  *             | [valid pointer to a zero |         |
51  *             |  length zero terminated  | valid   | tc06
52  *             |  string]                 |         |
53  *             |--------------------------+---------+-------------
54  *             | [NULL]                   | invalid | tc08, tc09
55  *  -----------+--------------------------+---------+-------------
56  *
57  */
58 
59 #define result_str(pass) ((pass == 0) ? ("FAIL") : ("PASS"))
60 
61 /*
62  * bit mask for each test-case,
63  * if test is passed, bit will be set to 1
64  */
65 static int test_result;
66 
device_release(struct device * dev)67 static void device_release(struct device *dev)
68 {
69 	prk_info("device released\n");
70 }
71 
72 static struct device tdev = {
73 	.init_name	= BLK_DEV_NAME,
74 	.release	= device_release,
75 };
76 
tc01(void)77 static int tc01(void)
78 {
79 	int major1, major2;
80 	int pass = 1;
81 
82 	prk_info("Test Case 1: register_blkdev() with auto allocating "
83 		"major numbers (major=0)\n");
84 
85 	major1 = register_blkdev(0, BLK_DEV_NAME);
86 	prk_debug("major1 = %i\n", major1);
87 
88 	major2 = register_blkdev(0, BLK_DEV_NAME);
89 	prk_debug("major2 = %i\n", major2);
90 
91 	if (major1 >= 0) {
92 		unregister_blkdev(major1, BLK_DEV_NAME);
93 	} else {
94 		pass = 0;
95 		prk_debug("1st call to register_blkdev() failed, error %i\n",
96 			major1);
97 	}
98 
99 	if (major2 >= 0) {
100 		unregister_blkdev(major2, BLK_DEV_NAME);
101 	} else {
102 		pass = 0;
103 		prk_debug("2nd call to register_blkdev() failed, error %i\n",
104 			major2);
105 	}
106 
107 	prk_info("Test Case Result: %s\n", result_str(pass));
108 	return pass;
109 }
110 
tc02(void)111 static int tc02(void)
112 {
113 	int major[MAX_MAJOR + 1];
114 	int i, pass = 2;
115 
116 	/* Try to allocate block devices until all major numbers are used.
117 	 * After this register_blkdev() should return -EBUSY
118 	 */
119 
120 	prk_info("Test Case 2: stress test of register_blkdev() "
121 		"with auto allocating major numbers (major=0)\n");
122 
123 	memset(major, 0, sizeof(major));
124 
125 	for (i = 0; i < sizeof(major) / sizeof(*major); ++i) {
126 		major[i] = register_blkdev(0, BLK_DEV_NAME);
127 		prk_debug("major[%i] = %i\n", i, major[i]);
128 
129 		if (major[i] == -EBUSY) {
130 			prk_info("device is busy, register_blkdev() ret %i\n",
131 				major[i]);
132 		} else if (major[i] < 0) {
133 			prk_debug("register_blkdev() failed with error %i\n",
134 				major[i]);
135 			pass = 0;
136 		}
137 	}
138 
139 	for (i = 0; i < sizeof(major) / sizeof(*major); ++i) {
140 		if (major[i] >= 0)
141 			unregister_blkdev(major[i], BLK_DEV_NAME);
142 	}
143 
144 	prk_info("Test Case Result: %s\n", result_str(pass));
145 	return pass;
146 }
147 
tc03(void)148 static int tc03(void)
149 {
150 	int major, major2, major3;
151 	int pass = 4;
152 
153 	prk_info("Test Case 3: register_blkdev() with major != 0\n");
154 
155 	/* autosearch for a free major number */
156 	major = register_blkdev(0, BLK_DEV_NAME);
157 	prk_debug("major = %i\n", major);
158 
159 	if (major > 0) {
160 		unregister_blkdev(major, BLK_DEV_NAME);
161 
162 		/* expected to return 0 */
163 		major2 = register_blkdev(major, BLK_DEV_NAME);
164 
165 		/* this call has to fail with EBUSY return value */
166 		major3 = register_blkdev(major, BLK_DEV_NAME);
167 
168 		if (major2 == 0) {
169 			unregister_blkdev(major, BLK_DEV_NAME);
170 		} else {
171 			pass = 0;
172 			prk_debug("1st call to register_blkdev() with major=%i "
173 				"failed with error %i\n", major, major2);
174 		}
175 
176 		if (major3 == 0) {
177 			unregister_blkdev(major, BLK_DEV_NAME);
178 			pass = 0;
179 		} else {
180 			if (major3 != -EBUSY)
181 				pass = 0;
182 			prk_debug("2nd call to register_blkdev() with major=%i "
183 				"failed with error %i\n", major, major3);
184 		}
185 
186 	} else {
187 		pass = 0;
188 		prk_debug("register_blkdev() failed with error %i\n", major);
189 	}
190 
191 	prk_info("Test Case Result: %s\n", result_str(pass));
192 	return pass;
193 }
194 
tc04(void)195 static int tc04(void)
196 {
197 	int major, pass = 8;
198 	unsigned int i, test_major[2] = {256, 511};
199 
200 	prk_info("Test Case 4: register_blkdev() with major=%u/%u\n",
201 		 test_major[0], test_major[1]);
202 
203 	for (i = 0; i < sizeof(test_major) / sizeof(unsigned int); i++) {
204 		major = register_blkdev(test_major[i], BLK_DEV_NAME);
205 		prk_debug("major = %i\n", major);
206 
207 		if (major == 0) {
208 			unregister_blkdev(test_major[i], BLK_DEV_NAME);
209 		} else if (major == -EBUSY) {
210 			prk_debug("device was busy, register_blkdev() with major %u skipped\n",
211 				  test_major[i]);
212 		} else {
213 			pass = 0;
214 			prk_debug("register_blkdev() with major %u got error %i\n",
215 				  test_major[i], major);
216 		}
217 	}
218 
219 	prk_info("Test Case Result: %s\n", result_str(pass));
220 	return pass;
221 }
222 
tc05(void)223 static int tc05(void)
224 {
225 	int major, pass = 16;
226 	unsigned int i, test_major[2] = {512, UINT_MAX};
227 
228 	prk_info("Test Case 5: register_blkdev() with major=%u/%u\n",
229 		 test_major[0], test_major[1]);
230 
231 	for (i = 0; i < sizeof(test_major) / sizeof(unsigned int); i++) {
232 		major = register_blkdev(test_major[i], BLK_DEV_NAME);
233 		prk_debug("major = %i\n", major);
234 
235 		if (major == 0) {
236 			unregister_blkdev(test_major[i], BLK_DEV_NAME);
237 #ifdef BLKDEV_MAJOR_MAX
238 			pass = 0;
239 #endif
240 		} else {
241 			prk_debug("register_blkdev() with major %u got error %i\n",
242 				  test_major[i], major);
243 #ifndef BLKDEV_MAJOR_MAX
244 			pass = 0;
245 #endif
246 		}
247 	}
248 
249 	prk_info("Test Case Result: %s\n", result_str(pass));
250 	return pass;
251 }
252 
tc06(void)253 static int tc06(void)
254 {
255 	int major, pass = 32;
256 
257 	prk_info("Test Case 6: register_blkdev() with name=\"\"\n");
258 
259 	major = register_blkdev(0, "");
260 	prk_debug("major = %i\n", major);
261 
262 	if (major >= 0) {
263 		unregister_blkdev(major, "");
264 	} else {
265 		pass = 0;
266 		prk_debug("register_blkdev() failed with error %i\n", major);
267 	}
268 
269 	prk_info("Test Case Result: %s\n", result_str(pass));
270 	return pass;
271 }
272 
tc07(void)273 static int tc07(void)
274 {
275 	int major, pass = 64;
276 
277 	prk_info("Test Case 7: unregister_blkdev() with major=0\n");
278 
279 	major = register_blkdev(0, BLK_DEV_NAME);
280 	prk_debug("major = %i\n", major);
281 
282 	if (major >= 0) {
283 		prk_debug("calling unregister_blkdev() with major=0\n");
284 		unregister_blkdev(0, BLK_DEV_NAME);
285 		prk_debug("calling unregister_blkdev() with major=%i\n", major);
286 		unregister_blkdev(major, BLK_DEV_NAME);
287 	} else {
288 		pass = 0;
289 		prk_debug("register_blkdev() failed with error %i\n", major);
290 	}
291 
292 	prk_info("Test Case Result: %s\n", result_str(pass));
293 	return pass;
294 }
295 
tc08(void)296 static int tc08(void)
297 {
298 	int major, pass = 128;
299 
300 	prk_info("Test Case 8: register_blkdev() with name=NULL\n");
301 
302 	/* should fail with -EINVAL */
303 	major = register_blkdev(0, NULL);
304 	prk_debug("major = %i\n", major);
305 
306 	if (major >= 0) {
307 		unregister_blkdev(major, NULL);
308 		pass = 0;
309 	} else {
310 		prk_debug("register_blkdev() failed with error %i\n", major);
311 	}
312 
313 	prk_info("Test Case Result: %s\n", result_str(pass));
314 	return pass;
315 }
316 
tc09(void)317 static int tc09(void)
318 {
319 	int major, pass = 256;
320 
321 	prk_info("Test Case 9: unregister_blkdev() with name=NULL\n");
322 
323 	major = register_blkdev(0, BLK_DEV_NAME);
324 	prk_debug("major = %i\n", major);
325 
326 	if (major >= 0) {
327 		/* kernel should silently ignore this */
328 		unregister_blkdev(major, NULL);
329 		unregister_blkdev(major, BLK_DEV_NAME);
330 	} else {
331 		pass = 0;
332 		prk_debug("register_blkdev() failed with error %i\n", major);
333 	}
334 
335 	prk_info("Test Case Result: %s\n", result_str(pass));
336 	return pass;
337 }
338 
339 /* print test result to sysfs file */
sys_result(struct device * dev,struct device_attribute * attr,char * buf)340 static ssize_t sys_result(struct device *dev,
341 	struct device_attribute *attr, char *buf)
342 {
343 	return scnprintf(buf, PAGE_SIZE, "%d\n", test_result);
344 }
345 static DEVICE_ATTR(result, S_IRUSR, sys_result, NULL);
346 
347 /*
348  * get test-case number and run it
349  */
sys_tcase(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)350 static ssize_t sys_tcase(struct device *dev,
351 	struct device_attribute *attr,  const char *buf, size_t count)
352 {
353 	int tc = 0;
354 	sscanf(buf, "%d", &tc);
355 	if (tc < 0 || tc > 9) {
356 		prk_err(": Unexpected test-case number '%d'", tc);
357 		return count;
358 	}
359 
360 	test_result = 0;
361 
362 	if (tc == 0 || tc == 1)
363 		test_result |= tc01();
364 
365 	if (tc == 0 || tc == 2)
366 		test_result |= tc02();
367 
368 	if (tc == 0 || tc == 3)
369 		test_result |= tc03();
370 
371 	if (tc == 0 || tc == 4)
372 		test_result |= tc04();
373 
374 	if (tc == 0 || tc == 5)
375 		test_result |= tc05();
376 
377 	if (tc == 0 || tc == 6)
378 		test_result |= tc06();
379 
380 	if (tc == 0 || tc == 7)
381 		test_result |= tc07();
382 
383 	if (tc == 0 || tc == 8)
384 		test_result |= tc08();
385 
386 	if (tc == 0 || tc == 9)
387 		test_result |= tc09();
388 
389 	return count;
390 }
391 static DEVICE_ATTR(tcase, S_IWUSR, NULL, sys_tcase);
392 
test_init_module(void)393 static int test_init_module(void)
394 {
395 	int err = 0;
396 	prk_info("Starting module\n");
397 
398 	err = device_register(&tdev);
399 	if (err) {
400 		prk_err("Unable to register device\n");
401 		goto err0;
402 	}
403 	prk_info("device registered\n");
404 
405 	err = device_create_file(&tdev, &dev_attr_result);
406 	if (err) {
407 		prk_err("Can't create sysfs file 'result'\n");
408 		goto err1;
409 	}
410 
411 	err = device_create_file(&tdev, &dev_attr_tcase);
412 	if (err) {
413 		prk_err(": Can't create sysfs file 'tc'\n");
414 		goto err2;
415 	}
416 
417 	return 0;
418 
419 err2:
420 	device_remove_file(&tdev, &dev_attr_result);
421 err1:
422 	device_unregister(&tdev);
423 err0:
424 	return err;
425 }
426 module_init(test_init_module);
427 
test_exit_module(void)428 static void test_exit_module(void)
429 {
430 	prk_debug("Unloading module\n");
431 	device_remove_file(&tdev, &dev_attr_result);
432 	device_remove_file(&tdev, &dev_attr_tcase);
433 	device_unregister(&tdev);
434 }
435 module_exit(test_exit_module);
436