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