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