【发布时间】:2015-04-01 21:36:52
【问题描述】:
简而言之我的问题:
KEXT 发布在其提供程序堆栈中没有 IOBlockStorageDevice 的 IOMedia 对象是否可接受/常见做法?
背景:
我正在编写一个 kext,它将为用户空间提供某种虚拟设备。 目前我有一个匹配 IOResources 的驱动程序,然后创建一个从 IOMedia 派生的类对象并将其附加到“this”。发布此媒体对象后,标准 IOMediaBSDClient 会附加到它并在 /dev/ 中创建一个节点。
第一次测试顺利通过,我可以成功打开创建的设备并从中读取数据,但是当我尝试使用本机 FS 驱动程序挂载它时,我偶然发现了一个问题。设备已成功挂载,挂载点可浏览,但不久之后,内核因 vfs 代码深处的段错误而崩溃。
经过长时间的调试,我找到了问题的根源:
- IOMediaBSDClient 实现 DKIOCGETTHROTTLEMASK ioctl,方法是遍历 Media 父级中的 IOBlockStorageDevice 对象,然后遍历这些设备提供的所有 Media 对象,并将它们的 BSD 单元编号组合成一个位掩码。由于我的媒体没有任何 IOBlockStorageDevice 父级,因此生成的掩码为 0。
- 这个 ioctl 返回的值被 vfs_init_io_attributes() 用来填充我的 mount 对应的 mp struct 的 mnt_throttle_mask 字段。
- 紧接着,mnt_throttle_mask 通过计算其中的尾随零转换为 mnt_devbsdunit。由于在我的情况下 mnt_throttle_mask 为 0,因此 mnt_devbsdunit 变为 64。
- mnt_devbsdunit 被 spec_strategy(以及其他一些处理节流的函数)用作 _throttle_io_info 中的元素编号,它是 LOWPRI_MAX_NUM_DEV 元素的数组,LOWPRI_MAX_NUM_DEV 等于 64。 显然,访问 _throttle_io_info 的 64 个元素会破坏位于它后面的数据,在我的例子中是 speclisth 数组。
目前,我在代码中看到了两种解决此问题的方法: 1. 实现一个派生自 IOMediaBSDClient 的类,该类将正确处理 DKIOCGETTHROTTLEMASK ioctl。 2、重写代码发布IOBlockStorageDevice对象,让标准IOBlockStorageDriver发布Media对象。
就个人而言,我更喜欢第一个解决方案,但我遇到的问题似乎相当顽固,我无法摆脱我做某事根本错误的想法。
我想避免以后出现这样的问题,所以我问这个问题。
编辑:至少对于 OS X 10.8.3 和 10.8.5 是这样。我还没有在其他版本上对此进行测试。
【问题讨论】:
标签: macos kernel iokit kernel-extension