无法卸载内核扩展;类有实例 [英] Can't Unload Kernel Extension; Classes Have Instances

查看:132
本文介绍了无法卸载内核扩展;类有实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm writing an OSX kernel extension for an audio device driver (it's software, but emulates a hardware device).

在开发过程中,完全卸载现有的旧版本,然后从头开始构建并安装新版本会很方便.但是,有时在没有重新启动系统的情况下这是不可能的.

During development, it'd be convenient to completely uninstall existing old versions and then build and install the new version from scratch. However, this occasionally seems to not be possible without a system restart.

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

The program itself is not running and the source files have been deleted from the /System/Library/Extensions/ dir.

但是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有时会失败,并抱怨现有实例:

So there are 0 Refs to my driver instance, but kextunload will sometimes fail, complaining of existing instances:

$ 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(据我所知).

When this happens, there's no way to "force" unload the kext (that I know of).

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

Am I right in guessing that this single instance still exists because of a reference held in memory by the running OS kernel? That doesn't seem right, because then kextunload would always fail. So why does kextunload only sometimes require a system restart to "fully" unload all driver instances?

推荐答案

为IOKit kext运行kextunload(如果没有其他kext依赖它)将导致内核尝试terminate()该类中的任何类实例I/O Kit注册表中的kext.然后它将稍等片刻,然后检查该kext的任何类是否仍具有实例.如果没有,它将卸载kext.如果仍然存在实例,则kextunload会失败(不过,终止的实例仍保持终止状态;这意味着我不会在其提供程序上重新运行I/O套件匹配).

Running kextunload for an IOKit kext will (if no other kexts depend on it) cause the kernel to attempt to terminate() any instances of classes in that kext which are in the I/O Kit registry. It will then wait a bit and check if any of that kext's classes still have instances. If not, it will unload the kext. If instances remain, kextunload fails (the terminated instances stay terminated, though; by this I mean that I/O kit matching is not re-run on their providers).

所以以某种方式,您仍然可以使用实时实例.

So somehow, you're still ending up with live instances.

  • 一种可能性是您的对象拒绝使用terminate().如果他们的客户不会放弃控制权,例如发生这种情况,就会发生这种情况.您不能为顶部装有已挂载文件系统的磁盘卸载驱动程序.不响应终止消息的用户空间客户端是另一个示例.

  • One possibility is that your objects are refusing to terminate(). This can happen if they have clients that won't give up control, e.g. you can't unload the driver for a disk with a mounted file system on top. Userspace clients that don't respond to termination messages are another example.

否则,实例终止,但不释放.因为它们似乎属于您的两个主要驱动程序类,所以如果您没有任何不会放弃其主张的用户客户,那么我将不胜枚举,建议您可能有一个循环参考. .如果不是那样,您只需寻找与release()不匹配的retain().我在此答案中给出了一些如何在上进行跟踪的提示.

Otherwise, the instances terminate, but are not freed. Since they seem to be of two of your main driver classes, if you don't have any user clients that won't give up their claim, I'm going to go out on a limb and suggest that you might have a circular reference. If that's not it, you'll just have to hunt for retain()s which are not matched by a release(). I give some tips on how to track these down in this answer.

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

If the instances terminate and are deregistered, they will no longer appear in the output of the ioreg commandline tool, so that's an easy way of checking which of the two cases applies here.

这篇关于无法卸载内核扩展;类有实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