Управление блочными устройствами структура дисков

Обновлено: 06.07.2024

Минимальной адресуемой областью данных на жёстком диске является сектор. Размер сектора традиционно равен 512 байт. В 2010-х появились жёсткие диски с размером сектора 4096 байт (Advanced Format). На диске каждый сектор состоит из заголовка, полезных данных и кода коррекции ошибок (ECC).

Операционные системы обычно оперируют понятием блока. Блок включает один или несколько секторов.

Понятие кластер используется в файловых системах FAT, NTFS.

Системы адресации

CHS (от англ. Cylinder, Head, Sector — цилиндр, головка, сектор) — система адресации сектора, как минимальной единицы хранения данных в накопителях на жёстких магнитных дисках, основанная на использовании физических адресов геометрии диска.

LBA (англ. Logical block addressing) — механизм адресации и доступа к блоку данных на жёстком или оптическом диске, при котором системному контроллеру нет необходимости учитывать геометрию самого жесткого диска (количество цилиндров, сторон (головок), секторов на дорожке).

Суть LBA состоит в том, что каждый блок, адресуемый на жёстком диске, имеет свой номер, целое число, начиная с нуля и т. д. (то есть первый блок LBA=0, второй LBA=1, . )

Таблица разделов

Схема MBR

Информация о размещении разделов на жёстком диске хранится в таблице разделов (partition table), которая является частью главной загрузочной записи (MBR). MBR располагается в первом физическом секторе жёсткого диска.

Главная загрузочная запись (англ. master boot record, MBR) — код и данные, необходимые для последующей загрузки операционной системы и расположенные в первых физических секторах (чаще всего в самом первом) на жёстком диске или другом устройстве хранения информации.

MBR содержит небольшой фрагмент исполняемого кода, таблицу разделов (partition table) и специальную сигнатуру.

Функция MBR — «переход» в тот раздел жёсткого диска, с которого следует исполнять «дальнейший код» (обычно — загружать ОС). На «стадии MBR» происходит выбор раздела диска, загрузка кода ОС происходит на более поздних этапах алгоритма.

В процессе запуска компьютера, после окончания начального теста (Power-on self-test — POST), Базовая система ввода-вывода (BIOS) загружает «код MBR» в оперативную память (в IBM PC обычно с адреса 0000:7c00) и передаёт управление находящемуся в MBR загрузочному коду.

Классическая структура главной загрузочной записи (MBR)
Смещение Длина, байт Описание
0000h 446 Машинный код загрузчика
01BEh 16 Раздел 1 Таблица разделов
01CEh 16 Раздел 2
01DEh 16 Раздел 3
01EEh 16 Раздел 4
01FEh 2 Сигнатура (55h AAh)


В MBR под таблицу разделов выделено 64 байта. Каждая запись занимает 16 байт. Таким образом, всего на жестком диске может быть создано не более четырёх разделов. Когда разрабатывалась структура MBR, это считалось достаточным. Однако, позднее был введён дополнительный раздел, структура которого позволяет создавать внутри него неограниченное число логических дисков (разделов).

Таким образом, MBR может содержать не более четырёх первичных (primary) разделов, либо, как вариант, не более трёх первичных и один расширенный (extended) раздел.

Организация таблицы разделов налагает ограничение в 2 ТБ на общий размер адресуемого места на диске.

Схема GPT

В новых компьютерах, перешедших на технологию EFI вместо BIOS, нет ограничений на количество основных разделов, а логических и расширенных за ненадобностью не существует, поскольку используется не Master Boot Record, а GPT (GUID Partition Table).

Именование устройств

Есть два типа файлов устройств: блочные (англ. block special files) и символьные (англ. character special files). Блочные файлы устройств используются для передачи данных, разделённых на пакеты фиксированной длины — блоки. А символьные файлы устройств используются для небуферизованного обмена данными. Большинство устройств способно принимать и отправлять данные либо блоками (блочные устройства), либо сплошным потоком байтов (символьные устройства), но некоторые (такие как жёсткий диск) сочетают в себе обе эти возможности. Работа с первым типом устройств возможна либо через блочные, либо через символьные файлы, а вот с последним типом — подходят и те, и другие.

