18ac646d6SZijun Hu // SPDX-License-Identifier: GPL-2.0 28ac646d6SZijun Hu #include <kunit/test.h> 38ac646d6SZijun Hu #include <kunit/test-bug.h> 48ac646d6SZijun Hu #include <linux/module.h> 58ac646d6SZijun Hu #include <linux/miscdevice.h> 68ac646d6SZijun Hu #include <linux/fs.h> 78ac646d6SZijun Hu #include <linux/file.h> 88ac646d6SZijun Hu #include <linux/init_syscalls.h> 98ac646d6SZijun Hu 108ac646d6SZijun Hu /* static minor (LCD_MINOR) */ 118ac646d6SZijun Hu static struct miscdevice dev_static_minor = { 128ac646d6SZijun Hu .minor = LCD_MINOR, 138ac646d6SZijun Hu .name = "dev_static_minor", 148ac646d6SZijun Hu }; 158ac646d6SZijun Hu 168ac646d6SZijun Hu /* misc dynamic minor */ 178ac646d6SZijun Hu static struct miscdevice dev_misc_dynamic_minor = { 188ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 198ac646d6SZijun Hu .name = "dev_misc_dynamic_minor", 208ac646d6SZijun Hu }; 218ac646d6SZijun Hu 228ac646d6SZijun Hu static void kunit_static_minor(struct kunit *test) 238ac646d6SZijun Hu { 248ac646d6SZijun Hu int ret; 258ac646d6SZijun Hu 268ac646d6SZijun Hu ret = misc_register(&dev_static_minor); 278ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, 0, ret); 288ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, LCD_MINOR, dev_static_minor.minor); 298ac646d6SZijun Hu misc_deregister(&dev_static_minor); 308ac646d6SZijun Hu } 318ac646d6SZijun Hu 328ac646d6SZijun Hu static void kunit_misc_dynamic_minor(struct kunit *test) 338ac646d6SZijun Hu { 348ac646d6SZijun Hu int ret; 358ac646d6SZijun Hu 368ac646d6SZijun Hu ret = misc_register(&dev_misc_dynamic_minor); 378ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, 0, ret); 388ac646d6SZijun Hu misc_deregister(&dev_misc_dynamic_minor); 398ac646d6SZijun Hu } 408ac646d6SZijun Hu 418ac646d6SZijun Hu struct miscdev_test_case { 428ac646d6SZijun Hu const char *str; 438ac646d6SZijun Hu int minor; 448ac646d6SZijun Hu }; 458ac646d6SZijun Hu 468ac646d6SZijun Hu static struct miscdev_test_case miscdev_test_ranges[] = { 478ac646d6SZijun Hu { 488ac646d6SZijun Hu .str = "lower static range, top", 498ac646d6SZijun Hu .minor = 15, 508ac646d6SZijun Hu }, 518ac646d6SZijun Hu { 528ac646d6SZijun Hu .str = "upper static range, bottom", 538ac646d6SZijun Hu .minor = 130, 548ac646d6SZijun Hu }, 558ac646d6SZijun Hu { 568ac646d6SZijun Hu .str = "lower static range, bottom", 578ac646d6SZijun Hu .minor = 0, 588ac646d6SZijun Hu }, 598ac646d6SZijun Hu { 608ac646d6SZijun Hu .str = "upper static range, top", 618ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR - 1, 628ac646d6SZijun Hu }, 638ac646d6SZijun Hu }; 648ac646d6SZijun Hu 658ac646d6SZijun Hu KUNIT_ARRAY_PARAM_DESC(miscdev, miscdev_test_ranges, str); 668ac646d6SZijun Hu 678ac646d6SZijun Hu static int miscdev_find_minors(struct kunit_suite *suite) 688ac646d6SZijun Hu { 698ac646d6SZijun Hu int ret; 708ac646d6SZijun Hu struct miscdevice miscstat = { 718ac646d6SZijun Hu .name = "miscstat", 728ac646d6SZijun Hu }; 738ac646d6SZijun Hu int i; 748ac646d6SZijun Hu 758ac646d6SZijun Hu for (i = 15; i >= 0; i--) { 768ac646d6SZijun Hu miscstat.minor = i; 778ac646d6SZijun Hu ret = misc_register(&miscstat); 788ac646d6SZijun Hu if (ret == 0) 798ac646d6SZijun Hu break; 808ac646d6SZijun Hu } 818ac646d6SZijun Hu 828ac646d6SZijun Hu if (ret == 0) { 838ac646d6SZijun Hu kunit_info(suite, "found misc device minor %d available\n", 848ac646d6SZijun Hu miscstat.minor); 858ac646d6SZijun Hu miscdev_test_ranges[0].minor = miscstat.minor; 868ac646d6SZijun Hu misc_deregister(&miscstat); 878ac646d6SZijun Hu } else { 888ac646d6SZijun Hu return ret; 898ac646d6SZijun Hu } 908ac646d6SZijun Hu 918ac646d6SZijun Hu for (i = 128; i < MISC_DYNAMIC_MINOR; i++) { 928ac646d6SZijun Hu miscstat.minor = i; 938ac646d6SZijun Hu ret = misc_register(&miscstat); 948ac646d6SZijun Hu if (ret == 0) 958ac646d6SZijun Hu break; 968ac646d6SZijun Hu } 978ac646d6SZijun Hu 988ac646d6SZijun Hu if (ret == 0) { 998ac646d6SZijun Hu kunit_info(suite, "found misc device minor %d available\n", 1008ac646d6SZijun Hu miscstat.minor); 1018ac646d6SZijun Hu miscdev_test_ranges[1].minor = miscstat.minor; 1028ac646d6SZijun Hu misc_deregister(&miscstat); 1038ac646d6SZijun Hu } else { 1048ac646d6SZijun Hu return ret; 1058ac646d6SZijun Hu } 1068ac646d6SZijun Hu 1078ac646d6SZijun Hu for (i = 0; i < miscdev_test_ranges[0].minor; i++) { 1088ac646d6SZijun Hu miscstat.minor = i; 1098ac646d6SZijun Hu ret = misc_register(&miscstat); 1108ac646d6SZijun Hu if (ret == 0) 1118ac646d6SZijun Hu break; 1128ac646d6SZijun Hu } 1138ac646d6SZijun Hu 1148ac646d6SZijun Hu if (ret == 0) { 1158ac646d6SZijun Hu kunit_info(suite, "found misc device minor %d available\n", 1168ac646d6SZijun Hu miscstat.minor); 1178ac646d6SZijun Hu miscdev_test_ranges[2].minor = miscstat.minor; 1188ac646d6SZijun Hu misc_deregister(&miscstat); 1198ac646d6SZijun Hu } else { 1208ac646d6SZijun Hu return ret; 1218ac646d6SZijun Hu } 1228ac646d6SZijun Hu 1238ac646d6SZijun Hu for (i = MISC_DYNAMIC_MINOR - 1; i > miscdev_test_ranges[1].minor; i--) { 1248ac646d6SZijun Hu miscstat.minor = i; 1258ac646d6SZijun Hu ret = misc_register(&miscstat); 1268ac646d6SZijun Hu if (ret == 0) 1278ac646d6SZijun Hu break; 1288ac646d6SZijun Hu } 1298ac646d6SZijun Hu 1308ac646d6SZijun Hu if (ret == 0) { 1318ac646d6SZijun Hu kunit_info(suite, "found misc device minor %d available\n", 1328ac646d6SZijun Hu miscstat.minor); 1338ac646d6SZijun Hu miscdev_test_ranges[3].minor = miscstat.minor; 1348ac646d6SZijun Hu misc_deregister(&miscstat); 1358ac646d6SZijun Hu } 1368ac646d6SZijun Hu 1378ac646d6SZijun Hu return ret; 1388ac646d6SZijun Hu } 1398ac646d6SZijun Hu 1408ac646d6SZijun Hu static bool is_valid_dynamic_minor(int minor) 1418ac646d6SZijun Hu { 1428ac646d6SZijun Hu if (minor < 0) 1438ac646d6SZijun Hu return false; 144f4e47affSZijun Hu return minor > MISC_DYNAMIC_MINOR; 1458ac646d6SZijun Hu } 1468ac646d6SZijun Hu 1478ac646d6SZijun Hu static int miscdev_test_open(struct inode *inode, struct file *file) 1488ac646d6SZijun Hu { 1498ac646d6SZijun Hu return 0; 1508ac646d6SZijun Hu } 1518ac646d6SZijun Hu 1528ac646d6SZijun Hu static const struct file_operations miscdev_test_fops = { 1538ac646d6SZijun Hu .open = miscdev_test_open, 1548ac646d6SZijun Hu }; 1558ac646d6SZijun Hu 1568ac646d6SZijun Hu static void __init miscdev_test_can_open(struct kunit *test, struct miscdevice *misc) 1578ac646d6SZijun Hu { 1588ac646d6SZijun Hu int ret; 1598ac646d6SZijun Hu struct file *filp; 1608ac646d6SZijun Hu char *devname; 1618ac646d6SZijun Hu 1628ac646d6SZijun Hu devname = kasprintf(GFP_KERNEL, "/dev/%s", misc->name); 1638ac646d6SZijun Hu ret = init_mknod(devname, S_IFCHR | 0600, 1648ac646d6SZijun Hu new_encode_dev(MKDEV(MISC_MAJOR, misc->minor))); 1658ac646d6SZijun Hu if (ret != 0) 1668ac646d6SZijun Hu KUNIT_FAIL(test, "failed to create node\n"); 1678ac646d6SZijun Hu 1688ac646d6SZijun Hu filp = filp_open(devname, O_RDONLY, 0); 1698ac646d6SZijun Hu if (IS_ERR_OR_NULL(filp)) 1708ac646d6SZijun Hu KUNIT_FAIL(test, "failed to open misc device: %ld\n", PTR_ERR(filp)); 1718ac646d6SZijun Hu else 1728ac646d6SZijun Hu fput(filp); 1738ac646d6SZijun Hu 1748ac646d6SZijun Hu init_unlink(devname); 1758ac646d6SZijun Hu kfree(devname); 1768ac646d6SZijun Hu } 1778ac646d6SZijun Hu 1788ac646d6SZijun Hu static void __init miscdev_test_static_basic(struct kunit *test) 1798ac646d6SZijun Hu { 1808ac646d6SZijun Hu struct miscdevice misc_test = { 1818ac646d6SZijun Hu .name = "misc_test", 1828ac646d6SZijun Hu .fops = &miscdev_test_fops, 1838ac646d6SZijun Hu }; 1848ac646d6SZijun Hu int ret; 1858ac646d6SZijun Hu const struct miscdev_test_case *params = test->param_value; 1868ac646d6SZijun Hu 1878ac646d6SZijun Hu misc_test.minor = params->minor; 1888ac646d6SZijun Hu 1898ac646d6SZijun Hu ret = misc_register(&misc_test); 1908ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 1918ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor); 1928ac646d6SZijun Hu 1938ac646d6SZijun Hu if (ret == 0) { 1948ac646d6SZijun Hu miscdev_test_can_open(test, &misc_test); 1958ac646d6SZijun Hu misc_deregister(&misc_test); 1968ac646d6SZijun Hu } 1978ac646d6SZijun Hu } 1988ac646d6SZijun Hu 1998ac646d6SZijun Hu static void __init miscdev_test_dynamic_basic(struct kunit *test) 2008ac646d6SZijun Hu { 2018ac646d6SZijun Hu struct miscdevice misc_test = { 2028ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 2038ac646d6SZijun Hu .name = "misc_test", 2048ac646d6SZijun Hu .fops = &miscdev_test_fops, 2058ac646d6SZijun Hu }; 2068ac646d6SZijun Hu int ret; 2078ac646d6SZijun Hu 2088ac646d6SZijun Hu ret = misc_register(&misc_test); 2098ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 2108ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc_test.minor)); 2118ac646d6SZijun Hu 2128ac646d6SZijun Hu if (ret == 0) { 2138ac646d6SZijun Hu miscdev_test_can_open(test, &misc_test); 2148ac646d6SZijun Hu misc_deregister(&misc_test); 2158ac646d6SZijun Hu } 2168ac646d6SZijun Hu } 2178ac646d6SZijun Hu 2188ac646d6SZijun Hu static void miscdev_test_twice(struct kunit *test) 2198ac646d6SZijun Hu { 2208ac646d6SZijun Hu struct miscdevice misc_test = { 2218ac646d6SZijun Hu .name = "misc_test", 2228ac646d6SZijun Hu .fops = &miscdev_test_fops, 2238ac646d6SZijun Hu }; 2248ac646d6SZijun Hu int ret; 2258ac646d6SZijun Hu const struct miscdev_test_case *params = test->param_value; 2268ac646d6SZijun Hu 2278ac646d6SZijun Hu misc_test.minor = params->minor; 2288ac646d6SZijun Hu 2298ac646d6SZijun Hu ret = misc_register(&misc_test); 2308ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 2318ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor); 2328ac646d6SZijun Hu if (ret == 0) 2338ac646d6SZijun Hu misc_deregister(&misc_test); 2348ac646d6SZijun Hu 2358ac646d6SZijun Hu ret = misc_register(&misc_test); 2368ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 2378ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor); 2388ac646d6SZijun Hu if (ret == 0) 2398ac646d6SZijun Hu misc_deregister(&misc_test); 2408ac646d6SZijun Hu } 2418ac646d6SZijun Hu 2428ac646d6SZijun Hu static void miscdev_test_duplicate_minor(struct kunit *test) 2438ac646d6SZijun Hu { 2448ac646d6SZijun Hu struct miscdevice misc1 = { 2458ac646d6SZijun Hu .name = "misc1", 2468ac646d6SZijun Hu .fops = &miscdev_test_fops, 2478ac646d6SZijun Hu }; 2488ac646d6SZijun Hu struct miscdevice misc2 = { 2498ac646d6SZijun Hu .name = "misc2", 2508ac646d6SZijun Hu .fops = &miscdev_test_fops, 2518ac646d6SZijun Hu }; 2528ac646d6SZijun Hu int ret; 2538ac646d6SZijun Hu const struct miscdev_test_case *params = test->param_value; 2548ac646d6SZijun Hu 2558ac646d6SZijun Hu misc1.minor = params->minor; 2568ac646d6SZijun Hu misc2.minor = params->minor; 2578ac646d6SZijun Hu 2588ac646d6SZijun Hu ret = misc_register(&misc1); 2598ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 2608ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, misc1.minor, params->minor); 2618ac646d6SZijun Hu 2628ac646d6SZijun Hu ret = misc_register(&misc2); 2638ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, -EBUSY); 2648ac646d6SZijun Hu if (ret == 0) 2658ac646d6SZijun Hu misc_deregister(&misc2); 2668ac646d6SZijun Hu 2678ac646d6SZijun Hu misc_deregister(&misc1); 2688ac646d6SZijun Hu } 2698ac646d6SZijun Hu 2708ac646d6SZijun Hu static void miscdev_test_duplicate_name(struct kunit *test) 2718ac646d6SZijun Hu { 2728ac646d6SZijun Hu struct miscdevice misc1 = { 2738ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 2748ac646d6SZijun Hu .name = "misc1", 2758ac646d6SZijun Hu .fops = &miscdev_test_fops, 2768ac646d6SZijun Hu }; 2778ac646d6SZijun Hu struct miscdevice misc2 = { 2788ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 2798ac646d6SZijun Hu .name = "misc1", 2808ac646d6SZijun Hu .fops = &miscdev_test_fops, 2818ac646d6SZijun Hu }; 2828ac646d6SZijun Hu int ret; 2838ac646d6SZijun Hu 2848ac646d6SZijun Hu ret = misc_register(&misc1); 2858ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 2868ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor)); 2878ac646d6SZijun Hu 2888ac646d6SZijun Hu ret = misc_register(&misc2); 2898ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, -EEXIST); 2908ac646d6SZijun Hu if (ret == 0) 2918ac646d6SZijun Hu misc_deregister(&misc2); 2928ac646d6SZijun Hu 2938ac646d6SZijun Hu misc_deregister(&misc1); 2948ac646d6SZijun Hu } 2958ac646d6SZijun Hu 2968ac646d6SZijun Hu /* 2978ac646d6SZijun Hu * Test that after a duplicate name failure, the reserved minor number is 2988ac646d6SZijun Hu * freed to be allocated next. 2998ac646d6SZijun Hu */ 3008ac646d6SZijun Hu static void miscdev_test_duplicate_name_leak(struct kunit *test) 3018ac646d6SZijun Hu { 3028ac646d6SZijun Hu struct miscdevice misc1 = { 3038ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 3048ac646d6SZijun Hu .name = "misc1", 3058ac646d6SZijun Hu .fops = &miscdev_test_fops, 3068ac646d6SZijun Hu }; 3078ac646d6SZijun Hu struct miscdevice misc2 = { 3088ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 3098ac646d6SZijun Hu .name = "misc1", 3108ac646d6SZijun Hu .fops = &miscdev_test_fops, 3118ac646d6SZijun Hu }; 3128ac646d6SZijun Hu struct miscdevice misc3 = { 3138ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 3148ac646d6SZijun Hu .name = "misc3", 3158ac646d6SZijun Hu .fops = &miscdev_test_fops, 3168ac646d6SZijun Hu }; 3178ac646d6SZijun Hu int ret; 3188ac646d6SZijun Hu int dyn_minor; 3198ac646d6SZijun Hu 3208ac646d6SZijun Hu ret = misc_register(&misc1); 3218ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 3228ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor)); 3238ac646d6SZijun Hu 3248ac646d6SZijun Hu /* 3258ac646d6SZijun Hu * Find out what is the next minor number available. 3268ac646d6SZijun Hu */ 3278ac646d6SZijun Hu ret = misc_register(&misc3); 3288ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 3298ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor)); 3308ac646d6SZijun Hu dyn_minor = misc3.minor; 3318ac646d6SZijun Hu misc_deregister(&misc3); 3328ac646d6SZijun Hu misc3.minor = MISC_DYNAMIC_MINOR; 3338ac646d6SZijun Hu 3348ac646d6SZijun Hu ret = misc_register(&misc2); 3358ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, -EEXIST); 3368ac646d6SZijun Hu if (ret == 0) 3378ac646d6SZijun Hu misc_deregister(&misc2); 3388ac646d6SZijun Hu 3398ac646d6SZijun Hu /* 3408ac646d6SZijun Hu * Now check that we can still get the same minor we found before. 3418ac646d6SZijun Hu */ 3428ac646d6SZijun Hu ret = misc_register(&misc3); 3438ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 3448ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor)); 3458ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, misc3.minor, dyn_minor); 3468ac646d6SZijun Hu misc_deregister(&misc3); 3478ac646d6SZijun Hu 3488ac646d6SZijun Hu misc_deregister(&misc1); 3498ac646d6SZijun Hu } 3508ac646d6SZijun Hu 3518ac646d6SZijun Hu /* 3528ac646d6SZijun Hu * Try to register a static minor with a duplicate name. That might not 3538ac646d6SZijun Hu * deallocate the minor, preventing it from being used again. 3548ac646d6SZijun Hu */ 3558ac646d6SZijun Hu static void miscdev_test_duplicate_error(struct kunit *test) 3568ac646d6SZijun Hu { 3578ac646d6SZijun Hu struct miscdevice miscdyn = { 3588ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 3598ac646d6SZijun Hu .name = "name1", 3608ac646d6SZijun Hu .fops = &miscdev_test_fops, 3618ac646d6SZijun Hu }; 3628ac646d6SZijun Hu struct miscdevice miscstat = { 3638ac646d6SZijun Hu .name = "name1", 3648ac646d6SZijun Hu .fops = &miscdev_test_fops, 3658ac646d6SZijun Hu }; 3668ac646d6SZijun Hu struct miscdevice miscnew = { 3678ac646d6SZijun Hu .name = "name2", 3688ac646d6SZijun Hu .fops = &miscdev_test_fops, 3698ac646d6SZijun Hu }; 3708ac646d6SZijun Hu int ret; 3718ac646d6SZijun Hu const struct miscdev_test_case *params = test->param_value; 3728ac646d6SZijun Hu 3738ac646d6SZijun Hu miscstat.minor = params->minor; 3748ac646d6SZijun Hu miscnew.minor = params->minor; 3758ac646d6SZijun Hu 3768ac646d6SZijun Hu ret = misc_register(&miscdyn); 3778ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 3788ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 3798ac646d6SZijun Hu 3808ac646d6SZijun Hu ret = misc_register(&miscstat); 3818ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, -EEXIST); 3828ac646d6SZijun Hu if (ret == 0) 3838ac646d6SZijun Hu misc_deregister(&miscstat); 3848ac646d6SZijun Hu 3858ac646d6SZijun Hu ret = misc_register(&miscnew); 3868ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 3878ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, miscnew.minor, params->minor); 3888ac646d6SZijun Hu if (ret == 0) 3898ac646d6SZijun Hu misc_deregister(&miscnew); 3908ac646d6SZijun Hu 3918ac646d6SZijun Hu misc_deregister(&miscdyn); 3928ac646d6SZijun Hu } 3938ac646d6SZijun Hu 3948ac646d6SZijun Hu static void __init miscdev_test_dynamic_only_range(struct kunit *test) 3958ac646d6SZijun Hu { 3968ac646d6SZijun Hu int ret; 3978ac646d6SZijun Hu struct miscdevice *miscdev; 3988ac646d6SZijun Hu const int dynamic_minors = 256; 3998ac646d6SZijun Hu int i; 4008ac646d6SZijun Hu 4018ac646d6SZijun Hu miscdev = kunit_kmalloc_array(test, dynamic_minors, 4028ac646d6SZijun Hu sizeof(struct miscdevice), 4038ac646d6SZijun Hu GFP_KERNEL | __GFP_ZERO); 4048ac646d6SZijun Hu 4058ac646d6SZijun Hu for (i = 0; i < dynamic_minors; i++) { 4068ac646d6SZijun Hu miscdev[i].minor = MISC_DYNAMIC_MINOR; 4078ac646d6SZijun Hu miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i); 4088ac646d6SZijun Hu miscdev[i].fops = &miscdev_test_fops; 4098ac646d6SZijun Hu ret = misc_register(&miscdev[i]); 4108ac646d6SZijun Hu if (ret != 0) 4118ac646d6SZijun Hu break; 4128ac646d6SZijun Hu /* 4138ac646d6SZijun Hu * This is the bug we are looking for! 4148ac646d6SZijun Hu * We asked for a dynamic minor and got a minor in the static range space. 4158ac646d6SZijun Hu */ 4168ac646d6SZijun Hu if (miscdev[i].minor >= 0 && miscdev[i].minor <= 15) { 4178ac646d6SZijun Hu KUNIT_FAIL(test, "misc_register allocated minor %d\n", miscdev[i].minor); 4188ac646d6SZijun Hu i++; 4198ac646d6SZijun Hu break; 4208ac646d6SZijun Hu } 4218ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor)); 4228ac646d6SZijun Hu } 4238ac646d6SZijun Hu 4248ac646d6SZijun Hu for (i--; i >= 0; i--) { 4258ac646d6SZijun Hu miscdev_test_can_open(test, &miscdev[i]); 4268ac646d6SZijun Hu misc_deregister(&miscdev[i]); 4278ac646d6SZijun Hu kfree_const(miscdev[i].name); 4288ac646d6SZijun Hu } 4298ac646d6SZijun Hu 4308ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 4318ac646d6SZijun Hu } 4328ac646d6SZijun Hu 4338ac646d6SZijun Hu static void __init miscdev_test_collision(struct kunit *test) 4348ac646d6SZijun Hu { 4358ac646d6SZijun Hu int ret; 4368ac646d6SZijun Hu struct miscdevice *miscdev; 4378ac646d6SZijun Hu struct miscdevice miscstat = { 4388ac646d6SZijun Hu .name = "miscstat", 4398ac646d6SZijun Hu .fops = &miscdev_test_fops, 4408ac646d6SZijun Hu }; 4418ac646d6SZijun Hu const int dynamic_minors = 256; 4428ac646d6SZijun Hu int i; 4438ac646d6SZijun Hu 4448ac646d6SZijun Hu miscdev = kunit_kmalloc_array(test, dynamic_minors, 4458ac646d6SZijun Hu sizeof(struct miscdevice), 4468ac646d6SZijun Hu GFP_KERNEL | __GFP_ZERO); 4478ac646d6SZijun Hu 4488ac646d6SZijun Hu miscstat.minor = miscdev_test_ranges[0].minor; 4498ac646d6SZijun Hu ret = misc_register(&miscstat); 4508ac646d6SZijun Hu KUNIT_ASSERT_EQ(test, ret, 0); 4518ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor); 4528ac646d6SZijun Hu 4538ac646d6SZijun Hu for (i = 0; i < dynamic_minors; i++) { 4548ac646d6SZijun Hu miscdev[i].minor = MISC_DYNAMIC_MINOR; 4558ac646d6SZijun Hu miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i); 4568ac646d6SZijun Hu miscdev[i].fops = &miscdev_test_fops; 4578ac646d6SZijun Hu ret = misc_register(&miscdev[i]); 4588ac646d6SZijun Hu if (ret != 0) 4598ac646d6SZijun Hu break; 4608ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor)); 4618ac646d6SZijun Hu } 4628ac646d6SZijun Hu 4638ac646d6SZijun Hu for (i--; i >= 0; i--) { 4648ac646d6SZijun Hu miscdev_test_can_open(test, &miscdev[i]); 4658ac646d6SZijun Hu misc_deregister(&miscdev[i]); 4668ac646d6SZijun Hu kfree_const(miscdev[i].name); 4678ac646d6SZijun Hu } 4688ac646d6SZijun Hu 4698ac646d6SZijun Hu misc_deregister(&miscstat); 4708ac646d6SZijun Hu 4718ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 4728ac646d6SZijun Hu } 4738ac646d6SZijun Hu 4748ac646d6SZijun Hu static void __init miscdev_test_collision_reverse(struct kunit *test) 4758ac646d6SZijun Hu { 4768ac646d6SZijun Hu int ret; 4778ac646d6SZijun Hu struct miscdevice *miscdev; 4788ac646d6SZijun Hu struct miscdevice miscstat = { 4798ac646d6SZijun Hu .name = "miscstat", 4808ac646d6SZijun Hu .fops = &miscdev_test_fops, 4818ac646d6SZijun Hu }; 4828ac646d6SZijun Hu const int dynamic_minors = 256; 4838ac646d6SZijun Hu int i; 4848ac646d6SZijun Hu 4858ac646d6SZijun Hu miscdev = kunit_kmalloc_array(test, dynamic_minors, 4868ac646d6SZijun Hu sizeof(struct miscdevice), 4878ac646d6SZijun Hu GFP_KERNEL | __GFP_ZERO); 4888ac646d6SZijun Hu 4898ac646d6SZijun Hu for (i = 0; i < dynamic_minors; i++) { 4908ac646d6SZijun Hu miscdev[i].minor = MISC_DYNAMIC_MINOR; 4918ac646d6SZijun Hu miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i); 4928ac646d6SZijun Hu miscdev[i].fops = &miscdev_test_fops; 4938ac646d6SZijun Hu ret = misc_register(&miscdev[i]); 4948ac646d6SZijun Hu if (ret != 0) 4958ac646d6SZijun Hu break; 4968ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor)); 4978ac646d6SZijun Hu } 4988ac646d6SZijun Hu 4998ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 5008ac646d6SZijun Hu 5018ac646d6SZijun Hu miscstat.minor = miscdev_test_ranges[0].minor; 5028ac646d6SZijun Hu ret = misc_register(&miscstat); 5038ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 5048ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor); 5058ac646d6SZijun Hu if (ret == 0) 5068ac646d6SZijun Hu misc_deregister(&miscstat); 5078ac646d6SZijun Hu 5088ac646d6SZijun Hu for (i--; i >= 0; i--) { 5098ac646d6SZijun Hu miscdev_test_can_open(test, &miscdev[i]); 5108ac646d6SZijun Hu misc_deregister(&miscdev[i]); 5118ac646d6SZijun Hu kfree_const(miscdev[i].name); 5128ac646d6SZijun Hu } 5138ac646d6SZijun Hu } 5148ac646d6SZijun Hu 5158ac646d6SZijun Hu static void __init miscdev_test_conflict(struct kunit *test) 5168ac646d6SZijun Hu { 5178ac646d6SZijun Hu int ret; 5188ac646d6SZijun Hu struct miscdevice miscdyn = { 5198ac646d6SZijun Hu .name = "miscdyn", 5208ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 5218ac646d6SZijun Hu .fops = &miscdev_test_fops, 5228ac646d6SZijun Hu }; 5238ac646d6SZijun Hu struct miscdevice miscstat = { 5248ac646d6SZijun Hu .name = "miscstat", 5258ac646d6SZijun Hu .fops = &miscdev_test_fops, 5268ac646d6SZijun Hu }; 5278ac646d6SZijun Hu 5288ac646d6SZijun Hu ret = misc_register(&miscdyn); 5298ac646d6SZijun Hu KUNIT_ASSERT_EQ(test, ret, 0); 5308ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 5318ac646d6SZijun Hu 5328ac646d6SZijun Hu /* 5338ac646d6SZijun Hu * Try to register a static minor with the same minor as the 5348ac646d6SZijun Hu * dynamic one. 5358ac646d6SZijun Hu */ 5368ac646d6SZijun Hu miscstat.minor = miscdyn.minor; 5378ac646d6SZijun Hu ret = misc_register(&miscstat); 538f4e47affSZijun Hu KUNIT_EXPECT_EQ(test, ret, -EINVAL); 5398ac646d6SZijun Hu if (ret == 0) 5408ac646d6SZijun Hu misc_deregister(&miscstat); 5418ac646d6SZijun Hu 5428ac646d6SZijun Hu miscdev_test_can_open(test, &miscdyn); 5438ac646d6SZijun Hu 5448ac646d6SZijun Hu misc_deregister(&miscdyn); 5458ac646d6SZijun Hu } 5468ac646d6SZijun Hu 5478ac646d6SZijun Hu static void __init miscdev_test_conflict_reverse(struct kunit *test) 5488ac646d6SZijun Hu { 5498ac646d6SZijun Hu int ret; 5508ac646d6SZijun Hu struct miscdevice miscdyn = { 5518ac646d6SZijun Hu .name = "miscdyn", 5528ac646d6SZijun Hu .minor = MISC_DYNAMIC_MINOR, 5538ac646d6SZijun Hu .fops = &miscdev_test_fops, 5548ac646d6SZijun Hu }; 5558ac646d6SZijun Hu struct miscdevice miscstat = { 5568ac646d6SZijun Hu .name = "miscstat", 5578ac646d6SZijun Hu .fops = &miscdev_test_fops, 5588ac646d6SZijun Hu }; 5598ac646d6SZijun Hu 5608ac646d6SZijun Hu /* 5618ac646d6SZijun Hu * Find the first available dynamic minor to use it as a static 5628ac646d6SZijun Hu * minor later on. 5638ac646d6SZijun Hu */ 5648ac646d6SZijun Hu ret = misc_register(&miscdyn); 5658ac646d6SZijun Hu KUNIT_ASSERT_EQ(test, ret, 0); 5668ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 5678ac646d6SZijun Hu miscstat.minor = miscdyn.minor; 5688ac646d6SZijun Hu misc_deregister(&miscdyn); 5698ac646d6SZijun Hu 5708ac646d6SZijun Hu ret = misc_register(&miscstat); 571f4e47affSZijun Hu KUNIT_EXPECT_EQ(test, ret, -EINVAL); 572f4e47affSZijun Hu if (ret == 0) 573f4e47affSZijun Hu misc_deregister(&miscstat); 5748ac646d6SZijun Hu 5758ac646d6SZijun Hu /* 5768ac646d6SZijun Hu * Try to register a dynamic minor after registering a static minor 5778ac646d6SZijun Hu * within the dynamic range. It should work but get a different 5788ac646d6SZijun Hu * minor. 5798ac646d6SZijun Hu */ 5808ac646d6SZijun Hu miscdyn.minor = MISC_DYNAMIC_MINOR; 5818ac646d6SZijun Hu ret = misc_register(&miscdyn); 5828ac646d6SZijun Hu KUNIT_EXPECT_EQ(test, ret, 0); 583f4e47affSZijun Hu KUNIT_EXPECT_EQ(test, miscdyn.minor, miscstat.minor); 5848ac646d6SZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 5858ac646d6SZijun Hu if (ret == 0) 5868ac646d6SZijun Hu misc_deregister(&miscdyn); 587f4e47affSZijun Hu } 5888ac646d6SZijun Hu 589f4e47affSZijun Hu /* Take minor(> MISC_DYNAMIC_MINOR) as invalid when register miscdevice */ 590f4e47affSZijun Hu static void miscdev_test_invalid_input(struct kunit *test) 591f4e47affSZijun Hu { 592f4e47affSZijun Hu struct miscdevice misc_test = { 593f4e47affSZijun Hu .minor = MISC_DYNAMIC_MINOR + 1, 594f4e47affSZijun Hu .name = "misc_test", 595f4e47affSZijun Hu .fops = &miscdev_test_fops, 596f4e47affSZijun Hu }; 597f4e47affSZijun Hu int ret; 5988ac646d6SZijun Hu 599f4e47affSZijun Hu ret = misc_register(&misc_test); 600f4e47affSZijun Hu KUNIT_EXPECT_EQ(test, ret, -EINVAL); 601f4e47affSZijun Hu if (ret == 0) 602f4e47affSZijun Hu misc_deregister(&misc_test); 6038ac646d6SZijun Hu } 6048ac646d6SZijun Hu 605*2334668aSZijun Hu /* 606*2334668aSZijun Hu * Verify if @miscdyn_a can still be registered successfully without 607*2334668aSZijun Hu * reinitialization even if its minor ever owned was requested by 608*2334668aSZijun Hu * another miscdevice such as @miscdyn_b. 609*2334668aSZijun Hu */ 610*2334668aSZijun Hu static void miscdev_test_dynamic_reentry(struct kunit *test) 611*2334668aSZijun Hu { 612*2334668aSZijun Hu struct miscdevice miscdyn_a = { 613*2334668aSZijun Hu .name = "miscdyn_a", 614*2334668aSZijun Hu .minor = MISC_DYNAMIC_MINOR, 615*2334668aSZijun Hu .fops = &miscdev_test_fops, 616*2334668aSZijun Hu }; 617*2334668aSZijun Hu struct miscdevice miscdyn_b = { 618*2334668aSZijun Hu .name = "miscdyn_b", 619*2334668aSZijun Hu .minor = MISC_DYNAMIC_MINOR, 620*2334668aSZijun Hu .fops = &miscdev_test_fops, 621*2334668aSZijun Hu }; 622*2334668aSZijun Hu int ret, minor_a; 623*2334668aSZijun Hu 624*2334668aSZijun Hu ret = misc_register(&miscdyn_a); 625*2334668aSZijun Hu KUNIT_ASSERT_EQ(test, ret, 0); 626*2334668aSZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor)); 627*2334668aSZijun Hu minor_a = miscdyn_a.minor; 628*2334668aSZijun Hu if (ret != 0) 629*2334668aSZijun Hu return; 630*2334668aSZijun Hu misc_deregister(&miscdyn_a); 631*2334668aSZijun Hu 632*2334668aSZijun Hu ret = misc_register(&miscdyn_b); 633*2334668aSZijun Hu KUNIT_ASSERT_EQ(test, ret, 0); 634*2334668aSZijun Hu KUNIT_EXPECT_EQ(test, miscdyn_b.minor, minor_a); 635*2334668aSZijun Hu if (ret != 0) 636*2334668aSZijun Hu return; 637*2334668aSZijun Hu 638*2334668aSZijun Hu ret = misc_register(&miscdyn_a); 639*2334668aSZijun Hu KUNIT_ASSERT_EQ(test, ret, 0); 640*2334668aSZijun Hu KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor)); 641*2334668aSZijun Hu KUNIT_EXPECT_NE(test, miscdyn_a.minor, miscdyn_b.minor); 642*2334668aSZijun Hu if (ret == 0) 643*2334668aSZijun Hu misc_deregister(&miscdyn_a); 644*2334668aSZijun Hu 645*2334668aSZijun Hu misc_deregister(&miscdyn_b); 646*2334668aSZijun Hu } 647*2334668aSZijun Hu 6488ac646d6SZijun Hu static struct kunit_case test_cases[] = { 6498ac646d6SZijun Hu KUNIT_CASE(kunit_static_minor), 6508ac646d6SZijun Hu KUNIT_CASE(kunit_misc_dynamic_minor), 651f4e47affSZijun Hu KUNIT_CASE(miscdev_test_invalid_input), 6528ac646d6SZijun Hu KUNIT_CASE_PARAM(miscdev_test_twice, miscdev_gen_params), 6538ac646d6SZijun Hu KUNIT_CASE_PARAM(miscdev_test_duplicate_minor, miscdev_gen_params), 6548ac646d6SZijun Hu KUNIT_CASE(miscdev_test_duplicate_name), 6558ac646d6SZijun Hu KUNIT_CASE(miscdev_test_duplicate_name_leak), 6568ac646d6SZijun Hu KUNIT_CASE_PARAM(miscdev_test_duplicate_error, miscdev_gen_params), 657*2334668aSZijun Hu KUNIT_CASE(miscdev_test_dynamic_reentry), 6588ac646d6SZijun Hu {} 6598ac646d6SZijun Hu }; 6608ac646d6SZijun Hu 6618ac646d6SZijun Hu static struct kunit_suite test_suite = { 6628ac646d6SZijun Hu .name = "miscdev", 6638ac646d6SZijun Hu .suite_init = miscdev_find_minors, 6648ac646d6SZijun Hu .test_cases = test_cases, 6658ac646d6SZijun Hu }; 6668ac646d6SZijun Hu kunit_test_suite(test_suite); 6678ac646d6SZijun Hu 6688ac646d6SZijun Hu static struct kunit_case __refdata test_init_cases[] = { 6698ac646d6SZijun Hu KUNIT_CASE_PARAM(miscdev_test_static_basic, miscdev_gen_params), 6708ac646d6SZijun Hu KUNIT_CASE(miscdev_test_dynamic_basic), 6718ac646d6SZijun Hu KUNIT_CASE(miscdev_test_dynamic_only_range), 6728ac646d6SZijun Hu KUNIT_CASE(miscdev_test_collision), 6738ac646d6SZijun Hu KUNIT_CASE(miscdev_test_collision_reverse), 6748ac646d6SZijun Hu KUNIT_CASE(miscdev_test_conflict), 6758ac646d6SZijun Hu KUNIT_CASE(miscdev_test_conflict_reverse), 6768ac646d6SZijun Hu {} 6778ac646d6SZijun Hu }; 6788ac646d6SZijun Hu 6798ac646d6SZijun Hu static struct kunit_suite test_init_suite = { 6808ac646d6SZijun Hu .name = "miscdev_init", 6818ac646d6SZijun Hu .suite_init = miscdev_find_minors, 6828ac646d6SZijun Hu .test_cases = test_init_cases, 6838ac646d6SZijun Hu }; 6848ac646d6SZijun Hu kunit_test_init_section_suite(test_init_suite); 6858ac646d6SZijun Hu 6868ac646d6SZijun Hu MODULE_LICENSE("GPL"); 6878ac646d6SZijun Hu MODULE_AUTHOR("Vimal Agrawal"); 6888ac646d6SZijun Hu MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@igalia.com>"); 6898ac646d6SZijun Hu MODULE_DESCRIPTION("Test module for misc character devices"); 690