Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 3.3. Несколько важных структур данных

Оглавление
← →
Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

Некоторые важные структуры данных

hardorsoft 19.11.10 в 07:52

0

Как вы можете себе представить, регистрация номера устройства является лишь первой из многих задач, которые должен выполнять код драйвера. В скором времени мы рассмотрим другие важные компоненты драйвера, но одно отступление необходимо в первую очередь. Большинство основных операций драйвера включает три важных структуры данных ядра, называемых file_operations, file и inode. Требуется базовое знакомство с этими структурами, чтобы быть способным делать много всего интересного, так что сейчас мы бросим быстрый взгляд на каждую из них, прежде чем углубляться в подробности того, как осуществляются основные операции драйвера.

hardorsoft 19.11.10 в 07:52

0

Файловые операции

hardorsoft 19.11.10 в 07:52

0

До этого мы зарезервировали некоторые номера устройств для нашего использования, но мы ещё не подключили никаких своих драйверных операций на эти номера. Структура file_operations это то, как символьный драйвер устанавливает эту связь. Структура определена в <linux></linux>fs.h>, это коллекция указателей на функции. Каждое открытие файла (представленное внутри структуры file, которую мы рассмотрим в ближайшее время) связано с собственным набором функций (включая поле, названное f_op, которое указывает на структуру file_operations). Операции в основном отвечают за осуществление системных вызовов и, таким образом, названы open (открыть), read (читать) и так далее. Мы можем рассматривать файл как "объект" и функции, работающие с ним, будут его "методами", используя терминологию объектно-ориентированного программирования для обозначения действий, декларируемых исполняющим их объектом. Это первый признак объектно-ориентированного программирования, видимого нами в ядре Linux, и мы увидим больше в последующих главах.

hardorsoft 19.11.10 в 07:52

0

Обычно, структура file_operations или указатель на неё называется fops (или как-то похоже). Каждое поле структуры должно указывать на функцию в драйвере, которая реализует соответствующие операции, или оставить NULL для неподдерживаемых операций. Точное поведение ядра, когда задан указатель NULL, отличается для каждой функции, список показан позже в этом разделе.

hardorsoft 19.11.10 в 07:52

0

В приведенном ниже списке приводятся все операции, которые приложение может вызывать на устройстве. Мы постарались сохранить список кратким, поэтому он может быть использован в качестве справки, только кратко описывающим каждую операцию и поведение ядра по умолчанию, когда используется указатель NULL.

hardorsoft 19.11.10 в 07:53

0

Прочитав список методов file_operations, вы заметите, что некоторое число параметров включает строку __user. Эта аннотация является одной из форм документации, отмечая, что указатель является адресом пространства пользователя, который не может быть разыменовываться непосредственно. Для нормальной компиляции __user не имеет никакого эффекта, но может быть использована внешним проверяющим программным обеспечением, чтобы найти злоупотребление адресами пользовательского пространства.

hardorsoft 19.11.10 в 07:53

0

Остальная часть главы, после описания некоторых других важных структур данных, объясняет роль наиболее важных операций и предлагает подсказки, предостережения и реальные примеры кода. Мы отложим обсуждение наиболее сложных операций для последующих глав, потому что мы ещё совсем не готовы углубиться в такие темы, как управление памятью, блокирующие операции, а также асинхронные уведомления.

hardorsoft 19.11.10 в 07:53

0

struct module *owner

hardorsoft 28.10.10 в 11:34

0

Первое поле file_operations вовсе не операция, это указатель на модуль, который "владеет" структурой. Это поле используется для предотвращения выгрузки модуля во время использования его операций. Почти всегда оно просто инициализируется THIS_MODULE, макрос определён в <linux></linux>module.h>.

hardorsoft 19.11.10 в 07:53

0

loff_t (*llseek) (struct file *, loff_t, int);

hardorsoft 28.10.10 в 11:34

0