ОС Linux представляет жёсткие диски в виде блочных устройств.

Традиционные имена Linux-устройств для жёстких дисков:

  • /dev/sda, /dev/sdb, /dev/sdc. — устройства SCSI, SATA, USB
  • /dev/hda, /dev/hdb, /dev/hdc. — устройства PATA

Эти правила настраиваются через udev

Если устройств больше 26, система начнёт использовать большие буквы: a, b, c, . z, Aa, . Az, .

Разделы на устройствах нумеруются цифрами с единицы: /dev/sda1, /dev/sda2, .

Для схемы MBR в нумерации разделов могут быть пропуски. Логические разделы всегда нумеруются с 5.

Чтение MBR

Посмотреть список разделов

Diskpartition-600x426.jpg

RAID (англ. redundant array of independent disks — избыточный массив независимых дисков) — технология виртуализации данных, которая объединяет несколько дисков в логический элемент для избыточности и повышения производительности.

Уровни RAID

Программный RAID

Для реализации RAID можно применять не только аппаратные средства, но и полностью программные компоненты (драйверы). Например, в системах на ядре Linux существуют специальные модули ядра, а управлять RAID-устройствами можно с помощью утилиты mdadm. Устройства обычно называются /dev/md1, /dev/md2, .

Некоторые файловые системы (ZFS, Btrfs, . ) могут организовывать хранение данных на нескольких устройствах самостоятельно, без дополнительного ПО.

Менеджер логических томов (logical volume manager) — подсистема ОС Linux, позволяющая использовать разные области одного жёсткого диска и/или области с разных жёстких дисков как один логический том.

Используется для следующих целей:

  • Создание одного логического раздела поверх нескольких физических разделов или даже разных жёстких дисков (чем-то похоже на RAID 0), с поддержкой динамического изменения размера раздела.
  • Поддержка больших дисковых массивов с возможностью горячей замены отдельных дисков без остановки сервера.
  • На небольших системах (например на десктопах), можно во время установки не думать, каких размеров сделать разделы, а затем легко изменять размер файловых систем.
  • Осуществление консистентных резервных копий путём получения снэпшотов логических разделов.

LVM — тонкая программная прослойка, ещё один слой абстракции между жестким диском (будь то винчестер, RAID-массив или что-то ещё) и файловой системой.

Основным видом блочных устройств являются магнитные и другие диски, поэтому начнем с рассмотрения структуры диска (рис. 2‑7).


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

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

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

Структура сектора показана на рис. 2‑8.


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

Заголовок сектора содержит физический адрессектора и его размер. Физический адрес состоит из трех чисел: номер цилиндра, номер поверхности и номер сектора на дорожке. Самый первый сектор диска имеет адрес (0, 0, 1). Размер сектора наIBM-совместимых компьютерах всегда равен 512 байт.

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

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

Нумерация секторов не обязательно ведется в порядке их размещения на дорожке. Если скорость имеющейся аппаратуры недостаточна для того, чтобы успеть прочесть и передать в память данные со всей дорожки за время одного оборота диска, то система при форматировании нумерует секторы «через один» или даже «через два». Например, при 9 секторах на дорожке они могут быть пронумерованы «через один» в таком порядке: 1, 6, 2, 7, 3, 8, 4, 9, 5. После чтения сектора 1 у контроллера диска есть время передать прочитанные данные, пока к головке чтения не подойдет сектор 2. В результате вся дорожка может быть прочитана за два оборота диска.

Разделы и логические тома

Общая структура дискет и жестких дисков различаются между собой. Эти структуры показаны на рис. 2‑9.


