Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 16.2. Операции блочного устройства

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

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

16.2 Операции блочного устройства

hardorsoft 25.10.10 в 22:29

0

В предыдущем подразделе мы сделали короткое введение в
структуру block_device_operations. Теперь мы подробнее рассмотрим эти
операции, а потом поговорим об обработке запросов. В конце мы
упомянем еще одну возможность драйвера sbull: сделаем вид, что
устройство – сменный носитель. Когда бы пользователь не закрыл
устройство, устанавливается 30-секундный таймер, и если устройство не
открывается в течении этого времени, контекст очищается, и ядру
сообщается о смене носителя. 30 секунд дают пользователю время,
например на то, чтобы монтировать устройство после создания файловой
системы.

hardorsoft 25.10.10 в 22:29

0

16.2.1 Методы open и release

hardorsoft 25.10.10 в 22:29

0

Для реализации фиктивного съемного носителя sbull должен знать, когда последний пользователь закрыл устройство. Драйвером
поддерживается счетчик пользователей. Эта работа выполняется в
методах open и release.

hardorsoft 25.10.10 в 22:30

0

Метод open выглядит очень похоже на соответствующий метод для
символьных устройств. Он получает, в качестве аргументов, указатели на
и структуру file. Когда inode ссылается на блочное устройство, поле
i_bdev->bd_disk содержит указатель на ассоциированную структуру
gendisk. Этот указатель может быть использован для получения
драйвером внутренней структуры данных устройства. Фактически это
первое что делает метод open.

hardorsoft 25.10.10 в 22:30

0

static int sbull_open(struct inode *inode, struct file *filp)
{
struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data;
del_timer_sync(&dev->timer);
filp->private_data = dev;
spin_lock(&dev->lock);
if (! dev->users)
check_disk_change(inode->i_bdev);
dev->users++;
spin_unlock(&dev->lock);
return 0;
}

hardorsoft 25.10.10 в 22:30

0

Получив указатель на структуру устройства, sbull_open, вызывает
del_timer_sync для удаления таймера съемного носителя, если тот
активен. Обратите внимание, что мы не блокируем устройство
посредством spinlock, пока таймер не удален. В противном случае
возможно возникновение взаимной блокировки, в том случае если
таймерная функция запустится перед ее удалением. Когда устройство
заблокировано, мы выполняем функцию ядра check_disk_change, для
проверки: удачно ли прошла смена носителя. Можно было бы утверждать,
что это должно выполнить ядро, но, следуя стандарту, обработку
выполняет драйвер при открытии.

hardorsoft 25.10.10 в 22:31

0

На последнем шаге инкрементируем счетчик пользователей, и
возвращаемся из функции.

hardorsoft 25.10.10 в 22:31

0

Метод release, напротив, выполняет декремент счетчика
пользователей, и, при необходимости, запускает таймер смены носителя:

hardorsoft 25.10.10 в 22:31

0

static int sbull_release(struct inode *inode, struct file *filp)
{
struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data;
spin_lock(&dev->lock);
dev->users--;
if (!dev->users) {
dev->timer.expires = jiffies + INVALIDATE_DELAY;
add_timer(&dev->timer);
}
spin_unlock(&dev->lock);
return 0;
}

hardorsoft 25.10.10 в 22:31

0

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

hardorsoft 25.10.10 в 22:32

0

Вы можете спросить, кто же реально открывает блочное устройство?
Имеется несколько операций, которые вызывают открытие устройства,
непосредственно из пользовательского пространства. Это разбиение
диска на разделы, построение файловой системы на разделе, выполнение
проверки файловой системы, а так же монтирование раздела. В
последнем случае, имеется не пользовательский процесс, который хранит
дескриптор открытого устройства для использования его ядром. Драйвер
блочного устройства не может отличить операцию mount (которая
открывает устройство из пространства ядра) от работы утилиты mkfs
(которая работает из пространства пользователя).

hardorsoft 25.10.10 в 22:32

0

