2015-04-01 9 views
1

Мой вопрос в двух словах:Publishing IOMedia без основной IOBlockStorageDevice

ли это приемлемо/обычная практика для Kext опубликовать объект IOMedia, который не имеет в IOBlockStorageDevice в своих поставщиков стек?

фон:

Я пишу Kext, который будет предоставлять какое-то виртуальное устройство в пользовательское пространство. В настоящее время у меня есть драйвер, который соответствует IOResources, а затем создает объект класса, полученный из IOMedia, и прикрепляет его к «этому». После публикации этого медиа-объекта стандартный IOMediaBSDClient присоединяется к нему и создает узел в/dev /.

Первые тесты прошли хорошо, я смог успешно открыть созданное устройство и прочитать данные с него, но когда я попытался установить его с помощью родных драйверов FS, я наткнулся на проблему. Устройство было смонтировано успешно, и точка монтирования была доступна для просмотра, но через некоторое время ядро ​​запаниковало из-за segfault, глубоко внутри кода vfs.

После долгой отладки я обнаружил, корни проблемы:

  1. IOMediaBSDClient реализует DKIOCGETTHROTTLEMASK IOCTL перебирая объектов IOBlockStorageDevice в СМИ родителей, а затем итерации по всем объектам СМИ, которые предоставляются этими устройствами и сочетающих их Номера BSD в битовой маске. Поскольку у моего Media нет родительских объектов IOBlockStorageDevice, полученная маска равна 0.
  2. Значение, возвращаемое этим ioctl, используется vfs_init_io_attributes(), чтобы заполнить поле mnt_throttle_mask структуры mp, соответствующее моему монтированию.
  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. Очевидно, что доступ к 64 элементам _throttle_io_info разбивает данные, расположенные сразу после него, что в моем случае является массивом speclisth.

На данный момент я вижу 2 пути, чтобы исправить это в моем коде: 1. Реализовать класс, производный от IOMediaBSDClient, который будет обрабатывать DKIOCGETTHROTTLEMASK IOCTL corrrectly. 2. Перепишите код, чтобы опубликовать объект IOBlockStorageDevice, и позвольте стандарту IOBlockStorageDriver опубликовать объект Media.

Лично мне нравится первое решение лучше, но проблема, с которой я столкнулась, кажется довольно хардкорной, и я не могу избавиться от мыслей, что я делаю что-то принципиально неправильное.

Я хотел бы избежать таких проблем в будущем, поэтому я задаю этот вопрос.

EDIT: это верно, по крайней мере, для OS X 10.8.3 и 10.8.5. Я еще не тестировал это в других релизах.

ответ

0

Я бы, вероятно, пошел с подклассом IOBlockStorageDevice. Я написал несколько драйверов таким образом и никогда не сталкивался с какими-либо проблемами. Прямые драйверы IOStorage/IOMedia подходят для «фильтрующих» драйверов (управление логическим томом, RAID, шифрование и т. Д.).- все, что сидит поверх «реальных» блочных устройств), но, как вы нашли, некоторые области ОС ожидают основания IOBlockStorageDriver/IOBlockStorageDevice.

Преобразование из IOStorage в IOBlockStorageDevice довольно просто: имена методов в значительной степени префиксны «делать» или «сообщать» и почти точно совпадают с семантически иначе. Вероятно, это сэкономит вам неприятность в долгосрочной перспективе. Не создавайте объект IOBlockStorageDriver самостоятельно - соответствие набора входов/выходов создаст его для вас, как только вы вызовете registerService() на свой экземпляр подкласса IOBlockStorageDevice.

Есть несколько примеров, плавающие вокруг, в том числе очень простой в книге OS X and iOS[sic] Kernel Programming - даже если у вас нет книги, вы можете получить код примера here - глава 14.

+0

Спасибо за ваш ответ. Я преобразовал код в подкласс IOBlockStorageDevice, и теперь он отлично работает. В любом случае, это похоже на единственный вариант в этом случае, потому что после некоторого исследования я обнаружил, что нельзя просто переопределить DKIOCGETTHROTTLEMASK ioctl в IOMediaBSDClient, поскольку он обрабатывается непосредственно в функции dkioctl. –

+0

Рад, что вы все разобрались! Я ранее не знал о проблеме с DKIOCGETTHROTTLEMASK, вы узнаете что-то новое каждый день. :-) – pmdj