Начальный сектор дискеты (рис. 2‑9, а) принято называть BOOT-сектором. Он содержит количественные данные о дискете (размер секторов, количество секторов на каждой дорожке и на всей дискете, число поверхностей и т.п.), метку (название) и серийный номер дискеты, а также данные о файловой системе. Кроме того, если дискета содержит системные файлы ОС, то вBOOT-секторе находится также небольшая программа начальной загрузки, которая считывает один сектор ОС и передает ему управление для продолжения загрузки. Все остальные секторы дискеты могут использоваться ОС для хранения ее файлов и других данных. Общее количество секторов на дискете не может превышать 2 16 (на самом деле, их значительно меньше).

Скажите быстро, сколько примерно секторов содержит стандартная трехдюймовая дискета?

Для жесткого диска (рис. 2‑9, б) начальный сектор называется MBR(MasterBootRecord, главная загрузочная запись). Он тоже может содержать программу начальной загрузки, но, кроме того, содержиттаблицу разделов(partitiontable), которая описывает разбиение жесткого диска наразделы.

Таблица может содержать от 1 до 4 записей о разделах. Каждая запись содержит тип раздела, число секторов в нем, физические адреса начала и конца раздела.

Возможны следующие типы разделов.

Обычныйраздел. Его структура точно такая же, как у дискеты, т.е. такой раздел начинается сBOOT-сектора, а общее число секторов не превышает 2 16 . Таким образом, общий размер раздела не может превышать 32 Мб.

Большойраздел. Он отличается от обычного тем, что число секторов может достигать 2 32 . Это позволяет описывать большие разделы размером до 2048 Гб.

Расширенныйраздел. Его структура аналогична структуре всего жесткого диска, т.е. начальный сектор раздела – неBOOT, аMBR-сектор. Аналогия не совсем полная, поскольку таблица разделов вMBRрасширенного раздела может содержать не более двух записей, причем первая из них должна описывать либо обычный, либо большой раздел, а вторая запись, если она имеется, описывает еще один расширенный раздел.

Разделы других ОС (например, UNIX).

Обычные и большие разделы называются также логическими томамиилилогическими дисками, в отличие от физических дисков. Обычная буквенная нумерация дисковA,B,C,Dи т.д. относится именно к логическим томам. Для дискет понятия физического и логического тома совпадают.

Изначально MS-DOSподдерживала только обычные разделы на жестком диске. В 80-е годы казалось, что 32 Мб – это очень большой объем диска. Когда появились диски объемом в несколько сотен мегабайт, была придумана матрешечная структура расширенных разделов, что позволило на одном физическом томе разместить сколько угодно логических томов по 32 Мб. Затем были реализованы большие разделы, что потребовало от разработчиковMS-DOSвнести существенные изменения в программный интерфейс и реализацию средств работы с дисками. После этого использование расширенных разделов стало необязательным, если пользователю достаточно иметь не более четырех логических томов на одном физическом диске.

Операционная система Linux предоставляет производительные средства и наборы инструментов для управления аппаратными устройствами, в том числе накопителями. Эта статья расскажет, как Linux представляет эти устройства и, как превратить неформатированное хранилище (raw storage) в полезное пространство.

Блочные системы хранения

Блочная система хранения (block storage) – это ещё одно название блочного устройства в Linux. Блочное устройство – это часть аппаратных средств, предназначенная для хранения данных, например жесткий диск (hard disk drive, HDD), твердотельный накопитель (solid state drive, SSD), флэш-карта памяти и т.д. Они называются блочными устройствами, так как ядро подключается к аппаратным средствам путем ссылки на блоки фиксированного размера (фрагменты пространства).

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

Разделы диска

Дисковые разделы – один из способов разделения накопителя на меньшие единицы. Разделом называется логически выделенная часть накопителя, которую, по сути, можно воспринимать и обрабатывать как сам накопитель.

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

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

MBR и GPT

При разделении диска важно учитывать формат. Как правило, при этом используются форматы MBR (Master Boot Record) и GPT (GUID Partition Table).

