在没有底层 IOBlockStorageDevice 的情况下发布 IOMedia

Publishing IOMedia without underlying IOBlockStorageDevice

我的问题简而言之:

KEXT 发布其提供程序堆栈中没有 IOBlockStorageDevice 的 IOMedia 对象是否是一种acceptable/common做法?

背景:

我正在编写一个 kext,它将为用户空间提供某种虚拟设备。 目前我有一个匹配 IOResources 的驱动程序,然后创建一个从 IOMedia 派生的 class 对象并将其附加到 'this'。发布此媒体对象后,标准 IOMediaBSDClient 附加到它并在 /dev/ 中创建一个节点。

第一次测试顺利通过,我可以成功打开创建的设备并从中读取数据,但是当我尝试使用本机 FS 驱动程序挂载它时,我遇到了问题。设备已成功挂载且挂载点可浏览,但不久之后内核因 vfs 代码深处的段错误而崩溃。

经过长时间的调试,我找到了问题的根源:

  1. IOMediaBSDClient 通过遍历 Media parents 中的 IOBlockStorageDevice 对象,然后遍历这些设备提供的所有 Media 对象并将它们的 BSD 单元号组合成位掩码来实现 DKIOCGETTHROTTLEMASK ioctl。由于我的媒体没有任何 IOBlockStorageDevice 父级,因此生成的掩码为 0。
  2. vfs_init_io_attributes() 使用此 ioctl 返回的值来填充对应于我的挂载的 mp 结构的 mnt_throttle_mask 字段。
  3. 紧接着,mnt_throttle_mask通过计算其中的尾随零被转换为mnt_devbsdunit。因为在我的例子中 mnt_throttle_mask 是 0,所以 mnt_devbsdunit 变成 64.
  4. mnt_devbsdunit 被 spec_strategy(以及其他一些处理节流的函数)用作 _throttle_io_info 中的元素编号,它是 LOWPRI_MAX_NUM_DEV 元素的数组,并且LOWPRI_MAX_NUM_DEV 等于 64。 显然,访问 _throttle_io_info 的 64 元素会破坏紧随其后的数据,在我的例子中是 speclisth 数组。

目前,我在代码中看到了两种解决此问题的方法: 1. 实施派生自 IOMediaBSDClient 的 class,它将正确处理 DKIOCGETTHROTTLEMASK ioctl。 2.重写代码发布一个IOBlockStorageDevice对象,让标准的IOBlockStorageDriver发布Media对象。

就我个人而言,我更喜欢第一个解决方案,但我遇到的问题似乎很核心,我无法摆脱我做的根本错误的想法。

我想避免以后出现这样的问题,所以才问这个问题。

编辑:至少对于 OS X 10.8.3 和 10.8.5 是这样。我还没有在其他版本上对此进行测试。

我可能会选择 IOBlockStorageDevice 子类。我已经用这种方法编写了一些驱动程序,并且从未 运行 遇到过任何问题。直接 IOStorage/IOMedia 驱动程序适用于 "filter" 驱动程序(逻辑卷管理、RAID、加密等 - 位于 "real" 块设备之上的任何内容)但正如您所发现的,某些领域OS 期望 IOBlockStorageDriver/IOBlockStorageDevice 基金会。

IOStorage 转换为 IOBlockStorageDevice 非常简单:方法名称几乎都带有 "do" 或 "report" 前缀,否则在语义上几乎完全相同。在漫长的 运行 中,它可能会为您省去一些麻烦。不要自己创建 IOBlockStorageDriver 对象 - I/O 套件匹配会在您对 IOBlockStorageDevice 子类实例调用 registerService() 时立即为您创建它。

周围有一些示例,包括书 OS X and iOS[sic] Kernel Programming - even if you don't have the book, you can get the example code here - 第 14 章中的一个非常简单的示例。