16.2.2 Поддержка устройств со сменными носителями.

hardorsoft 25.10.10 в 22:32

0

Структура block_device_operations содержит два метода для
поддержки устройств со сменными носителями. Если ваше устройство не
позволяет смену носителя, вы можете опустить реализацию этих методов.
Методы относительно просты.

hardorsoft 25.10.10 в 22:32

0

Метод media_changed вызывается из функции check_disk_change для
указания того, что произошла смена носителя. В этом случае,
возвращается не нулевое значение. Реализация для sbull – проста.
Происходит проверка значения флага, который устанавливается, если
сработал таймер смены носителя:

hardorsoft 25.10.10 в 22:33

0

int sbull_media_changed(struct gendisk *gd)
{
struct sbull_dev *dev = gd->private_data;
return dev->media_change;
}

hardorsoft 25.10.10 в 22:33

0

Метод revalidate вызывается после смены носителя. Его работа
заключается в подготовке драйвера к работе с новым носителем. После
выполнения revalidate ядро повторяет чтение таблицы разделов и
начинает работать с устройством. В sbull этот метод просто сбрасывает
флаг media_change, и обнуляет память устройства, симулируя получение
пустого диска:

hardorsoft 25.10.10 в 22:33

0

int sbull_revalidate(struct gendisk *gd)
{
struct sbull_dev *dev = gd->private_data;
if (dev->media_change) {
dev->media_change = 0;
memset (dev->data, 0, dev->size);
}
return 0;
}

hardorsoft 25.10.10 в 22:33

0

16.2.3 Метод ioctl

hardorsoft 25.10.10 в 22:34

0

Блочное устройство предоставляет метод ioctl для управления
устройством. Код высокого уровня подсистемы блочных устройств
перехватывает команды ioctl перед подачей их вашему драйверу
(смотрите файл ядра drivers/block/ioctl.c для более полной
информации). Фактически, современный драйвер блочного устройства
может вовсе не реализовывать очень многие команды ioctl.

hardorsoft 25.10.10 в 22:34

0

В драйвере sbull метод ioctl выполняет только одну команду –
запрос геометрии устройства:

hardorsoft 25.10.10 в 22:34

0

int sbull_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
long size;
struct hd_geometry geo;
struct sbull_dev *dev = filp->private_data;
switch(cmd) {
case HDIO_GETGEO:
/* получение геометрии: т.к. У нас виртуальное устройство,мы
создаем что-то правдоподобное. Мы устанавливаем 16
секторов, 4 головки и вычисляем соответствующее количество
цилиндров. Начало данных устанавливаем на 4 сектор
*/
size = dev->size*(hardsect_size/KERNEL_SECTOR_SIZE);
geo.cylinders = (size & ~0x3f) >> 6;
geo.heads = 4;
geo.sectors = 16;
geo.start = 4;
if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
return -EFAULT;
return 0;
}
return -ENOTTY; /* Не известная команда */
}

hardorsoft 25.10.10 в 22:35

0

Задача предоставления геометрии может показаться странной,
поскольку наше устройство является виртуальным и ничего не делает с
дорожками и цилиндрами. Многие реальные блочные устройства
окружаются множеством сложных структур. Ядру не интересна
геометрия блочного устройства, оно рассматривается просто как
линейный массив секторов. Однако есть пользовательские утилиты,
которые по-прежнему запрашивают геометрию диска. Следует обратить
внимание на программу fdisk, которая редактирует таблицу разделов. Ей
необходима информация о цилиндрах. Без этой информации fdisk не
будет работать.

hardorsoft 25.10.10 в 22:35

0

Устройство sbull может быть разбито на разделы. Мы
предоставляем в ioctl фиктивную геометрию, которая соответствует
емкости нашего устройства. Подобное делают многие дисковые драйверы.
Обратите внимание, что количество секторов в устройстве преобразуется,
учитывая тот факт, что ядро работает только с 512-байтными секторами .

hardorsoft 25.10.10 в 22:35

0
Минутку...