MBR – традиционная система дискового разделения, которая используется уже более 30 лет. Из-за её возраста в ней есть ряд серьёзных ограничений. Например, её нельзя использовать для разделения дисков, чей объём превышает 2Тб. Также MBR позволяет создать максимум четыре первичных раздела; при этом четвертый раздел, как правило, является «расширенным разделом», в котором можно создавать «логические разделы» (то есть, таким образом можно разделить последний раздел, чтобы добавить дополнительные разделы).

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

В большинстве случаев лучше использовать GPT (если только операционная система или наборы инструментов не подразумевают другого решения).

Форматирование и файловые системы

Ядро Linux может распознавать неформатированный диск. Но накопитель должен обязательно быть отформатированным.

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

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

Наиболее популярными файловыми системами в Linux являются:

  • Ext4: (четвертая версия расширенной файловой системы) самая популярная на сегодняшний день файловая система. Ext4 обеспечивает систему журналирования и обратную совместимость с существующими системами, она невероятно надёжна и имеет зрелую поддержку и инструментарий. Это отличный выбор, если у вас нет никаких особенных требований.
  • XFS: специализируется на производительности и больших файлах данных. Эта файловая система быстро форматируется и предоставляет высокую пропускную способность при работе с большими файлами и дисками. Также она поддерживает быстрые снапшоты. XFS журналирует только метаданные. Это обеспечивает высокую производительность, но может привести к повреждению данных в случае резкой потери мощности.
  • Btrfs: современная многофункциональная файловая система, работающая по принципу «копирование при записи» (copy-on-write). Такая архитектура позволяет интегрировать функциональные возможности управления томами на уровне файловой системы. Готовность системы Btrfs к производственным нагрузкам всё ещё остаётся предметом активного обсуждения; многие системные администраторы считают её несколько незрелой для этого.
  • ZFS: современная файловая система и менеджер томов с широким и зрелым набором функций, работающий по принципу «копирование при записи». ZFS обеспечивает высокую целостность данных, может обрабатывать большие файловые системы, предоставляет функции управления томами (клонирование, создание снапшотов, систематизация томов в RAID и RAID-подобные массивы для обеспечения избыточности данных и повышения производительности). Что касается работы в Linux, ZFS имеет противоречивую историю из-за проблем с лицензированием. Несмотря на это Ubuntu поставляет двоичный модуль ядра ZFS, а Debian включает исходный код ZFS в свои репозитории. Другие дистрибутивы ещё не определились с поддержкой ZFS.

Управление устройствами хранения в Linux

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

Система Linux почти всё представляет в виде файлов. Это касается и аппаратных накопителей, которые представлены в системе в виде файлов в каталоге /dev. Как правило, имена файлов, представляющих устройства хранения данных, начинаются с sd или hd, после чего следует буква. Например, первый диск на сервере, как правило, будет называться примерно так: /dev/sda.

Разделы таких накопителей тоже будут иметь свои файлы в /dev. В имя такого файла входит sd или hd + буква + порядковый номер раздела. Например, первый раздел на первом диске сервера будет называться /dev/sda1.

Файлы /dev/sd* и /dev/hd* представляют традиционный способ обозначения дисков и разделов, существует значительный недостаток в использовании значений. Ядро Linux распределяет имена устройств при каждой загрузке системы, а это может привести к путанице при изменении узлов устройств.

Чтобы обойти эту проблему, каталог /dev/disk содержит подкаталоги, которые предоставляют более надёжный способ определения дисков и разделов в системе. Они содержат символические ссылки на правильные файлы /dev/[sh]da*, которые создаются при загрузке системы. В названии ссылки содержится идентифицирующий признак каталога. Эти ссылки всегда указывают на правильные устройства, потому они используются как статические идентификаторы хранилищ.

