};
Поле name
содержит имя атрибута. Такое же имя будет иметь и соответствующий файл на файловой системе sysfs. Поле owner
— это указатель на структуру module
, которая представляет загружаемый модуль, содержащий соответствующие данные. Если такого модуля не существует, то значение поля равно NULL
. Поле mode
имеет тип mode_t
и указывает права доступа к файлу на файловой системе sysfs. Если атрибут предназначен для чтения всеми, то флаг прав доступа должен быть установлен в значение S_IRUGO
, если атрибут имеет право на чтение только для владельца, то права доступа устанавливаются в значение S_IRUSR
. Атрибуты с правом на запись, скорее всего, будут иметь права доступа S_IRUGO | S_IWUSR
. Все файлы и каталоги на файловой системе sysfs принадлежат пользователю с идентификаторами пользователя и группы равными нулю.
Структура attribute
используется для представления атрибутов, а структура sysfs_ops
описывает, как эти атрибуты использовать. Поле sysfs_ops
— это указатель на одноименную структуру, которая определена в файле <linux/sysfs.h>
следующим образом.
struct sysfs_ops {
/* метод вызывается при чтении файла на файловой системе sysfs */
ssize_t (*show)(struct kobject *kobj,
struct attribute *attr, char *buffer);
/* метод вызывается при записи файла на файловой системе sysfs */
ssize_t (*store)(struct kobject *kobj,
struct attribute *attr, const char *buffer, size_t size);
};
Метод show()
вызывается при чтении файла. Он должен выполнить копирование значения атрибута, который передается в качестве параметра attr
, в буфер, на который указывает параметр buffer
. Размер буфера равен PAGE_SIZE
байт. Для аппаратной платформы значение PAGE_SIZE
равно 4096 байтов. Функция должна возвратить количество байтов данных, которые записаны в буфер в случае успешного завершения, и отрицательный код ошибки, если такая ошибка возникает.
Метод store()
вызывается при записи. Он должен скопировать size
байт данных из буфера buffer
в атрибут attr
. Размер буфера всегда равен PAGE_SIZE
или меньше. Функция должна возвратить количество байтов данных, которые прочитаны из буфера при успешном выполнении, и отрицательный код ошибки в случае неудачного завершения.
Так как этот набор функций должен выполнять операции ввода-вывода для всех атрибутов, то необходимо выполнить некоторые дополнительные действия, чтобы вызвать обработчик, специфичный для каждого атрибута.
Обычно атрибутов, которые используются по умолчанию и предоставляются типом ktype
, связанным с объектом kobject
, оказывается достаточно. Действительно, все объекты kobject
одного типа должны быть чём-то похожи друг на друга или даже быть идентичными по своей природе. Например, для всех разделов жестких дисков один и тот же набор атрибутов должен подходить для всех объектов kobject
. Это не просто упрощает жизнь, но и позволяет упорядочить код и получить одинаковый способ доступа ко всем каталогам файловой системы sysfs, связанным с родственными объектами.
Тем не менее иногда требуется, чтобы определенный экземпляр объекта kobject
имел некоторые специфические свойства. Для таких объектов может оказаться желательным (или необходимым) создать атрибут, которого нет у общего типа данного объекта. Для такого случая ядро предоставляет функцию sysfs_create_file()
для добавления атрибута к существующему объекту.
int sysfs_create_file(struct kobject *kobj, const struct attribute *attr);
Эта функция позволяет привязать структуру attribute, на которую указывает параметр attr
, к объекту kobject
, на который указывает параметр kobj
. Перед тем как вызвать эту функцию, необходимо установить значение атрибута (заполнить поля структуры). Эта функция возвращает значение нуль в случае успеха и отрицательное значение в случае ошибки.
Обратите внимание, что для обработки указанного атрибута используется структура sysfs_ops
, соответствующая типу ktype
объекта. Иными словами, существующие функции show()
и store()
, которые используются для объекта по умолчанию, должны иметь возможность обработать вновь созданный атрибут.
Кроме того, существует возможность создавать символьные ссылки. Создать символьную ссылку на файловой системе sysfs можно с помощью вызова следующей функции.
int sysfs_create_link(struct kobject *kobj,
struct kobject *target, char *name);
Эта функция создает символьную ссылку с именем name
в каталоге объекта, соответствующего параметру kobj
, на каталог, соответствующий параметру target
. Эта функция возвращает нулевое значение в случае успеха и отрицательный код ошибки в противном случае.
Удаляется атрибут с помощью вызова функции sysfs_remove_file()
.
void sysfs_remove_file(struct kobject *kobj,
const struct attribute *attr);
После возврата из этой функции указанный атрибут больше не отображается в каталоге объекта.
Символьная ссылка, созданная с помощью функции sysfs_create_link()
, может быть удалена с помощью функции sysfs_remove_link()
.
void sysfs_remove_link(struct kobject *kobj, char *name);
После возврата из функции символьная ссылка с именем name удаляется из каталога, на который отображается объект kobj
.
Все эти четыре функции объявлены в файле <linux/kobject.h>
. Функции sysfs_create_file()
и sysfs_remove_file()
определены в файле fs/sysfs/file.c
, а функции sysfs_create_link()
и sysfs_remove_link()
— в файле fs/sysfs/symlink.c
.
Файловая система sysfs — это место, где должна реализовываться функциональность, для которой раньше использовался системный вызов ioctl()
для специальных файлов устройств, или файловая система procfs. Сегодня модно выполнять такие вещи через атрибуты файловой системы sysfs в соответствующем каталоге. Например, вместо того чтобы реализовать новую директиву ioctl()
для специального файла устройства, лучше добавить соответствующий атрибут в каталоге файловой системы sysfs, который относится к этому устройству. Такой подход позволяет избежать использования небезопасных, из-за отсутствия проверки типов аргументов, директив ioctl()
, а также файловой системы /proc
с ее бессистемным расположением файлов и каталогов.
Однако чтобы файловая система sysfs оставалась четко организованной и интуитивно понятной, разработчики должны придерживаться определенных соглашений.
Во-первых, каждый атрибут sysfs должен экспортировать значение одной переменной на файл. Значения должны быть в текстовом формате и соответствовать простым типам языка программирования С. Целью такого представления является необходимость избежать чрезвычайно запутанного и плохо структурированного представления информации, которое мы сегодня имеем на файловой системе /proc
. Использование одной переменной на файл позволяет легко считывать и записывать данные из командной строки, а также просто работать через файловую систему sysfs с данными ядра в программах, написанных на языке С. В случаях, когда одно значение на файл приводит к неэффективному представлению информации, допустимо использование файлов, в которых хранится несколько значений одного типа. Эти данные необходимо четко разделять. Наиболее предпочтительным разделителем является символ пробела. При разработке кода ядра необходимо всегда помнить, что файлы файловой системы sysfs являются представлениями переменных ядра, и ориентироваться на доступ к ним из пространства пользователя, в частности из командной строки.