cdev_alloc() 对比 cdev_init()

cdev_alloc() vs cdev_init()

在 Linux 内核模块中,创建 struct cdev 时可以遵循两种不同的方法,如 this site and in this answer:

中所建议

第一种方法cdev_alloc()

struct cdev *my_dev;
...
static int __init example_module_init(void) {
    ...
    my_dev = cdev_alloc();
    if (my_dev != NULL) {
            my_dev->ops = &my_fops;  /* The file_operations structure */
            my_dev->owner = THIS_MODULE;
        }
        else
                ...
}

第二种方法,cdev_init()

static struct cdev my_cdev;
...
static int __init example_module_init(void) {
        ...
        cdev_init(&my_cdev, my_fops);
        my_cdev.owner = THIS_MODULE;
        ...
}

(假设 my_fops 是指向已初始化 struct file_operations 的指针)。

  1. 第一种方法是已弃用还是仍在使用?
  2. 第一种方法 cdev_alloc() 也可以使用 cdev_init() 吗?如果不是,为什么?

第二个问题也在linked answer的评论里。

他们做不同的事情。偏好是通常的 - 不需要时不使用动态分配,而在可能的情况下在堆栈上分配。

cdev_alloc()动态分配my_dev,所以在cdev_del().

时会调用kfree(pointer)

cdev_init() 不会释放指针。

最重要的是,结构my_cdev的生命周期不同。在 cdev_init() 情况下 struct cdev my_cdev 绑定到包含的词法范围,而 cdev_alloc() returns 动态分配指针直到 free-d 有效。

Can cdev_init() be used also in the first approach, with cdev_alloc()?

不,cdev_init不应该用于字符设备,分配为cdev_alloc

在某种程度上,cdev_alloc 相当于 kmalloc 加上 cdev_init。因此,为使用 cdev_alloc 创建的字符设备调用 cdev_init 没有任何意义。

此外,分配有 cdev_alloc 的字符设备包含一个 提示,该设备应该 解除分配 当不再被分配时用过的。为该设备调用 cdev_init 将清除该提示,因此您将得到 内存泄漏


cdev_initcdev_alloc 之间的选择取决于您希望字符设备拥有的生命周期

通常,人们希望字符设备的生命周期与模块的生命周期相同。在那种情况下:

  1. 定义类型为 struct cdev 的静态或全局变量。
  2. 使用cdev_init.
  3. 在模块的init函数中创建字符设备
  4. 使用cdev_del.
  5. 在模块的exit函数中销毁字符设备
  6. 确保字符设备的文件操作将 .owner 字段设置为 THIS_MODULE

在复杂的情况下,希望在模块初始化后的特定点创建一个字符设备。例如。模块可以为某些硬件提供驱动程序,而字符设备应该与该硬件绑定。在那种情况下,字符设备无法在模块的 init 函数中创建(因为尚未检测到硬件),更重要的是,字符设备无法在模块的 exit 函数中销毁。在那种情况下:

  1. 在结构中定义一个字段,描述硬件,指针类型struct cdev*
  2. 在创建(探测)硬件的函数中使用cdev_alloc创建字符设备。
  3. 在销毁(断开)硬件的函数中用cdev_del销毁字符设备

第一种情况 cdev_del 在字符设备 未被用户使用 时被调用。 THIS_MODULE在文件操作中提供了这种保证:如果用户打开了与字符设备对应的文件,则无法卸载模块。

在第二种情况下没有这样的保证(因为 cdev_del 在模块的退出函数中被调用 NOT)。所以,在cdev_delreturns的时候,一个字符设备可能还在被用户使用。这里 cdev_alloc 真的很重要:字符设备的 释放 延迟 直到用户关闭与字符设备关联的所有文件描述符.没有 cdev_alloc.

就无法获得这种行为