В каталоге /dev/disk могут существовать следующие подкаталоги:

  • by-label: большинство файловых систем предоставляет механизмы маркировки, которые позволяют назначать произвольные имена для диска или раздела. Этот каталог хранит ссылки, названные с помощью предоставленных пользователем меток.
  • by-uuid: UUID (универсально уникальные идентификаторы) – это длинные уникальные последовательности букв и цифр, которые можно использовать в качестве идентификатора для ресурса хранения. Как правило, они очень сложные для человеческого восприятия, но зато они обеспечивают уникальность (даже при работе между несколькими системами). UUID отлично подходят для создания ссылок на хранилища, которые могут мигрировать между системами, так как они устраняют конфликты имён.
  • by-partlabel и by-partuuid: GPT таблицы предоставляют свой собственный набор меток и UUID. Они во многом похожи на идентификаторы из предыдущих каталогов, но используют специфические идентификаторы GPT.
  • by-id: хранит ссылки, сгенерированные серийным номером устройства.
  • by-path: как и by-id, этот каталог использует подключения устройств хранения к самой системе. Ссылки здесь построены на основе интерпретации системой аппаратного обеспечения, используемого для доступа к устройству. Серьёзным недостатком является то, что при подключении устройства к другому порту это значение может измениться.

Как правило, для постоянной идентификации конкретных устройств используются каталоги by-label или by-uuid.

Монтирование блочных устройств

Файлы устройств в каталоге /dev используются для обмена данными с драйвером ядра. Тем не менее, чтобы рассматривать устройство в качестве сегмента доступного пространства, требуется более удобное разделение.

В Linux и других Unix-подобных системах вся система представлена единым унифицированным деревом файлов независимо от количества физических устройств. Таким образом, когда на диске или разделе используется файловая система, её нужно подключить к существующему дереву. Монтирование – это процесс присоединения отформатированного раздела или диска к каталогу в файловой системе Linux. Доступ к содержимому накопителя можно получить с помощью этого каталога.

Устройства обычно монтируются в специальные выделенные пустые каталоги; если устройство было смонтировано в непустой каталог, то текущее содержимое этого каталога будет недоступно, пока устройство не демонтируют. Существует множество различных опций для монтирования, которые можно настроить, чтобы изменить поведение смонтированного устройства (например, открыть устройство только для чтения, чтобы защитить его данные от изменений).

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

Постоянное монтирование

Дистрибутивы Linux читают файл /etc/fstab, чтобы узнать, какие файловые системы нужно монтировать во время запуска. Если этот файл не содержит записи о какой-либо файловой системе, то такая файловая система не будет смонтирована автоматически. Исключение составляют только системы, которые определяются файлами .mount системы инициализации systemd.

Файл /etc/fstab достаточно прост. Каждая строка определяет блочное устройство, его точку монтирования, формат диска, параметры монтирования, а также некоторую другую информацию.

Продвинутое управление хранилищами

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

Что такое RAID?

RAID (Redundant Array of Independent Disks) – это технология управления хранением данных и виртуализацией, которая позволяет сгруппировать диски и управлять ими как единым целым.

Характеристики RAID-массива зависит от уровня RAID, который определяет, как именно диски в массиве связаны друг с другом. Выбранный уровень влияет на производительность и избыточность. Наиболее распространенными уровнями являются:

  • RAID 0: также известен как распределение данных. При записи данных в массив они разделяются на блоки и распределяются между дисками в наборе. Это дает прирост производительности, поскольку можно одновременно записывать или читать несколько дисков. Недостатком является то, что отказ одного диска может стать причиной потери данных всего массива, так как ни один диск не содержит достаточных для восстановления данных.
  • RAID 1: технология зеркалирования. Данные, записанные в массив RAID 1, записываются на несколько дисков. Главным преимуществом такого подхода является избыточность данных, что позволяет сохранить данные даже в случае потери жёсткого диска. Поскольку несколько дисков содержат одни и те же данные, полезная емкость уменьшается наполовину.
  • RAID 5: технология распределения данных (подобно RAID 0). Этот уровень также реализует распределенную четность по всем дискам. Это означает, что если диск выйдет из строя, остальные диски позволяют восстановить массив с помощью информации о четности. Этой информации достаточно, чтобы восстановить один из дисков, то есть массив может пережить потерю любого диска.
  • RAID 6: обладает теми же параметрами, что и RAID 5, но использует два диска чётности. То есть, такие массивы могут переносить потерю любых двух дисков. Конечно, емкость массива зависит от четности.
  • RAID 10: комбинация уровней 1 и 0 (массив RAID 0, построенный из массивов RAID 1). Этот уровень предоставляет два набора зеркальных массивов, в которых можно распределять данные. В результате получается высокопроизводительный массив, обладающий некоторыми характеристиками избыточности. Суммарная мощность такого массива составляет половину объединенного дискового пространства.