Метод llseek используется для изменения текущей позиции чтения/записи в файле, а новая позиция передаётся как (положительное) возвращаемое значение. Параметром loff_t является "длинное смещение" и он, по крайней мере, 64 бита даже на 32-х разрядных платформах. Об ошибках сигнализируют отрицательные возвращаемые значения. Если указатель на эту функцию NULL, вызовы поиска позиции будут изменять счётчик позиции в структуре file (описанной в разделе "Структура file") потенциально непредсказуемым образом.

hardorsoft 19.11.10 в 07:53

0

ssize_t (*read) (struct file *, char _ _user *, size_t, loff_t *);

hardorsoft 28.10.10 в 11:35

0

Используется для получения данных от устройства. Указатель NULL в этой позиции заставляет системный вызов read вернуться с ошибкой -EINVAL (“Invalid argument”, "Недопустимый аргумент"). Неотрицательное возвращаемое значение представляет собой число успешно считанных байт (возвращаемое значение является типом "размером со знаком", обычно родным (нативным) целочисленным типом для целевой платформы).

hardorsoft 19.11.10 в 07:54

0

ssize_t (*aio_read)(struct kiocb *, char _ _user *, size_t, loff_t);

hardorsoft 28.10.10 в 11:35

0

Начинает асинхронное чтение - операцию чтения, которая может быть не завершена перед возвратом из функции. Если этот метод NULL, все операции будут обрабатываться (синхронно) вместо неё функцией read.

hardorsoft 19.11.10 в 07:54

0

ssize_t (*write) (struct file *, const char _ _user *, size_t, loff_t *);

hardorsoft 28.10.10 в 11:35

0

Отправляет данные на устройство. Если NULL, -EINVAL возвращается в программу, сделавшую системный вызов write. Возвращаемое значение, если оно неотрицательное, представляет собой число успешно записанных байт.

hardorsoft 19.11.10 в 07:54

0

ssize_t (*aio_write)(struct kiocb *, const char _ _user *, size_t, loff_t *);

hardorsoft 28.10.10 в 11:35

0

Начинает асинхронную операции записи на устройство.

hardorsoft 19.11.10 в 07:54

0

int (*readdir) (struct file *, void *, filldir_t);

hardorsoft 28.10.10 в 11:35

0

Это поле должно быть NULL для файлов устройства; оно используется для чтения каталогов и используется только для файловых систем.
 

hardorsoft 19.11.10 в 09:36

0

unsigned int (*poll) (struct file *, struct poll_table_struct *);

hardorsoft 28.10.10 в 11:35

0

Метод poll (опрос) является внутренним для трёх системных вызовов: poll, epoll и select, все они используются для запросов чтения или записи, чтобы заблокировать один или несколько файловых дескрипторов. Метод poll должен вернуть битовую маску, показывающую, возможны ли неблокирующие чтение или запись, и, возможно, предоставить ядру информацию, которая может быть использована вызывающим процессом для ожидания, когда ввод/вывод станет возможным. Если драйвер оставляет метод poll NULL, предполагается, что устройство читаемо и записываемо без блокировки.

hardorsoft 19.11.10 в 09:53

0

int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

hardorsoft 28.10.10 в 11:36

0

Системный вызов ioctl (управление вводом-выводом) открывает путь к выполнению зависящих от устройства команд (например, форматирование дорожки гибкого диска, которая и не чтение, и не запись). Кроме того, несколько команд ioctl распознаются ядром без ссылки на таблицу fops. Если устройство не обеспечивает метод ioctl, системный вызов возвращает ошибку на любой запрос, который не является предопределенным (-ENOTTY, “No such ioctl for device”, "Нет такого управления вводом-выводом для устройства").

hardorsoft 19.11.10 в 09:37

0

int (*mmap) (struct file *, struct vm_area_struct *);

hardorsoft 28.10.10 в 11:36

0

mmap (отобразить в память) используется, чтобы запросить отображение памяти устройства на адресное пространство процесса. Если этот метод NULL, системный вызов mmap возвращает -ENODEV.

hardorsoft 19.11.10 в 09:37

0

int (*open) (struct inode *, struct file *);

hardorsoft 28.10.10 в 11:36

0

Хотя это всегда первая операция, выполняющаяся с файлом устройства, драйверу не требуется декларировать соответствующий метод. Если этот параметр NULL, открытие устройства всегда успешно, но ваш драйвер не уведомляется.

