Файловая система EXT2

       

Файлы устройств


Файл - основа любой операционной системы, поскольку именно с ним производится наибольшее число действий. В UNIX- и POSIX-системах существуют файлы следующих типов:

  • - обычный файл;
  • - каталог;
  • - FIFO-файл;
  • - байт-ориентированный файл устройства;
  • - блок-ориентированный файл устройства;
  • Блок-ориентированный файл устройства служит для представления физического устройства, которое передает данные блоками. Примером блок-ориентированного устройства является жесткий диск. Байт-ориентированный файл устройства служит для представления физического устройства, которое передает данные побайтово (например, модем).

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

    Файл устройства создается командой mknod, одним из аргументов которой является старший номер устройства (major device number). По сути старший номер - это индекс в таблице ядра, которая содержит адреса всех драйверов, известных системе. В ОС Linux создаются две таблицы - таблица блочных устройств (block device switch) и таблица символьных устройств (character device switch). Обе таблицы являются массивом структур и проиндексированы при помощи значения старшего номера устройства. Таблица блочных устройств определена в файле fs/block_dev.c следующим образом:

    static struct { const char *name; struct block_device_operations *bdops; } blkdevs[MAX_BLKDEV];

    Этот массив заполняется во время регистрации блочного устройства в системе. Для регистрации устройства соответствующий драйвер вызывает функцию register_blkdev (см. файл fs/block_dev.c):

    int register_blkdev(unsigned int major, const char * name, struct block_device_operations *bdops) { .... blkdevs[major].name = name; blkdevs[major].bdops = bdops; return 0; }

    Аргумент major - старший номер устройства, name - имя файла устройства, структура struct block_device_operations содержит функции, выполняемые драйвером устройства. Однако функции read и write в этой структуре отсутствуют. Дело в том, что пользовательский процесс не выполняет напрямую операции чтения/записи в блочное устройства. Для этой цели драйвер предоставляет системе механизм request, и все операции ввода/вывода выполняются через буферный кеш системы, но это тема для отдельной статьи.


    При снятии регистрации соответствующий элемент массива blkdevs обнуляется:

    int unregister_blkdev(unsigned int major, const char * name) { .... blkdevs[major].name = NULL; blkdevs[major].bdops = NULL; return 0; }

    Таблица символьных устройств определена в файле fs/devices.c и также является массивом структур, который заполняется при регистрации устройства в системе:

    struct device_struct { const char * name; struct file_operations * fops; };

    static struct device_struct chrdevs[MAX_CHRDEV];

    Структура struct file_operations определена в файле linux/fs.h и содержит функции, выполняемые драйвером символьного устройства.

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

    Кроме операций чтения/записи, драйвер также предоставляет возможность управления устройством. Операция управления осуществляется при помощи функции ioctl. Эта функция вызывается пользовательским процессом и имеет следующий прототип:

    int ioctl(int fd, int cmd, ...);

    Аргументы функции:

    int fd - файловый дескриптор устройства;

    int cmd - команда, посылаемая устройству.

    Третий параметр является специфичным для каждого устройства, поэтому в прототипе функции не указан.


    Содержание раздела