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