【问题标题】:Publishing IOMedia without underlying IOBlockStorageDevice在没有底层 IOBlockStorageDevice 的情况下发布 IOMedia
【发布时间】:2015-04-01 21:36:52
【问题描述】:

简而言之我的问题:

KEXT 发布在其提供程序堆栈中没有 IOBlockStorageDevice 的 IOMedia 对象是否可接受/常见做法?

背景:

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

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

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

  1. IOMediaBSDClient 实现 DKIOCGETTHROTTLEMASK ioctl,方法是遍历 Media 父级中的 IOBlockStorageDevice 对象,然后遍历这些设备提供的所有 Media 对象,并将它们的 BSD 单元编号组合成一个位掩码。由于我的媒体没有任何 IOBlockStorageDevice 父级,因此生成的掩码为 0。
  2. 这个 ioctl 返回的值被 vfs_init_io_attributes() 用来填充我的 mount 对应的 mp struct 的 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 的类,该类将正确处理 DKIOCGETTHROTTLEMASK ioctl。 2、重写代码发布IOBlockStorageDevice对象,让标准IOBlockStorageDriver发布Media对象。

就个人而言,我更喜欢第一个解决方案,但我遇到的问题似乎相当顽固,我无法摆脱我做某事根本错误的想法。

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

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

【问题讨论】:

    标签: macos kernel iokit kernel-extension


    【解决方案1】:

    我可能会选择IOBlockStorageDevice 子类。我以这种方式编写了一些驱动程序,从未遇到任何问题。直接 IOStorage/IOMedia 驱动程序适用于“过滤”驱动程序(逻辑卷管理、RAID、加密等 - 位于“真实”块设备之上的任何东西),但正如您所发现的,操作系统的某些区域需要 @987654324 @/IOBlockStorageDevice基金会。

    IOStorage 转换为IOBlockStorageDevice 非常简单:方法名称几乎都带有“do”或“report”前缀,并且在语义上几乎完全相同。从长远来看,它可能会为您节省一些麻烦。不要自己创建 IOBlockStorageDriver 对象 - 只要您在 IOBlockStorageDevice 子类实例上调用 registerService(),匹配的 I/O Kit 就会为您创建它。

    有一些例子在流传,包括书中OS X and iOS[sic] Kernel Programming中的一个非常简单的例子——即使你没有这本书,你也可以得到例子代码here——第14章。

    【讨论】:

    • 感谢您的回答。我将代码转换为 IOBlockStorageDevice 子类,现在它工作正常。无论如何,这似乎是这种情况下的唯一选择,因为经过一番调查,我发现不能简单地在 IOMediaBSDClient 中重新实现 DKIOCGETTHROTTLEMASK ioctl,因为它是直接在 dkioctl 函数中处理的。
    • 很高兴你把一切都搞定了!我以前不知道 DKIOCGETTHROTTLEMASK 的问题,你每天都会学到新东西。 :-)
    猜你喜欢
    • 2020-08-25
    • 1970-01-01
    • 1970-01-01
    • 2013-02-18
    • 2013-05-23
    • 2019-09-13
    • 2013-12-03
    • 2017-02-04
    • 1970-01-01
    相关资源
    最近更新 更多