xref: /linux/drivers/char/misc_minor_kunit.c (revision 63740349eba78f242bcbf60d5244d7f2b2600853)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <kunit/test.h>
3 #include <kunit/test-bug.h>
4 #include <linux/module.h>
5 #include <linux/miscdevice.h>
6 #include <linux/fs.h>
7 #include <linux/file.h>
8 #include <linux/init_syscalls.h>
9 
10 /* static minor (LCD_MINOR) */
11 static struct miscdevice dev_static_minor = {
12 	.minor  = LCD_MINOR,
13 	.name   = "dev_static_minor",
14 };
15 
16 /* misc dynamic minor */
17 static struct miscdevice dev_misc_dynamic_minor = {
18 	.minor  = MISC_DYNAMIC_MINOR,
19 	.name   = "dev_misc_dynamic_minor",
20 };
21 
22 static void kunit_static_minor(struct kunit *test)
23 {
24 	int ret;
25 
26 	ret = misc_register(&dev_static_minor);
27 	KUNIT_EXPECT_EQ(test, 0, ret);
28 	KUNIT_EXPECT_EQ(test, LCD_MINOR, dev_static_minor.minor);
29 	misc_deregister(&dev_static_minor);
30 }
31 
32 static void kunit_misc_dynamic_minor(struct kunit *test)
33 {
34 	int ret;
35 
36 	ret = misc_register(&dev_misc_dynamic_minor);
37 	KUNIT_EXPECT_EQ(test, 0, ret);
38 	misc_deregister(&dev_misc_dynamic_minor);
39 }
40 
41 struct miscdev_test_case {
42 	const char *str;
43 	int minor;
44 };
45 
46 static struct miscdev_test_case miscdev_test_ranges[] = {
47 	{
48 		.str = "lower static range, top",
49 		.minor = 15,
50 	},
51 	{
52 		.str = "upper static range, bottom",
53 		.minor = 130,
54 	},
55 	{
56 		.str = "lower static range, bottom",
57 		.minor = 0,
58 	},
59 	{
60 		.str = "upper static range, top",
61 		.minor = MISC_DYNAMIC_MINOR - 1,
62 	},
63 };
64 
65 KUNIT_ARRAY_PARAM_DESC(miscdev, miscdev_test_ranges, str);
66 
67 static int miscdev_find_minors(struct kunit_suite *suite)
68 {
69 	int ret;
70 	struct miscdevice miscstat = {
71 		.name = "miscstat",
72 	};
73 	int i;
74 
75 	for (i = 15; i >= 0; i--) {
76 		miscstat.minor = i;
77 		ret = misc_register(&miscstat);
78 		if (ret == 0)
79 			break;
80 	}
81 
82 	if (ret == 0) {
83 		kunit_info(suite, "found misc device minor %d available\n",
84 				miscstat.minor);
85 		miscdev_test_ranges[0].minor = miscstat.minor;
86 		misc_deregister(&miscstat);
87 	} else {
88 		return ret;
89 	}
90 
91 	for (i = 128; i < MISC_DYNAMIC_MINOR; i++) {
92 		miscstat.minor = i;
93 		ret = misc_register(&miscstat);
94 		if (ret == 0)
95 			break;
96 	}
97 
98 	if (ret == 0) {
99 		kunit_info(suite, "found misc device minor %d available\n",
100 				miscstat.minor);
101 		miscdev_test_ranges[1].minor = miscstat.minor;
102 		misc_deregister(&miscstat);
103 	} else {
104 		return ret;
105 	}
106 
107 	for (i = 0; i < miscdev_test_ranges[0].minor; i++) {
108 		miscstat.minor = i;
109 		ret = misc_register(&miscstat);
110 		if (ret == 0)
111 			break;
112 	}
113 
114 	if (ret == 0) {
115 		kunit_info(suite, "found misc device minor %d available\n",
116 			miscstat.minor);
117 		miscdev_test_ranges[2].minor = miscstat.minor;
118 		misc_deregister(&miscstat);
119 	} else {
120 		return ret;
121 	}
122 
123 	for (i = MISC_DYNAMIC_MINOR - 1; i > miscdev_test_ranges[1].minor; i--) {
124 		miscstat.minor = i;
125 		ret = misc_register(&miscstat);
126 		if (ret == 0)
127 			break;
128 	}
129 
130 	if (ret == 0) {
131 		kunit_info(suite, "found misc device minor %d available\n",
132 			miscstat.minor);
133 		miscdev_test_ranges[3].minor = miscstat.minor;
134 		misc_deregister(&miscstat);
135 	}
136 
137 	return ret;
138 }
139 
140 static bool is_valid_dynamic_minor(int minor)
141 {
142 	if (minor < 0)
143 		return false;
144 	return minor > MISC_DYNAMIC_MINOR;
145 }
146 
147 static int miscdev_test_open(struct inode *inode, struct file *file)
148 {
149 	return 0;
150 }
151 
152 static const struct file_operations miscdev_test_fops = {
153 	.open	= miscdev_test_open,
154 };
155 
156 static void __init miscdev_test_can_open(struct kunit *test, struct miscdevice *misc)
157 {
158 	int ret;
159 	struct file *filp;
160 	char *devname;
161 
162 	devname = kasprintf(GFP_KERNEL, "/dev/%s", misc->name);
163 	ret = init_mknod(devname, S_IFCHR | 0600,
164 			 new_encode_dev(MKDEV(MISC_MAJOR, misc->minor)));
165 	if (ret != 0)
166 		KUNIT_FAIL(test, "failed to create node\n");
167 
168 	filp = filp_open(devname, O_RDONLY, 0);
169 	if (IS_ERR_OR_NULL(filp))
170 		KUNIT_FAIL(test, "failed to open misc device: %ld\n", PTR_ERR(filp));
171 	else
172 		fput(filp);
173 
174 	init_unlink(devname);
175 	kfree(devname);
176 }
177 
178 static void __init miscdev_test_static_basic(struct kunit *test)
179 {
180 	struct miscdevice misc_test = {
181 		.name = "misc_test",
182 		.fops = &miscdev_test_fops,
183 	};
184 	int ret;
185 	const struct miscdev_test_case *params = test->param_value;
186 
187 	misc_test.minor = params->minor;
188 
189 	ret = misc_register(&misc_test);
190 	KUNIT_EXPECT_EQ(test, ret, 0);
191 	KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor);
192 
193 	if (ret == 0) {
194 		miscdev_test_can_open(test, &misc_test);
195 		misc_deregister(&misc_test);
196 	}
197 }
198 
199 static void __init miscdev_test_dynamic_basic(struct kunit *test)
200 {
201 	struct miscdevice misc_test = {
202 		.minor = MISC_DYNAMIC_MINOR,
203 		.name = "misc_test",
204 		.fops = &miscdev_test_fops,
205 	};
206 	int ret;
207 
208 	ret = misc_register(&misc_test);
209 	KUNIT_EXPECT_EQ(test, ret, 0);
210 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc_test.minor));
211 
212 	if (ret == 0) {
213 		miscdev_test_can_open(test, &misc_test);
214 		misc_deregister(&misc_test);
215 	}
216 }
217 
218 static void miscdev_test_twice(struct kunit *test)
219 {
220 	struct miscdevice misc_test = {
221 		.name = "misc_test",
222 		.fops = &miscdev_test_fops,
223 	};
224 	int ret;
225 	const struct miscdev_test_case *params = test->param_value;
226 
227 	misc_test.minor = params->minor;
228 
229 	ret = misc_register(&misc_test);
230 	KUNIT_EXPECT_EQ(test, ret, 0);
231 	KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor);
232 	if (ret == 0)
233 		misc_deregister(&misc_test);
234 
235 	ret = misc_register(&misc_test);
236 	KUNIT_EXPECT_EQ(test, ret, 0);
237 	KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor);
238 	if (ret == 0)
239 		misc_deregister(&misc_test);
240 }
241 
242 static void miscdev_test_duplicate_minor(struct kunit *test)
243 {
244 	struct miscdevice misc1 = {
245 		.name = "misc1",
246 		.fops = &miscdev_test_fops,
247 	};
248 	struct miscdevice misc2 = {
249 		.name = "misc2",
250 		.fops = &miscdev_test_fops,
251 	};
252 	int ret;
253 	const struct miscdev_test_case *params = test->param_value;
254 
255 	misc1.minor = params->minor;
256 	misc2.minor = params->minor;
257 
258 	ret = misc_register(&misc1);
259 	KUNIT_EXPECT_EQ(test, ret, 0);
260 	KUNIT_EXPECT_EQ(test, misc1.minor, params->minor);
261 
262 	ret = misc_register(&misc2);
263 	KUNIT_EXPECT_EQ(test, ret, -EBUSY);
264 	if (ret == 0)
265 		misc_deregister(&misc2);
266 
267 	misc_deregister(&misc1);
268 }
269 
270 static void miscdev_test_duplicate_name(struct kunit *test)
271 {
272 	struct miscdevice misc1 = {
273 		.minor = MISC_DYNAMIC_MINOR,
274 		.name = "misc1",
275 		.fops = &miscdev_test_fops,
276 	};
277 	struct miscdevice misc2 = {
278 		.minor = MISC_DYNAMIC_MINOR,
279 		.name = "misc1",
280 		.fops = &miscdev_test_fops,
281 	};
282 	int ret;
283 
284 	ret = misc_register(&misc1);
285 	KUNIT_EXPECT_EQ(test, ret, 0);
286 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor));
287 
288 	ret = misc_register(&misc2);
289 	KUNIT_EXPECT_EQ(test, ret, -EEXIST);
290 	if (ret == 0)
291 		misc_deregister(&misc2);
292 
293 	misc_deregister(&misc1);
294 }
295 
296 /*
297  * Test that after a duplicate name failure, the reserved minor number is
298  * freed to be allocated next.
299  */
300 static void miscdev_test_duplicate_name_leak(struct kunit *test)
301 {
302 	struct miscdevice misc1 = {
303 		.minor = MISC_DYNAMIC_MINOR,
304 		.name = "misc1",
305 		.fops = &miscdev_test_fops,
306 	};
307 	struct miscdevice misc2 = {
308 		.minor = MISC_DYNAMIC_MINOR,
309 		.name = "misc1",
310 		.fops = &miscdev_test_fops,
311 	};
312 	struct miscdevice misc3 = {
313 		.minor = MISC_DYNAMIC_MINOR,
314 		.name = "misc3",
315 		.fops = &miscdev_test_fops,
316 	};
317 	int ret;
318 	int dyn_minor;
319 
320 	ret = misc_register(&misc1);
321 	KUNIT_EXPECT_EQ(test, ret, 0);
322 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor));
323 
324 	/*
325 	 * Find out what is the next minor number available.
326 	 */
327 	ret = misc_register(&misc3);
328 	KUNIT_EXPECT_EQ(test, ret, 0);
329 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor));
330 	dyn_minor = misc3.minor;
331 	misc_deregister(&misc3);
332 	misc3.minor = MISC_DYNAMIC_MINOR;
333 
334 	ret = misc_register(&misc2);
335 	KUNIT_EXPECT_EQ(test, ret, -EEXIST);
336 	if (ret == 0)
337 		misc_deregister(&misc2);
338 
339 	/*
340 	 * Now check that we can still get the same minor we found before.
341 	 */
342 	ret = misc_register(&misc3);
343 	KUNIT_EXPECT_EQ(test, ret, 0);
344 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor));
345 	KUNIT_EXPECT_EQ(test, misc3.minor, dyn_minor);
346 	misc_deregister(&misc3);
347 
348 	misc_deregister(&misc1);
349 }
350 
351 /*
352  * Try to register a static minor with a duplicate name. That might not
353  * deallocate the minor, preventing it from being used again.
354  */
355 static void miscdev_test_duplicate_error(struct kunit *test)
356 {
357 	struct miscdevice miscdyn = {
358 		.minor = MISC_DYNAMIC_MINOR,
359 		.name = "name1",
360 		.fops = &miscdev_test_fops,
361 	};
362 	struct miscdevice miscstat = {
363 		.name = "name1",
364 		.fops = &miscdev_test_fops,
365 	};
366 	struct miscdevice miscnew = {
367 		.name = "name2",
368 		.fops = &miscdev_test_fops,
369 	};
370 	int ret;
371 	const struct miscdev_test_case *params = test->param_value;
372 
373 	miscstat.minor = params->minor;
374 	miscnew.minor = params->minor;
375 
376 	ret = misc_register(&miscdyn);
377 	KUNIT_EXPECT_EQ(test, ret, 0);
378 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor));
379 
380 	ret = misc_register(&miscstat);
381 	KUNIT_EXPECT_EQ(test, ret, -EEXIST);
382 	if (ret == 0)
383 		misc_deregister(&miscstat);
384 
385 	ret = misc_register(&miscnew);
386 	KUNIT_EXPECT_EQ(test, ret, 0);
387 	KUNIT_EXPECT_EQ(test, miscnew.minor, params->minor);
388 	if (ret == 0)
389 		misc_deregister(&miscnew);
390 
391 	misc_deregister(&miscdyn);
392 }
393 
394 static void __init miscdev_test_dynamic_only_range(struct kunit *test)
395 {
396 	int ret;
397 	struct miscdevice *miscdev;
398 	const int dynamic_minors = 256;
399 	int i;
400 
401 	miscdev = kunit_kmalloc_array(test, dynamic_minors,
402 					sizeof(struct miscdevice),
403 					GFP_KERNEL | __GFP_ZERO);
404 
405 	for (i = 0; i < dynamic_minors; i++) {
406 		miscdev[i].minor = MISC_DYNAMIC_MINOR;
407 		miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i);
408 		miscdev[i].fops = &miscdev_test_fops;
409 		ret = misc_register(&miscdev[i]);
410 		if (ret != 0)
411 			break;
412 		/*
413 		 * This is the bug we are looking for!
414 		 * We asked for a dynamic minor and got a minor in the static range space.
415 		 */
416 		if (miscdev[i].minor >= 0 && miscdev[i].minor <= 15) {
417 			KUNIT_FAIL(test, "misc_register allocated minor %d\n", miscdev[i].minor);
418 			i++;
419 			break;
420 		}
421 		KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor));
422 	}
423 
424 	for (i--; i >= 0; i--) {
425 		miscdev_test_can_open(test, &miscdev[i]);
426 		misc_deregister(&miscdev[i]);
427 		kfree_const(miscdev[i].name);
428 	}
429 
430 	KUNIT_EXPECT_EQ(test, ret, 0);
431 }
432 
433 static void __init miscdev_test_collision(struct kunit *test)
434 {
435 	int ret;
436 	struct miscdevice *miscdev;
437 	struct miscdevice miscstat = {
438 		.name = "miscstat",
439 		.fops = &miscdev_test_fops,
440 	};
441 	const int dynamic_minors = 256;
442 	int i;
443 
444 	miscdev = kunit_kmalloc_array(test, dynamic_minors,
445 					sizeof(struct miscdevice),
446 					GFP_KERNEL | __GFP_ZERO);
447 
448 	miscstat.minor = miscdev_test_ranges[0].minor;
449 	ret = misc_register(&miscstat);
450 	KUNIT_ASSERT_EQ(test, ret, 0);
451 	KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor);
452 
453 	for (i = 0; i < dynamic_minors; i++) {
454 		miscdev[i].minor = MISC_DYNAMIC_MINOR;
455 		miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i);
456 		miscdev[i].fops = &miscdev_test_fops;
457 		ret = misc_register(&miscdev[i]);
458 		if (ret != 0)
459 			break;
460 		KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor));
461 	}
462 
463 	for (i--; i >= 0; i--) {
464 		miscdev_test_can_open(test, &miscdev[i]);
465 		misc_deregister(&miscdev[i]);
466 		kfree_const(miscdev[i].name);
467 	}
468 
469 	misc_deregister(&miscstat);
470 
471 	KUNIT_EXPECT_EQ(test, ret, 0);
472 }
473 
474 static void __init miscdev_test_collision_reverse(struct kunit *test)
475 {
476 	int ret;
477 	struct miscdevice *miscdev;
478 	struct miscdevice miscstat = {
479 		.name = "miscstat",
480 		.fops = &miscdev_test_fops,
481 	};
482 	const int dynamic_minors = 256;
483 	int i;
484 
485 	miscdev = kunit_kmalloc_array(test, dynamic_minors,
486 					sizeof(struct miscdevice),
487 					GFP_KERNEL | __GFP_ZERO);
488 
489 	for (i = 0; i < dynamic_minors; i++) {
490 		miscdev[i].minor = MISC_DYNAMIC_MINOR;
491 		miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i);
492 		miscdev[i].fops = &miscdev_test_fops;
493 		ret = misc_register(&miscdev[i]);
494 		if (ret != 0)
495 			break;
496 		KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor));
497 	}
498 
499 	KUNIT_EXPECT_EQ(test, ret, 0);
500 
501 	miscstat.minor = miscdev_test_ranges[0].minor;
502 	ret = misc_register(&miscstat);
503 	KUNIT_EXPECT_EQ(test, ret, 0);
504 	KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor);
505 	if (ret == 0)
506 		misc_deregister(&miscstat);
507 
508 	for (i--; i >= 0; i--) {
509 		miscdev_test_can_open(test, &miscdev[i]);
510 		misc_deregister(&miscdev[i]);
511 		kfree_const(miscdev[i].name);
512 	}
513 }
514 
515 static void __init miscdev_test_conflict(struct kunit *test)
516 {
517 	int ret;
518 	struct miscdevice miscdyn = {
519 		.name = "miscdyn",
520 		.minor = MISC_DYNAMIC_MINOR,
521 		.fops = &miscdev_test_fops,
522 	};
523 	struct miscdevice miscstat = {
524 		.name = "miscstat",
525 		.fops = &miscdev_test_fops,
526 	};
527 
528 	ret = misc_register(&miscdyn);
529 	KUNIT_ASSERT_EQ(test, ret, 0);
530 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor));
531 
532 	/*
533 	 * Try to register a static minor with the same minor as the
534 	 * dynamic one.
535 	 */
536 	miscstat.minor = miscdyn.minor;
537 	ret = misc_register(&miscstat);
538 	KUNIT_EXPECT_EQ(test, ret, -EINVAL);
539 	if (ret == 0)
540 		misc_deregister(&miscstat);
541 
542 	miscdev_test_can_open(test, &miscdyn);
543 
544 	misc_deregister(&miscdyn);
545 }
546 
547 static void __init miscdev_test_conflict_reverse(struct kunit *test)
548 {
549 	int ret;
550 	struct miscdevice miscdyn = {
551 		.name = "miscdyn",
552 		.minor = MISC_DYNAMIC_MINOR,
553 		.fops = &miscdev_test_fops,
554 	};
555 	struct miscdevice miscstat = {
556 		.name = "miscstat",
557 		.fops = &miscdev_test_fops,
558 	};
559 
560 	/*
561 	 * Find the first available dynamic minor to use it as a static
562 	 * minor later on.
563 	 */
564 	ret = misc_register(&miscdyn);
565 	KUNIT_ASSERT_EQ(test, ret, 0);
566 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor));
567 	miscstat.minor = miscdyn.minor;
568 	misc_deregister(&miscdyn);
569 
570 	ret = misc_register(&miscstat);
571 	KUNIT_EXPECT_EQ(test, ret, -EINVAL);
572 	if (ret == 0)
573 		misc_deregister(&miscstat);
574 
575 	/*
576 	 * Try to register a dynamic minor after registering a static minor
577 	 * within the dynamic range. It should work but get a different
578 	 * minor.
579 	 */
580 	miscdyn.minor = MISC_DYNAMIC_MINOR;
581 	ret = misc_register(&miscdyn);
582 	KUNIT_EXPECT_EQ(test, ret, 0);
583 	KUNIT_EXPECT_EQ(test, miscdyn.minor, miscstat.minor);
584 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor));
585 	if (ret == 0)
586 		misc_deregister(&miscdyn);
587 }
588 
589 /* Take minor(> MISC_DYNAMIC_MINOR) as invalid when register miscdevice */
590 static void miscdev_test_invalid_input(struct kunit *test)
591 {
592 	struct miscdevice misc_test = {
593 		.minor = MISC_DYNAMIC_MINOR + 1,
594 		.name = "misc_test",
595 		.fops = &miscdev_test_fops,
596 	};
597 	int ret;
598 
599 	ret = misc_register(&misc_test);
600 	KUNIT_EXPECT_EQ(test, ret, -EINVAL);
601 	if (ret == 0)
602 		misc_deregister(&misc_test);
603 }
604 
605 /*
606  * Verify if @miscdyn_a can still be registered successfully without
607  * reinitialization even if its minor ever owned was requested by
608  * another miscdevice such as @miscdyn_b.
609  */
610 static void miscdev_test_dynamic_reentry(struct kunit *test)
611 {
612 	struct miscdevice miscdyn_a = {
613 		.name = "miscdyn_a",
614 		.minor = MISC_DYNAMIC_MINOR,
615 		.fops = &miscdev_test_fops,
616 	};
617 	struct miscdevice miscdyn_b = {
618 		.name = "miscdyn_b",
619 		.minor = MISC_DYNAMIC_MINOR,
620 		.fops = &miscdev_test_fops,
621 	};
622 	int ret, minor_a;
623 
624 	ret = misc_register(&miscdyn_a);
625 	KUNIT_ASSERT_EQ(test, ret, 0);
626 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor));
627 	minor_a = miscdyn_a.minor;
628 	if (ret != 0)
629 		return;
630 	misc_deregister(&miscdyn_a);
631 
632 	ret = misc_register(&miscdyn_b);
633 	KUNIT_ASSERT_EQ(test, ret, 0);
634 	KUNIT_EXPECT_EQ(test, miscdyn_b.minor, minor_a);
635 	if (ret != 0)
636 		return;
637 
638 	ret = misc_register(&miscdyn_a);
639 	KUNIT_ASSERT_EQ(test, ret, 0);
640 	KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor));
641 	KUNIT_EXPECT_NE(test, miscdyn_a.minor, miscdyn_b.minor);
642 	if (ret == 0)
643 		misc_deregister(&miscdyn_a);
644 
645 	misc_deregister(&miscdyn_b);
646 }
647 
648 static struct kunit_case test_cases[] = {
649 	KUNIT_CASE(kunit_static_minor),
650 	KUNIT_CASE(kunit_misc_dynamic_minor),
651 	KUNIT_CASE(miscdev_test_invalid_input),
652 	KUNIT_CASE_PARAM(miscdev_test_twice, miscdev_gen_params),
653 	KUNIT_CASE_PARAM(miscdev_test_duplicate_minor, miscdev_gen_params),
654 	KUNIT_CASE(miscdev_test_duplicate_name),
655 	KUNIT_CASE(miscdev_test_duplicate_name_leak),
656 	KUNIT_CASE_PARAM(miscdev_test_duplicate_error, miscdev_gen_params),
657 	KUNIT_CASE(miscdev_test_dynamic_reentry),
658 	{}
659 };
660 
661 static struct kunit_suite test_suite = {
662 	.name = "miscdev",
663 	.suite_init = miscdev_find_minors,
664 	.test_cases = test_cases,
665 };
666 kunit_test_suite(test_suite);
667 
668 static struct kunit_case __refdata test_init_cases[] = {
669 	KUNIT_CASE_PARAM(miscdev_test_static_basic, miscdev_gen_params),
670 	KUNIT_CASE(miscdev_test_dynamic_basic),
671 	KUNIT_CASE(miscdev_test_dynamic_only_range),
672 	KUNIT_CASE(miscdev_test_collision),
673 	KUNIT_CASE(miscdev_test_collision_reverse),
674 	KUNIT_CASE(miscdev_test_conflict),
675 	KUNIT_CASE(miscdev_test_conflict_reverse),
676 	{}
677 };
678 
679 static struct kunit_suite test_init_suite = {
680 	.name = "miscdev_init",
681 	.suite_init = miscdev_find_minors,
682 	.test_cases = test_init_cases,
683 };
684 kunit_test_init_section_suite(test_init_suite);
685 
686 MODULE_LICENSE("GPL");
687 MODULE_AUTHOR("Vimal Agrawal");
688 MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@igalia.com>");
689 MODULE_DESCRIPTION("Test module for misc character devices");
690