hardorsoft 19.11.10 в 09:38

0

int (*flush) (struct file *);

hardorsoft 28.10.10 в 11:36

0

Операция flush (сбросить на диск) вызывается, когда процесс закрывает свою копию файла дескриптора устройства; она должна выполнить (и ожидает это) любую ожидающую выполнения операцию на устройстве. Не следует путать это с операцией fsync, запрашиваемой программами пользователя. В настоящее время flush используется в очень редких драйверах; например, драйвер ленточного накопителя SCSI использует её, чтобы гарантировать, что все данные записаны на ленту, прежде чем устройство закроется. Если flush NULL, ядро просто игнорирует запрос пользовательского приложения.

hardorsoft 19.11.10 в 09:38

0

int (*release) (struct inode *, struct file *);

hardorsoft 28.10.10 в 11:36

0

Эта операция (отключение) вызывается, когда файловая структура освобождается. Как и open, release может быть NULL.

hardorsoft 19.11.10 в 09:39

0

(* Обратите внимание, что release не вызывается каждый раз, когда процесс вызывает close. Когда файловая структура используется несколькими процессами (например, после fork или dup), release не будет вызван, пока не будут закрыты все копии. Если вам необходимо при завершении копирования сбросить на диск ожидающие данные, вы должны реализовать метод flush.)

hardorsoft 19.11.10 в 09:39

0

int (*fsync) (struct file *, struct dentry *, int);

hardorsoft 28.10.10 в 11:37

0

Этот метод является внутренним системным вызовом fsync, который пользователь вызывает для сброса на диск любых ожидающих данных. Если этот указатель NULL, системный вызов возвращает -EINVAL.

hardorsoft 19.11.10 в 09:39

0

int (*aio_fsync)(struct kiocb *, int);

hardorsoft 28.10.10 в 11:37

0

Это асинхронная версия метода fsync.

hardorsoft 19.11.10 в 09:39

0

int (*fasync) (int, struct file *, int);

hardorsoft 28.10.10 в 11:37

0

Эта операция используется, чтобы уведомить устройство, изменив его флаг FASYNC. Асинхронные уведомления - сложная тема и она описана в Главе 6. Поле может быть NULL, если драйвер не поддерживает асинхронные уведомления.

hardorsoft 19.11.10 в 09:39

0

int (*lock) (struct file *, int, struct file_lock *);

hardorsoft 28.10.10 в 11:37

0

Метод lock (блокировка) используется для реализации блокировки файла; блокировка является неотъемлемой функцией для обычных файлов, но почти никогда не реализуется драйверами устройств.

hardorsoft 19.11.10 в 09:40

0

ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);

hardorsoft 28.10.10 в 11:37

0

Эти методы осуществляют разбросанные (scatter/gather, разборка/сборка) операции чтения и записи. Приложениям иногда необходимо сделать одну операцию чтения или записи с участием нескольких областей памяти; эти системные вызовы позволяют им сделать это без необходимости дополнительных операций копирования данных. Если эти указатели на функции остаются NULL, вместо них вызываются методы read и write (возможно, несколько раз).

hardorsoft 19.11.10 в 09:40

0

ssize_t (*sendfile)(struct file *, loff_t *, size_t, read_actor_t, void *);

hardorsoft 28.10.10 в 11:38

0

Этот метод реализует читающую сторону системного вызова sendfile (послать файл), который перемещает данные из одного файлового дескриптора на другой с минимумом копирования. Используется, например, веб-сервером, которому необходимо отправить содержимое файла из сети наружу. Драйверы устройств обычно оставляют sendfile NULL.

hardorsoft 19.11.10 в 09:40

0

ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);

hardorsoft 28.10.10 в 11:38

0

sendpage (послать страницу) - это другая половина sendfile, она вызывается ядром для передачи данных, одну страницу за один раз, в соответствующий файл. Драйверы устройств, как правило, не реализуют sendpage.

hardorsoft 19.11.10 в 09:40

0

unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);

hardorsoft 28.10.10 в 11:38

0
Минутку...

Следующая страница →