【问题标题】:Linux Kernel Modules: When to use try_module_get / module_putLinux 内核模块:何时使用 try_module_get / module_put
【发布时间】:2009-11-16 10:50:32
【问题描述】:

我正在阅读 LKMPG (See Section 4.1.4. Unregistering A Device),我不清楚何时使用 try_module_get / module_put 函数。有些 LKMPG 示例使用它们,有些则没有。

更令人困惑的是,try_module_get 在 2.6.24 源代码的 193 个文件中出现了 282 次,但在 Linux Device Drivers ( LDD3 )Essential Linux Device Drivers 中,它们甚至没有出现在一个代码示例中。

我想他们可能是绑定到旧的register_chrdev 接口(在 2.6 中被 cdev 接口取代),但它们只一起出现在同一个文件中 8 次:

find -type f -name *.c | xargs grep -l try_module_get | sort -u | xargs grep -l register_chrdev | sort -u | grep -c .

那么什么时候适合使用这些功能?它们是否与特定界面或一组环境的使用相关联?

编辑

我从 LKMPG 加载了sched.c 示例并尝试了以下实验:

anon@anon:~/kernel-source/lkmpg/2.6.24$ tail /proc/sched -f &
Timer called 5041 times so far
[1] 14594

anon@anon:~$ lsmod | grep sched
sched                   2868  1 

anon@anon:~$ sudo rmmod sched
ERROR: Module sched is in use

这让我相信内核现在可以自己记账,而gets/puts可能已经过时了。任何人都可以验证这一点吗?

【问题讨论】:

  • 在第 14 章,reference count manipulation 小节(第 367 页)中出现了一次 try_module_get
  • 我的意思是我之前评论中的 LDD 书

标签: linux-kernel linux-device-driver kernel-module


【解决方案1】:

您应该永远不必使用 try_module_get(THIS_MODULE);几乎所有这样的使用都是不安全的,因为如果你已经在你的模块中,那么增加引用计数为时已晚——总会有一个(小)窗口,你在模块中执行代码但没有增加引用数数。如果有人在该窗口中完全删除了模块,那么您将处于在卸载模块中运行代码的糟糕情况。

您在 LKMPG 中链接的特定示例,其中代码在 open() 方法中执行 try_module_get() 将在现代内核中通过设置 struct file_operations 中的 .owner 字段来处理:

struct file_operations fops = {
        .owner = THIS_MODULE,
        .open = device_open,
        //...
};

这将使 VFS 代码在调用它之前获取对模块的引用,从而消除了不安全的窗口——try_module_get() 将在调用 .open() 之前成功,否则 try_module_get() 将失败,VFS 将永远不会调用模块。无论哪种情况,我们都不会从已卸载的模块中运行代码。

使用 try_module_get() 的唯一好时机是当你想在调用它或以某种方式使用它之前对一个 不同 模块进行引用(例如文件打开代码在我上面解释的例子)。在内核源代码中有许多 try_module_get(THIS_MODULE) 的用法,但如果不是全部的话,大多数都是应该清理的潜在错误。

您无法卸载 sched 示例的原因是您的

$ tail /proc/sched -f &

命令保持 /proc/sched 打开,因为

        Our_Proc_File->owner = THIS_MODULE;

在 sched.c 代码中,打开 /proc/sched 会增加 sched 模块的引用计数,这说明 lsmod 显示的 1 个引用。通过快速浏览其余代码,我认为如果您通过终止 tail 命令释放 /proc/sched,您将能够删除 sched 模块。

【讨论】:

  • --- 好吧,我最近在做看门狗设备驱动时知道,有一个特性叫做 no-way-out,这意味着一旦这个设备启动,你就无法停止它。由于这个原因,这个模块无法被卸载,所以,在设备驱动的 open() 实现中,使用了一个 __module_get(THIS_MODULE),对于设备驱动模块,我们知道,当一个模块的引用计数不为零时,你不能卸载它。总而言之,也许这是您需要使用module_get、module_put等的情况。谢谢。
  • 来自init_module 函数的try_module_get 是安全的,但匹配的module_put 必须在cleanup_module 之前的某个时间点完成。
  • 这些引用计数功能仍然存在的目的是什么?
  • 有一些安全时间可以增加自身模块的数量。一个例子是在 proc 文件的 open()release() 中增加和减少它,因为 proc 文件操作受到保护,不会被模块删除。
猜你喜欢
  • 2020-08-29
  • 2012-04-11
  • 2013-12-17
  • 1970-01-01
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
相关资源
最近更新 更多