无法卸载内核扩展;类具有实例

时间:2012-11-23 23:43:06

标签: macos kernel-module kernel kernel-extension

我正在为音频设备驱动程序(它的软件,但模拟硬件设备)编写OSX内核扩展。

在开发过程中,可以方便地完全卸载现有的旧版本,然后从头开始构建和安装新版本。但是,如果没有重新启动系统,有时似乎无法进行此操作。

程序本身未运行且源文件已从/System/Library/Extensions/目录中删除。

但是kextstat显示了一个实例:

$ kextstat | grep 'com.foo.driver.bar'
219 0 0xfff123 0x5000 0x5000 com.foo.driver.bar (0.0.1) <102 5 4 3>

(...这意味着:)

Index Refs Address Size Wired Name (Version) <Linked Against>

因此我的驱动程序实例有0个引用,但kextunload有时会失败,抱怨现有实例:

$ sudo kextunload -b com.foo.driver.bar
(kernel) Can't unload kext com.foo.driver.bar; classes have instances:
(kernel)     Kext com.foo.driver.bar class FooBarDriver has 1 instance.
(kernel)     Kext com.foo.driver.bar class com_foo_driver_bar has 1 instance.
Failed to unload com.foo.driver.bar - (libkern/kext) kext is in use or retained (cannot unload).

当发生这种情况时,没有办法“强行”卸载kext(我知道)。

我是否正确地猜测这个单一实例仍然存在,因为运行的OS内核在内存中保存了引用?这似乎不对,因为kextunload总会失败。那么为什么kextunload有时只需要重新启动系统来“完全”卸载所有驱动程序实例?

1 个答案:

答案 0 :(得分:11)

为IOKit kext运行kextunload(如果没有其他关键字依赖于它)会导致内核尝试terminate()该文件夹中I / O Kit注册表中任何类的实例。然后它会稍等一下,检查一下这个kext的类是否还有实例。如果没有,它将卸载kext。如果实例仍然存在,则kextunload失败(终止的实例会终止;但是,我的意思是I / O工具包匹配不会在其提供商上重新运行)。

所以不知何故,你仍然以实时实例结束。

  • 一种可能是您的对象拒绝terminate()。如果他们的客户端不会放弃控制权,例如,您无法卸载顶部装有文件系统的磁盘的驱动程序。不响应终止消息的用户空间客户端是另一个例子。

  • 否则,实例会终止,但不会被释放。因为它们似乎是你的两个主要驱动程序类,如果你没有任何用户客户端不会放弃他们的声明,我会打算走出困境并建议你可能有一个循环引用。如果不是这样,你只需要寻找与retain()不匹配的release()。我提供了一些关于如何跟踪这些问题的提示in this answer

如果实例终止并取消注册,它们将不再出现在ioreg命令行工具的输出中,因此这是检查这两种情况中哪一种适用的简单方法。