Что такое LVM?

LVM (или Logical Vvolume Management) – это система, которая абстрагирует основные физические характеристики устройств хранения данных для повышения гибкости и мощности. LVM может создавать группы физических устройств и управлять ими как единым блоком. Это позволяет по мере необходимости сегментировать пространство в логические тома, которые будут работать как разделы.

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

Дальнейшие действия

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

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

Методы open и release

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

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

static int sbull_open(struct inode *inode, struct file *filp)

struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data;

После того, как sbull_open получила указатель на свою структуру устройства, она вызывает del_timer_sync для удаления таймера "носитель заменён", если таковой является активным. Обратите внимание, что мы не выполняем спин-блокировку устройства, пока таймер не был удалён; если поступить иначе, возможна взаимоблокировка, если таймерная функция запустится, прежде чем мы сможем её удалить. При заблокированном устройстве мы вызываем функцию ядра, названную check_disk_change , чтобы проверить не произошла ли смена носителя. Можно возразить, что этот вызов должно сделать ядро, но стандартным шаблоном для драйвера является его обработка во время работы open .

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

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

static int sbull_release(struct inode *inode, struct file *filp)

struct sbull_dev *dev = inode->i_bdev->bd_disk->private_data;

dev->timer.expires = jiffies + INVALIDATE_DELAY;

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

Вы можете быть удивлены, кто фактически открывает блочное устройство. Есть несколько операций, которые являются причиной открытия блочного устройства непосредственно из пространства пользователя; к ним относятся разбиение диска, создание файловой системы на разделе или работа контроля файловой системы. Кроме того, блочный драйвер получает вызов open при монтировании раздела. В этом случае нет никакого процесса пространства пользователя, содержащего дескриптор открытого на устройстве файла; открытый файл, вместо того, удерживается самим ядром. Блочный драйвер не может определить разницу между операцией mount (которая открывает устройство из пространства ядра) и вызов из такой утилиты, как mkfs (которая открывает его из пространства пользователя).

Поддержка сменных носителей

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

Чтобы увидеть, был ли заменён носитель, вызывается метод media_changed (из check_disk_change ); если это произошло, он должен вернуть ненулевое значение. Реализация в sbull проста; она запрашивает флаг, который был установлен, если истёк таймер смены носителя:

int sbull_media_changed(struct gendisk *gd)

struct sbull_dev *dev = gd->private_data;

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

int sbull_revalidate(struct gendisk *gd)

struct sbull_dev *dev = gd->private_data;

memset (dev->data, 0, dev->size);

Метод ioctl

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

Метод ioctl в sbull обрабатывает только одну команду - запрос о конфигурации устройства:

int sbull_ioctl (struct inode *inode, struct file *filp,

unsigned int cmd, unsigned long arg)

struct hd_geometry geo;

struct sbull_dev *dev = filp->private_data;

* Получить конфигурацию: поскольку мы являемся виртуальным устройством, мы должны сделать

* что-то правдоподобное. Итак, мы заявляем о 16 секторах, четырёх головках,

* и рассчитываем соответствующее число цилиндров. Мы устанавливаем

* начало данных на четвёртом секторе.

if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))

return -ENOTTY; /* команда неизвестна */

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

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

Читайте также: