Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/misc/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 15 kB image not shown  

Quelle  misc_minor_kunit.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
#include <kunit/test.h>
#include <kunit/test-bug.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/init_syscalls.h>

/* dynamic minor (2) */
static struct miscdevice dev_dynamic_minor = {
 .minor  = 2,
 .name   = "dev_dynamic_minor",
};

/* static minor (LCD_MINOR) */
static struct miscdevice dev_static_minor = {
 .minor  = LCD_MINOR,
 .name   = "dev_static_minor",
};

/* misc dynamic minor */
static struct miscdevice dev_misc_dynamic_minor = {
 .minor  = MISC_DYNAMIC_MINOR,
 .name   = "dev_misc_dynamic_minor",
};

static void kunit_dynamic_minor(struct kunit *test)
{
 int ret;

 ret = misc_register(&dev_dynamic_minor);
 KUNIT_EXPECT_EQ(test, 0, ret);
 KUNIT_EXPECT_EQ(test, 2, dev_dynamic_minor.minor);
 misc_deregister(&dev_dynamic_minor);
}

static void kunit_static_minor(struct kunit *test)
{
 int ret;

 ret = misc_register(&dev_static_minor);
 KUNIT_EXPECT_EQ(test, 0, ret);
 KUNIT_EXPECT_EQ(test, LCD_MINOR, dev_static_minor.minor);
 misc_deregister(&dev_static_minor);
}

static void kunit_misc_dynamic_minor(struct kunit *test)
{
 int ret;

 ret = misc_register(&dev_misc_dynamic_minor);
 KUNIT_EXPECT_EQ(test, 0, ret);
 misc_deregister(&dev_misc_dynamic_minor);
}

struct miscdev_test_case {
 const char *str;
 int minor;
};

static struct miscdev_test_case miscdev_test_ranges[] = {
 {
  .str = "lower static range, top",
  .minor = 15,
 },
 {
  .str = "upper static range, bottom",
  .minor = 130,
 },
 {
  .str = "lower static range, bottom",
  .minor = 0,
 },
 {
  .str = "upper static range, top",
  .minor = MISC_DYNAMIC_MINOR - 1,
 },
};

KUNIT_ARRAY_PARAM_DESC(miscdev, miscdev_test_ranges, str);

static int miscdev_find_minors(struct kunit_suite *suite)
{
 int ret;
 struct miscdevice miscstat = {
  .name = "miscstat",
 };
 int i;

 for (i = 15; i >= 0; i--) {
  miscstat.minor = i;
  ret = misc_register(&miscstat);
  if (ret == 0)
   break;
 }

 if (ret == 0) {
  kunit_info(suite, "found misc device minor %d available\n",
    miscstat.minor);
  miscdev_test_ranges[0].minor = miscstat.minor;
  misc_deregister(&miscstat);
 } else {
  return ret;
 }

 for (i = 128; i < MISC_DYNAMIC_MINOR; i++) {
  miscstat.minor = i;
  ret = misc_register(&miscstat);
  if (ret == 0)
   break;
 }

 if (ret == 0) {
  kunit_info(suite, "found misc device minor %d available\n",
    miscstat.minor);
  miscdev_test_ranges[1].minor = miscstat.minor;
  misc_deregister(&miscstat);
 } else {
  return ret;
 }

 for (i = 0; i < miscdev_test_ranges[0].minor; i++) {
  miscstat.minor = i;
  ret = misc_register(&miscstat);
  if (ret == 0)
   break;
 }

 if (ret == 0) {
  kunit_info(suite, "found misc device minor %d available\n",
   miscstat.minor);
  miscdev_test_ranges[2].minor = miscstat.minor;
  misc_deregister(&miscstat);
 } else {
  return ret;
 }

 for (i = MISC_DYNAMIC_MINOR - 1; i > miscdev_test_ranges[1].minor; i--) {
  miscstat.minor = i;
  ret = misc_register(&miscstat);
  if (ret == 0)
   break;
 }

 if (ret == 0) {
  kunit_info(suite, "found misc device minor %d available\n",
   miscstat.minor);
  miscdev_test_ranges[3].minor = miscstat.minor;
  misc_deregister(&miscstat);
 }

 return ret;
}

static bool is_valid_dynamic_minor(int minor)
{
 if (minor < 0)
  return false;
 if (minor == MISC_DYNAMIC_MINOR)
  return false;
 if (minor >= 0 && minor <= 15)
  return false;
 if (minor >= 128 && minor < MISC_DYNAMIC_MINOR)
  return false;
 return true;
}

static int miscdev_test_open(struct inode *inode, struct file *file)
{
 return 0;
}

static const struct file_operations miscdev_test_fops = {
 .open = miscdev_test_open,
};

static void __init miscdev_test_can_open(struct kunit *test, struct miscdevice *misc)
{
 int ret;
 struct file *filp;
 char *devname;

 devname = kasprintf(GFP_KERNEL, "/dev/%s", misc->name);
 ret = init_mknod(devname, S_IFCHR | 0600,
    new_encode_dev(MKDEV(MISC_MAJOR, misc->minor)));
 if (ret != 0)
  KUNIT_FAIL(test, "failed to create node\n");

 filp = filp_open(devname, O_RDONLY, 0);
 if (IS_ERR_OR_NULL(filp))
  KUNIT_FAIL(test, "failed to open misc device: %ld\n", PTR_ERR(filp));
 else
  fput(filp);

 init_unlink(devname);
 kfree(devname);
}

static void __init miscdev_test_static_basic(struct kunit *test)
{
 struct miscdevice misc_test = {
  .name = "misc_test",
  .fops = &miscdev_test_fops,
 };
 int ret;
 const struct miscdev_test_case *params = test->param_value;

 misc_test.minor = params->minor;

 ret = misc_register(&misc_test);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor);

 if (ret == 0) {
  miscdev_test_can_open(test, &misc_test);
  misc_deregister(&misc_test);
 }
}

static void __init miscdev_test_dynamic_basic(struct kunit *test)
{
 struct miscdevice misc_test = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "misc_test",
  .fops = &miscdev_test_fops,
 };
 int ret;

 ret = misc_register(&misc_test);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc_test.minor));

 if (ret == 0) {
  miscdev_test_can_open(test, &misc_test);
  misc_deregister(&misc_test);
 }
}

static void miscdev_test_twice(struct kunit *test)
{
 struct miscdevice misc_test = {
  .name = "misc_test",
  .fops = &miscdev_test_fops,
 };
 int ret;
 const struct miscdev_test_case *params = test->param_value;

 misc_test.minor = params->minor;

 ret = misc_register(&misc_test);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor);
 if (ret == 0)
  misc_deregister(&misc_test);

 ret = misc_register(&misc_test);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor);
 if (ret == 0)
  misc_deregister(&misc_test);
}

static void miscdev_test_duplicate_minor(struct kunit *test)
{
 struct miscdevice misc1 = {
  .name = "misc1",
  .fops = &miscdev_test_fops,
 };
 struct miscdevice misc2 = {
  .name = "misc2",
  .fops = &miscdev_test_fops,
 };
 int ret;
 const struct miscdev_test_case *params = test->param_value;

 misc1.minor = params->minor;
 misc2.minor = params->minor;

 ret = misc_register(&misc1);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_EQ(test, misc1.minor, params->minor);

 ret = misc_register(&misc2);
 KUNIT_EXPECT_EQ(test, ret, -EBUSY);
 if (ret == 0)
  misc_deregister(&misc2);

 misc_deregister(&misc1);
}

static void miscdev_test_duplicate_name(struct kunit *test)
{
 struct miscdevice misc1 = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "misc1",
  .fops = &miscdev_test_fops,
 };
 struct miscdevice misc2 = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "misc1",
  .fops = &miscdev_test_fops,
 };
 int ret;

 ret = misc_register(&misc1);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor));

 ret = misc_register(&misc2);
 KUNIT_EXPECT_EQ(test, ret, -EEXIST);
 if (ret == 0)
  misc_deregister(&misc2);

 misc_deregister(&misc1);
}

/*
 * Test that after a duplicate name failure, the reserved minor number is
 * freed to be allocated next.
 */

static void miscdev_test_duplicate_name_leak(struct kunit *test)
{
 struct miscdevice misc1 = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "misc1",
  .fops = &miscdev_test_fops,
 };
 struct miscdevice misc2 = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "misc1",
  .fops = &miscdev_test_fops,
 };
 struct miscdevice misc3 = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "misc3",
  .fops = &miscdev_test_fops,
 };
 int ret;
 int dyn_minor;

 ret = misc_register(&misc1);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor));

 /*
 * Find out what is the next minor number available.
 */

 ret = misc_register(&misc3);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor));
 dyn_minor = misc3.minor;
 misc_deregister(&misc3);
 misc3.minor = MISC_DYNAMIC_MINOR;

 ret = misc_register(&misc2);
 KUNIT_EXPECT_EQ(test, ret, -EEXIST);
 if (ret == 0)
  misc_deregister(&misc2);

 /*
 * Now check that we can still get the same minor we found before.
 */

 ret = misc_register(&misc3);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor));
 KUNIT_EXPECT_EQ(test, misc3.minor, dyn_minor);
 misc_deregister(&misc3);

 misc_deregister(&misc1);
}

/*
 * Try to register a static minor with a duplicate name. That might not
 * deallocate the minor, preventing it from being used again.
 */

static void miscdev_test_duplicate_error(struct kunit *test)
{
 struct miscdevice miscdyn = {
  .minor = MISC_DYNAMIC_MINOR,
  .name = "name1",
  .fops = &miscdev_test_fops,
 };
 struct miscdevice miscstat = {
  .name = "name1",
  .fops = &miscdev_test_fops,
 };
 struct miscdevice miscnew = {
  .name = "name2",
  .fops = &miscdev_test_fops,
 };
 int ret;
 const struct miscdev_test_case *params = test->param_value;

 miscstat.minor = params->minor;
 miscnew.minor = params->minor;

 ret = misc_register(&miscdyn);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor));

 ret = misc_register(&miscstat);
 KUNIT_EXPECT_EQ(test, ret, -EEXIST);
 if (ret == 0)
  misc_deregister(&miscstat);

 ret = misc_register(&miscnew);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_EQ(test, miscnew.minor, params->minor);
 if (ret == 0)
  misc_deregister(&miscnew);

 misc_deregister(&miscdyn);
}

static void __init miscdev_test_dynamic_only_range(struct kunit *test)
{
 int ret;
 struct miscdevice *miscdev;
 const int dynamic_minors = 256;
 int i;

 miscdev = kunit_kmalloc_array(test, dynamic_minors,
     sizeof(struct miscdevice),
     GFP_KERNEL | __GFP_ZERO);

 for (i = 0; i < dynamic_minors; i++) {
  miscdev[i].minor = MISC_DYNAMIC_MINOR;
  miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i);
  miscdev[i].fops = &miscdev_test_fops;
  ret = misc_register(&miscdev[i]);
  if (ret != 0)
   break;
  /*
 * This is the bug we are looking for!
 * We asked for a dynamic minor and got a minor in the static range space.
 */

  if (miscdev[i].minor >= 0 && miscdev[i].minor <= 15) {
   KUNIT_FAIL(test, "misc_register allocated minor %d\n", miscdev[i].minor);
   i++;
   break;
  }
  KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor));
 }

 for (i--; i >= 0; i--) {
  miscdev_test_can_open(test, &miscdev[i]);
  misc_deregister(&miscdev[i]);
  kfree_const(miscdev[i].name);
 }

 KUNIT_EXPECT_EQ(test, ret, 0);
}

static void __init miscdev_test_collision(struct kunit *test)
{
 int ret;
 struct miscdevice *miscdev;
 struct miscdevice miscstat = {
  .name = "miscstat",
  .fops = &miscdev_test_fops,
 };
 const int dynamic_minors = 256;
 int i;

 miscdev = kunit_kmalloc_array(test, dynamic_minors,
     sizeof(struct miscdevice),
     GFP_KERNEL | __GFP_ZERO);

 miscstat.minor = miscdev_test_ranges[0].minor;
 ret = misc_register(&miscstat);
 KUNIT_ASSERT_EQ(test, ret, 0);
 KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor);

 for (i = 0; i < dynamic_minors; i++) {
  miscdev[i].minor = MISC_DYNAMIC_MINOR;
  miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i);
  miscdev[i].fops = &miscdev_test_fops;
  ret = misc_register(&miscdev[i]);
  if (ret != 0)
   break;
  KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor));
 }

 for (i--; i >= 0; i--) {
  miscdev_test_can_open(test, &miscdev[i]);
  misc_deregister(&miscdev[i]);
  kfree_const(miscdev[i].name);
 }

 misc_deregister(&miscstat);

 KUNIT_EXPECT_EQ(test, ret, 0);
}

static void __init miscdev_test_collision_reverse(struct kunit *test)
{
 int ret;
 struct miscdevice *miscdev;
 struct miscdevice miscstat = {
  .name = "miscstat",
  .fops = &miscdev_test_fops,
 };
 const int dynamic_minors = 256;
 int i;

 miscdev = kunit_kmalloc_array(test, dynamic_minors,
     sizeof(struct miscdevice),
     GFP_KERNEL | __GFP_ZERO);

 for (i = 0; i < dynamic_minors; i++) {
  miscdev[i].minor = MISC_DYNAMIC_MINOR;
  miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i);
  miscdev[i].fops = &miscdev_test_fops;
  ret = misc_register(&miscdev[i]);
  if (ret != 0)
   break;
  KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor));
 }

 KUNIT_EXPECT_EQ(test, ret, 0);

 miscstat.minor = miscdev_test_ranges[0].minor;
 ret = misc_register(&miscstat);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor);
 if (ret == 0)
  misc_deregister(&miscstat);

 for (i--; i >= 0; i--) {
  miscdev_test_can_open(test, &miscdev[i]);
  misc_deregister(&miscdev[i]);
  kfree_const(miscdev[i].name);
 }
}

static void __init miscdev_test_conflict(struct kunit *test)
{
 int ret;
 struct miscdevice miscdyn = {
  .name = "miscdyn",
  .minor = MISC_DYNAMIC_MINOR,
  .fops = &miscdev_test_fops,
 };
 struct miscdevice miscstat = {
  .name = "miscstat",
  .fops = &miscdev_test_fops,
 };

 ret = misc_register(&miscdyn);
 KUNIT_ASSERT_EQ(test, ret, 0);
 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor));

 /*
 * Try to register a static minor with the same minor as the
 * dynamic one.
 */

 miscstat.minor = miscdyn.minor;
 ret = misc_register(&miscstat);
 KUNIT_EXPECT_EQ(test, ret, -EBUSY);
 if (ret == 0)
  misc_deregister(&miscstat);

 miscdev_test_can_open(test, &miscdyn);

 misc_deregister(&miscdyn);
}

static void __init miscdev_test_conflict_reverse(struct kunit *test)
{
 int ret;
 struct miscdevice miscdyn = {
  .name = "miscdyn",
  .minor = MISC_DYNAMIC_MINOR,
  .fops = &miscdev_test_fops,
 };
 struct miscdevice miscstat = {
  .name = "miscstat",
  .fops = &miscdev_test_fops,
 };

 /*
 * Find the first available dynamic minor to use it as a static
 * minor later on.
 */

 ret = misc_register(&miscdyn);
 KUNIT_ASSERT_EQ(test, ret, 0);
 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor));
 miscstat.minor = miscdyn.minor;
 misc_deregister(&miscdyn);

 ret = misc_register(&miscstat);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_EQ(test, miscstat.minor, miscdyn.minor);

 /*
 * Try to register a dynamic minor after registering a static minor
 * within the dynamic range. It should work but get a different
 * minor.
 */

 miscdyn.minor = MISC_DYNAMIC_MINOR;
 ret = misc_register(&miscdyn);
 KUNIT_EXPECT_EQ(test, ret, 0);
 KUNIT_EXPECT_NE(test, miscdyn.minor, miscstat.minor);
 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor));
 if (ret == 0)
  misc_deregister(&miscdyn);

 miscdev_test_can_open(test, &miscstat);

 misc_deregister(&miscstat);
}

static struct kunit_case test_cases[] = {
 KUNIT_CASE(kunit_dynamic_minor),
 KUNIT_CASE(kunit_static_minor),
 KUNIT_CASE(kunit_misc_dynamic_minor),
 KUNIT_CASE_PARAM(miscdev_test_twice, miscdev_gen_params),
 KUNIT_CASE_PARAM(miscdev_test_duplicate_minor, miscdev_gen_params),
 KUNIT_CASE(miscdev_test_duplicate_name),
 KUNIT_CASE(miscdev_test_duplicate_name_leak),
 KUNIT_CASE_PARAM(miscdev_test_duplicate_error, miscdev_gen_params),
 {}
};

static struct kunit_suite test_suite = {
 .name = "miscdev",
 .suite_init = miscdev_find_minors,
 .test_cases = test_cases,
};
kunit_test_suite(test_suite);

static struct kunit_case __refdata test_init_cases[] = {
 KUNIT_CASE_PARAM(miscdev_test_static_basic, miscdev_gen_params),
 KUNIT_CASE(miscdev_test_dynamic_basic),
 KUNIT_CASE(miscdev_test_dynamic_only_range),
 KUNIT_CASE(miscdev_test_collision),
 KUNIT_CASE(miscdev_test_collision_reverse),
 KUNIT_CASE(miscdev_test_conflict),
 KUNIT_CASE(miscdev_test_conflict_reverse),
 {}
};

static struct kunit_suite test_init_suite = {
 .name = "miscdev_init",
 .suite_init = miscdev_find_minors,
 .test_cases = test_init_cases,
};
kunit_test_init_section_suite(test_init_suite);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vimal Agrawal");
MODULE_AUTHOR("Thadeu Lima de Souza Cascardo ");
MODULE_DESCRIPTION("Test module for misc character devices");

Messung V0.5
C=94 H=86 G=89

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.