14.2. Низкоуровневые операции в sysfs |
Kobject-ы являются механизмом, стоящим за виртуальной файловой системой sysfs. Для каждого каталога, находящегося в sysfs, существует kobject, скрывающийся где-то в ядре. Каждый kobject интересен также экспортом одного или более атрибутов, которые появляются в каталоге sysfs kobject-а как файлы, содержащие генерируемую ядром информацию. В этом разделе рассматривается, как kobject-ы и sysfs взаимодействуют на низком уровне.
Код, который работает с sysfs, должен подключать .
Появление kobject-а в sysfs - это просто вопрос вызова kobject_add. Мы уже видели эту функцию, как способ добавить kobject к kset-у; создание записей в sysfs также является частью её работы. Есть несколько моментов, которые стоит знать, как создаётся запись в sysfs:
• | Записями sysfs для kobject-ов всегда являются каталоги, поэтому вызов kobject_add в результате создаёт каталог в sysfs. Обычно это каталог, содержащий один или более атрибутов; в ближайшее время мы увидим, как определяются эти атрибуты. |
• | Имя, присвоенное kobject-у (с помощью kobject_set_name), является именем, используемым для каталога в sysfs. Таким образом, kobject-ы, которые появляются в одной части иерархии sysfs, должны иметь уникальные имена. Имена, данные kobject-ам, должны быть также разумными именами файлов: они не могут содержать символ "косая черта" (slash), а также настоятельно не рекомендуется использование пробелов. |
• | Запись sysfs находится в каталоге, соответствующем указателю parent kobject-а. Если при вызове kobject_add parent является NULL, он устанавливается на kobject, внедрённый в новый kset kobject-а; таким образом, иерархия sysfs обычно соответствует внутренней иерархии, созданной kset-ми. Если и parent и kset установлены в NULL, каталог sysfs создаётся на высшем уровне, который почти наверняка не то, что вы хотите. |
Используя механизмы, которые мы описывали до сих пор, мы можем использовать kobject для создания пустого каталога в sysfs. Как правило, вы хотите сделать что-то более интересное, чем это, так что пришло время посмотреть на реализацию атрибутов.
При создании каждого kobject-а даётся набор атрибутов по умолчанию. Эти атрибуты задаются структурой kobj_type. Напомним, что эта структура выглядит следующим образом:
struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
};
Поле default_attrs перечисляет атрибуты, которые будут созданы для каждого kobject-а этого типа, а sysfs_ops предоставляет методы для реализации этих атрибутов. Мы начнём с default_attrs, который указывает на массив указателей на структуры attribute:
struct attribute {
char *name;
struct module *owner;
mode_t mode;
};
В этой структуре name является именем атрибута (как он показывается в каталог sysfs kobject-а), owner является указателем на модуль (если таковой имеется), который отвечает за реализацию этого атрибута, и mode (режим) представляет собой защитные биты, которые будут применяться к этому атрибуту. Режим, как правило, S_IRUGO для атрибутов, предназначенных только для чтения; если атрибут доступен для записи, вы можете добавить в него S_IWUSR, чтобы дать доступ на запись только суперпользователю (макросы для режимов определены в ). Последняя запись в списке default_attrs должна быть заполнена нулями.
Массив default_attrs говорит, какие атрибуты есть, но не говорит sysfs, как на самом деле реализовать эти атрибуты. Эта задача возложена на поле kobj_type->sysfs_ops, которое указывает на структуру, определённую следующим образом:
struct sysfs_ops {
ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
char *buffer);
ssize_t (*store)(struct kobject *kobj, struct attribute *attr,
const char *buffer, size_t size);
};
Всякий раз, когда из пользовательского пространства читается атрибут, вызывается метод show с указателем на kobject и соответствующую структуру attribute. Этот метод должен закодировать значение данного атрибута в буфер, будучи уверенным, что его не переполнил (он имеет PAGE_SIZE байт), и вернуть фактическую длину возвращаемых данных. Соглашения для sysfs заявляют, что каждый атрибут должен содержать единственное, доступное для человеческого понимания значение; если у вас для возвращения есть много информации, вы можете захотеть рассмотреть возможность её разделения на несколько атрибутов.
Для всех атрибутов, связанных с данным kobject-ом, используется тот же самый метод show. Указатель attr, передаваемый в функцию, может быть использован для определения, какой атрибут был запрошен. Те же методы show включают в себя наборы тестов по имени атрибута. Другие реализации внедряют структуру attribute внутрь другой структуры, которая содержит информацию, необходимую для возврата значения атрибута; в этом случае для получения указателя на вложенную структуру внутри метода show может быть использована container_of.
Метод store аналогичен; он должен декодировать данные, хранящиеся в buffer (size содержит длину этих данных, которая не превышает PAGE_SIZE), сохранить и отреагировать на новое значение любым имеющим смысл способом и вернуть количество фактически декодированных байт. Метод store может быть вызван только если разрешения атрибута позволяют запись. При написании метода store никогда не забывайте, что вы получаете произвольную информацию из пространства пользователя; вы должны проверять её очень внимательно, прежде чем в ответ выполнить какие-либо действия. Если входные данные не соответствуют ожиданиям, возвращение отрицательного значения ошибки лучше, чем возможность делать что-нибудь нежелательное и непоправимое. Если ваше устройство экспортирует атрибут self_destruct, вы должны требовать, чтобы для вызова такой функциональности была написана определённая строка; неожиданная, случайная запись должна приносить только ошибки.
Во многих случаях поле default_attrs типа kobject описывает все атрибуты, которые kobject будет когда-либо иметь. Но при разработке это не является ограничением; по желанию атрибуты могут быть добавлены и удалены из kobject-ов. Если вы желаете добавить новый атрибут в каталоге kobject-а в sysfs, просто заполните структуру attribute и передайте её в:
int sysfs_create_file(struct kobject *kobj, struct attribute *attr);
Если всё идёт хорошо, создаётся файл с именем, заданным в структуре attribute и возвращаемым значением является 0; в противном случае, возвращается обычный отрицательный код ошибки.
Обратите внимание, что для реализации операций на новом атрибуте вызываются те же самые функции show( ) и store( ). Прежде чем добавить новый, нестандартный атрибут к kobject-у, вы должны принять все необходимые меры для обеспечения того, чтобы эти функции знали, как реализовать этот атрибут.
Чтобы удалить атрибуты, вызывайте:
int sysfs_remove_file(struct kobject *kobj, struct attribute *attr);
После этого вызова атрибут больше не появляется в записи kobject-а в sysfs. Знайте, однако, что процесс в пользовательском пространстве мог бы иметь открытый дескриптор файла для этого атрибута и что после удаления атрибута вызовы show и store по-прежнему возможны.
Соглашения sysfs призывают, чтобы все атрибуты содержали единственное значение в удобном для восприятия человеком текстовом формате. Тем не менее, есть отдельная, редкая необходимость для создания атрибутов, которые могут обрабатывать большие куски двоичных данных. Такая необходимость возникает только в случаях, когда между пространством пользователем и устройством данные должны быть переданы нетронутыми. Например, эта функция требуется для загрузки в устройство программы (прошивка). Когда в системе встречается такое устройство, может быть запущена программа пользовательского пространства (с помощью механизма горячего подключения); эта программа затем передаёт код программы в ядро через бинарный атрибут в sysfs, как это показано в разделе "Интерфейс ядра для встроенного программного обеспечения".
Двоичные атрибуты описываются структурой bin_attribute:
struct bin_attribute {
struct attribute attr;
size_t size;
ssize_t (*read)(struct kobject *kobj, char *buffer, loff_t pos, size_t size);
ssize_t (*write)(struct kobject *kobj, char *buffer, loff_t pos, size_t size);
};
Здесь, attr является структурой attribute, задающей имя, владельца и разрешения для бинарного атрибута и size является максимальным размером бинарного атрибута (или 0, если максимума не существует). Методы read и write работают по аналогии с обычными эквивалентами символьного драйвера; они могут быть вызваны множество раз в течение одной загрузки с максимальным размером данных в каждом вызове в одну страницу. Для sysfs нет возможности просигнализировать о последней из набора операции записи, поэтому код реализации бинарных атрибутов должен быть в состоянии определить конец данных каким-то другим способом.
Двоичные атрибуты должны быть созданы явно; они не могут быть установлены как атрибуты по умолчанию. Для создания бинарного атрибута вызовите:
int sysfs_create_bin_file(struct kobject *kobj, struct bin_attribute *attr);
Двоичные атрибуты могут быть удалены с помощью:
int sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
Файловая система sysfs имеет обычную древовидную структуру, отражающую иерархическую организацию kobject-ов, которые она представляет. Однако, отношения между объектами в ядре часто более сложные, чем эти. Например, одно поддерево sysfs (/sys/devices) представляет все известные в системе устройства, в то время как другие поддеревья (в /sys/bus) представляют драйверы устройств. Эти деревья, однако, не показывают отношения между драйверами и устройствами, которыми они управляют. Показ этих дополнительных отношений требует дополнительных указателей, которые реализуются в sysfs через символические ссылки.
Создание символической ссылки в sysfs является простым:
int sysfs_create_link(struct kobject *kobj, struct kobject *target, char *name);
Эта функция создаёт ссылку (названную name, имя), указывающую на запись target-а (цели) в sysfs как атрибут kobj-а. Она является относительной ссылкой, так что она работает независимо от того, где в любой специфической системе смонтирована sysfs.
Ссылка сохраняется, даже если target удалён из системы. Если вы создаёте символические ссылки на другие kobject-ы, вам следует, вероятно, иметь способ узнать об изменениях в этих kobject-ах, или какую-то гарантию того, что целевые kobject-ы не исчезнут. Последствия (мёртвые символические ссылки внутри sysfs) не особенно серьёзные, но они показывают не лучший стиль программирования и могут создать путаницу в пространстве пользователя.
Символические ссылки могут быть удалены с помощью:
void sysfs_remove_link(struct kobject *kobj, char *name);
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.