Patrick Mochel <mochel@osdl.org>
Mike Murphy <mamurph@cs.clemson.edu>
Обновление: 16 августа 2011
Оригинал: 10 января 2003
Что это такое
Файловая система sysfs создается в ОЗУ компьютера и реализована исходно на базе ramfs. Она обеспечивает возможность экспорта структур данных ядра, их атрибутов и связей между объектами в пользовательское пространство. Файловая система sysfs непосредственно связана с инфраструктурой kobject (см. документ Documentation/kobject.txt).
Использование sysfs
Поддержка sysfs определяется опцией CONFIG_SYSFS при сборке ядра. Для доступа к файловой системе используется команда mount -t sysfs sysfs /sys
Создание структуры каталогов
Для каждого регистрируемого у системе объекта kobject создается каталог в файловой системе sysfs. Этот каталог создается, как субкаталог родительского объекта kobject, что дает в результате представление иерархии объектов для пользовательского пространства. Каталоги верхнего уровня в sysfs представляют «корни» иерархии объектов.
В sysfs сохраняется указатель на объект kobject, который реализует каталог в объекте sysfs_dirent, связанном с каталогом. В прошлом указатель на этот объект kobject использовался sysfs для прямого учета открытия и закрытия файлов kobject. В современных реализациях sysfs implementation счетчик ссылок kobject изменяется только непосредственно функцией sysfs_schedule_callback().
Атрибуты
Атрибуты объектов kobject могут экспортироваться в форме обычных файлов и sysfs будет предавать файловые операции ввода-вывода методам, определенным для соответствующего атрибута, обеспечивая способ чтения и записи значений атрибутов ядра.
Атрибуты следует помещать в текстовые файлы ASCII (предпочтительно с единственным значением в каждом файле). Однако использование отдельного файла для каждого значения не эффективно, поэтому допустимо включение в один файл массива однотипных значений.
Смешивание типов с использованием множества строк данных усложняет формат файлов и работу с ними. В результате данные могут удаляться или переписываться без ведома.
Определение атрибута весьма просто:
struct attribute { char * name; struct module *owner; umode_t mode; }; int sysfs_create_file(struct kobject * kobj, const struct attribute * attr); void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
«Голые» атрибуты не обеспечивают способов чтения и записи значений. Подсистемам рекомендуется определять собственные структуры атрибутов и функции для работы с ними.
Например, модель драйвера определяет структуры device_attribute вида:
struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); }; int device_create_file(struct device *, const struct device_attribute *); void device_remove_file(struct device *, const struct device_attribute *);
Эта же модель определяет функцию для работы с атрибутами:
#define DEVICE_ATTR(_name, _mode, _show, _store) \ struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
Например, декларирование
static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
эквивалентно выполнению операции
static struct device_attribute dev_attr_foo = { .attr = { .name = "foo", .mode = S_IWUSR | S_IRUGO, .show = show_foo, .store = store_foo, }, };
Специфические для подсистемы вызовы (Callback)
Когда подсистема определяет новый тип атрибута, она должна реализовать набор операций sysfs для передачи вызовов на чтение и запись методам просмотра и сохранения значений владельцу атрибута.
struct sysfs_ops { ssize_t (*show)(struct kobject *, struct attribute *, char *); ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); };
[подсистемам следует иметь уже определенную в качестве деструктора для данного типа структуру kobj_type, в которой хранится указатель sysfs_ops; см. документацию kobject]
При чтении или записи в файл sysfs вызывает подходящий для данного типа метод. Этот метод транслирует базовую структуру kobject и указатели на атрибуты структуры в соответствующие типы указателей и вызывает нужные методы. Например,
#define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, har *buf) { struct device_attribute *dev_attr = to_dev_attr(attr); struct device *dev = to_dev(kobj); ssize_t ret = -EIO; if (dev_attr->show) ret = dev_attr->show(dev, dev_attr, buf); if (ret >= (ssize_t)PAGE_SIZE) { print_symbol("dev_attr_show: %s returned bad count\n", (unsigned long)dev_attr->show); } return ret; }
Чтение и запись атрибутов
Для чтения и записи атрибутов при их декларировании должны задаваться методы show() и store(). Методы следует делать достаточно простыми:
ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
Иными словами, методам следует принимать в качестве параметров лишь объект, атрибут и буфер.
Sysfs выделяет буфер размера (PAGE_SIZE) и передает его методу. Sysfs будет вызывать соответствующий метод один раз при каждой операции чтения или записи. Это требует от реализации метода следующего поведения:
-
При операции read методу show() следует заполнять буфер целиком. С учетом того, что атрибут содержит лишь одно экспортируемое значение или массив однотипных значений здесь не должно возникать сложностей. В результате из пользовательского пространства становится возможным частичное считывание и перемещение вперед по файлу (seek). Если приложение вернется к началу файла или выполнит операцию pread с нулевым смещением, метод show() будет вызван снова для повторного заполнения буфера.
-
При записи (write) sysfs предполагает, что буфер передается целиком при первой операции записи. Содержимое буфера sysfs целиком передает методу store().
При записи в файлы sysfs пользовательским процессам следует сначала считать файл целиком, изменить нужное значение и записать весь буфер обратно в файл.
Реализациям методов работы с атрибутами следует применять идентичные буферы для чтения и записи значений.
Примечания
-
при записи метод show() вызывается независимо от текущей позициив файле;
-
размер буфера всегда составляет PAGE_SIZE байтов (на i386 это 4096);
-
методам show() следует возвращать число байтов, записанных в буфер )значение, возвращаемое scnprintf());
-
методам show() следует всегда использовать scnprintf();
-
методам store() следует возвращать число использованных байтов буфера (если использовались все байты, просто возвращается аргумент count);
-
методы show() и store() могут возвращать коды ошибок (особенно при получении некорректного значения);
-
объекты, переданные методам, помещаются в память с использованием счетчика ссылок sysfs, однако указываемый физический объект (например, устройство) может отсутствовать в системе и при необходимости следует проверять его наличие.
Пример очень простой и естественной реализации атрибута устройства показан ниже:
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name); } static ssize_t store_name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { snprintf(dev->name, sizeof(dev->name), "%.*s", (int)min(count, sizeof(dev->name) - 1), buf); return count; } static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
Отметим, что практические реализации не должны позволять задание имен устройств из пользовательского пространства.
Схема каталогов верхнего уровня
Каталог sysfs показывает соотношения между структурами данных ядра. Субкаталоги верхнего уровня имеют вид:
block/
bus/
class/
dev/
devices/
firmware/
net/
fs/
Каталог devices/ представляет дерево файлов, связанных с устройствами, и отображает их напрямую во внутреннее дерево устройств ядра, представляющее собой иерархию структур device. В каталоге bus/ содержится плоская схема различных типов шин в ядре. Каталог для каждой из шин включает два субкаталога:
devices/
drivers/
В субкаталоге devices/ размещаются символьные ссылки для каждого обнаруженного в системе устройства на соответствующие устройства в каталоге устройств корневой файловой системы (root/).
В каталоге drivers/ содержится каталог для каждого драйвера устройства, который загружается для конкретной шины (предполагается, что каждый драйвер работает только с одним типом шины).
Дерево fs/ содержит каталоги для некоторых файловых систем. В настоящее время система, желающая экспортировать атрибуты, должна создавать свою иерархию в дереве fs/ (см, например документ Documentation/filesystems/fuse.txt в дистрибутиве ядра).
Каталог dev/ содержит два субкаталога char/ и block/, в каждом из которых размещаются символьные ссылки с именами вида <major>:<minor>. Эти ссылки указывают на каталоги sysfs для каждого из устройств. Структура /sys/dev обеспечивает возможность быстрого поиска интерфейса sysfs для устройства по результатам операции stat.
Дополнительную информацию о конкретных свойствах драйверов можно найти в каталоге Documentation/driver-model/.
Примечание: Этот раздел пока не завершен.
Текущие интерфейсы
Ниже перечислены интерфейсные уровни, существующие в sysfs на текущий момент.
Устройства (include/linux/device.h)
Структура
struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); };
Декларирование
DEVICE_ATTR(_name, _mode, _show, _store);
Создание и удаление
int device_create_file(struct device *dev, const struct device_attribute * attr); void device_remove_file(struct device *dev, const struct device_attribute * attr);
Драйверы шин (include/linux/device.h)
Структура
struct bus_attribute { struct attribute attr; ssize_t (*show)(struct bus_type *, char * buf); ssize_t (*store)(struct bus_type *, const char * buf, size_t count); };
Декларирование
BUS_ATTR(_name, _mode, _show, _store)
Создание и удаление
int bus_create_file(struct bus_type *, struct bus_attribute *); void bus_remove_file(struct bus_type *, struct bus_attribute *);
Драйверы устройств (include/linux/device.h)
Структура
struct driver_attribute { struct attribute attr; ssize_t (*show)(struct device_driver *, char * buf); ssize_t (*store)(struct device_driver *, const char * buf, size_t count); };
Декларирование
DRIVER_ATTR(_name, _mode, _show, _store)
Создание и удаление
int driver_create_file(struct device_driver *, const struct driver_attribute *); void driver_remove_file(struct device_driver *, const struct driver_attribute *);
Документация
Структура каталога sysfs и атрибуты в каждом из субкаталогов определяют бинарный интерфейс (ABI) между ядром и пользовательским пространством. Как и для всякого ABI здесь важно обеспечить стабильность и надлежащее документирование. Все новые атрибуты sysfs должны документироваться в Documentation/ABI. Дополнительную информацию можно найти в документе Documentation/ABI/README.
Перевод на русский язык
Николай Малых