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