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

10
我正在为音频设备驱动程序编写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>

(...meaning:)

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

所以我的驱动程序实例没有引用,但是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。 我猜想,这个单一实例之所以仍然存在,是因为运行中的操作系统内核中保存了对它的引用吗?但这似乎不正确,因为那样的话,kextunload 将总是失败。那么,为什么 kextunload 只有在有时需要系统重启才能“完全”卸载所有驱动程序实例呢?
1个回答

11

运行 kextunload 命令会使内核尝试终止在 I/O Kit 注册表中的 kext 中所有类的实例 (如果没有其它依赖该kext的kext存在)。然后,它会等待一段时间并检查该kext的类是否仍然有实例。如果没有实例,则卸载该kext。如果仍有实例,则 kextunload 失败 (被终止的实例保持终止状态,这意味着I/O kit匹配不会再次运行他们的提供者)。

所以你仍然有活动实例存在,有以下两种可能性:

  • 一种可能是你的对象拒绝执行 terminate() 方法。这种情况可能发生在它们有客户端无法放弃控制权的情况下,例如无法卸载具有挂载文件系统的磁盘驱动程序。用户空间客户端不响应终止消息也是另一个例子。

  • 否则,实例已经被终止但未被释放。由于它们似乎属于两个主要的驱动程序类别之一,如果您没有任何无法放弃其声明权的用户客户端,则我建议您可能存在循环引用。如果不是这样,您只需寻找没有被匹配的 retain(),并使用 release() 进行匹配。我在这个答案中提供了一些跟踪它们的技巧。

如果实例已被终止并注销,则不再出现在 ioreg 命令行工具的输出中,因此这是检查两种情况适用哪种的简单方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接