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