Накопители в Linux: модели именования

Алексей Федорчук

Необходимость в этой заметке я ощутил во время сочинения интермедии в цикле про DragonFly, конкретно — про модели именования её устройств. Поскольку в этой операционке, как и в Linux’е, номенклатура дисковых накопителей давно уже не сводится к каноническим именам так называемого «верхнего уровня» (/dev/sd?# в Linux’е, /dev/ad# или /dev/da# — во FreeBSD и DragonFly), о которых повествуется в «толстых» книжках (тем более что последним из таковых на русском языка скоро стукнет десять лет).

На истории «номенклатурного вопроса» в Linux’е останавливаться не буду — она достаточно подробно изложена в книжке по истории мира FOSS, которая (всё ещё) готовится к размещению в Библиотеке Блогосайта. Которое сложилось вследствие внедрения udev и последующей разработки объединённой подсистемы ATA-SCSI, поддерживающей любые накопители — PATA, SATA, eSATA, SCSI, SAS, USB. И её рамках номенклатура накопителей в Linux полностью унифицировалась. Вне зависимости от типа их интерфейса, внешнего или внутреннего исполнения, файл дискового устройства стал выглядеть как /dev/sd?, где ? — литера (латинского алфавита) в порядке подключения к дисковому контроллеру:

  • сначала к внутренним SATA-разъёмам,
  • затем к дополнительному PATA-разъёму,
  • и наконец, к внешним разъёмам eSATA и USB.

Правила нумерации разделов на дисках при использовании разметки в стиле msdos остались без изменения:

  • файлы устройств первичных разделов, включая и тот, которому присвоен идентификатор расширенного, носят имена (например) от /dev/sda1 до /dev/sda4;
  • логические разделы в Extended partition по прежнему именуются от /dev/sda5 и далее.

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

Некоторые очередные коррективы в номенклатуру накопителей внесло появление интерфейса SATA-III: она оказалась зависимой от его реализации в чипсетах материнских плат или внешних контроллеров. Поскольку в чипсетах Intel 7-й серии из шести каналов SATA только два поддерживают SATA-III, оказалось, что последовательность устройств зависит от режима работы SATA-контроллера. В режиме эмуляции IDE диск на первом канале SATA-III получает имя /dev/sda, диск на первом канале SATA-II — /dev/sdb, диск на втором канале SATA-III — /dev/sdc. Диски на остальных каналах SATA-II маркируются в алфавитном порядке.

При переключении же SATA-контроллера в «родной» режим AHCI маркировка дисков становится сквозной: /dev/sda и /dev/sdb — диски на каналах SATA-III, /dev/sdc и так далее — на каналах SATA-II.

Отмеченные разночтения в именовании накопителей в десктопных конфигурациях с одним-двумя дисками обычно не создают проблем для пользователя, хотя при добавлении новых накопителей или «перетасовке» имеющихся могут возникнуть некоторые осложнения, требующие перенастройки загрузчика и (или) правки файла /etc/fstab. Потенциально проблемным может быть и обновление системы. Однако на практике с этим приходилось сталкиваться не часто. Да и с распространением Intel’овских чипсетов 8-й серии и отмиранием режима эмуляции IDE проблема вообще теряет актуальность.

Однако нынче в Linux’е применяются не только традиционные файловых системы, но и интегрированные системы размещения данных, такие, как btrfs и ZFS on Linux. Поскольку они также исполняют роль менеджеров мультидисковых устройств (подобных автономным softRAID и LVM), однозначность именования задействованных в них накопителей оказывается критически важной. Видимо, (в том числе и) поэтому наряду с «классической» номенклатурой накопителей (она именуется моделью имён верхнего уровня и поддерживается непосредственно ядром) всё более широко применяются иные модели именования. Хотя однозначность соответствия дисковых устройств их именам не менее важна и для упомянутых выше программного RAID и LVM.

Благо, правила менеджера устройств udev позволяют определять и другие модели идентификации накопителей. В частности, штатными средствами дисковой разметки некоторых дистрибутивов (в частности, системой YaST в openSUSE) предусмотрены такие варианты, как идентификация по:

  • метке тома (by-label),
  • идентификатору диска (by-id),
  • пути к дисковому устройству (by-path),
  • наконец, по пресловутому универсальному уникальному идентификатору, Universally Unique IDentifier (by-uuid).

Есть ещё несколько моделей идентификации накопителей, вроде by-partlabel или by-partuuid, но с примерами практического использования их я не сталкивался, и говорить не буду.

С идентификацией по метке тома, вероятно, многие из читателей моего сочинения знакомы — этот метод использовался задолго до появления не только udev, но даже devfs. Метка (label — не путать с disk label, то есть схемой дисковой разметки) — это просто некоторое условное имя, желательно мнемонически прозрачное. Оно присваивается дисковым разделам — либо пользователем вручную при разметке, либо генерируется автоматически инсталляторами некоторых дистрибутивов. Список «помеченных» разделов в системе можно просмотреть так:

# ls -l /dev/disk/by-label

lrwxrwxrwx ... raidboot -> ../../md0
lrwxrwxrwx ... raidroot -> ../../md1

Из этого вывода легко понять, что метки (как и все остальные имена устройств, о которых речь пойдёт ниже)— это символические ссылки на файл «верхнего уровня» (в примере — на программные RAID).

Метки тома является атрибутом раздела и не зависят от изменения имён верхнего уровня при реконфигурировании машины. Поэтому во многих случаях их удобно использовать для автоматического монтирования файловых систем, фигурирующих в файле /etc/fstab. Однако по умолчанию, насколько я знаю, ни в одном дистрибутиве Linux они не используются.

В последние годы большинство пользователей имели удовольствие ознакомиться и с идентификацией дисков и разделов по UUID — с лёгкой руки разработчиков Ubuntu по умолчанию именно они используются для описания автоматически монтируемых файловых систем во многих современных дистрибутивах.

UUID’ы представляют собой зубодробительные 128-битные числа, генерируемые для накопителей и их разделов по правилам, описываемым в библиотеке libuuid, и выглядят (в шестнадцатеричной системе счисления) примерно так:

# ls -l /dev/disk/by-uuid
итого 0
lrwxrwxrwx ... 1218e946-7f6b-4e27-beea-07fc6c06bf7a -> ../../sdc2
lrwxrwxrwx ... 2eec0b23-343f-4e3d-8507-dd042c876a60 -> ../../md0
lrwxrwxrwx ... 329f123c-17d6-4431-b4f1-583a7f59d8db -> ../../sdd1
lrwxrwxrwx ... 380c1570-d039-4ac6-ac6a-81321ea465d9 -> ../../sdc4
lrwxrwxrwx ... 9a76161d-ef7b-4a0d-afc8-c54e68857fee -> ../../sdc5
lrwxrwxrwx ... e63a68da-eb73-490b-b056-01c4945dca13 -> ../../md1
lrwxrwxrwx ... e8304d6c-a136-4c97-87d4-cb9a456af791 -> ../../sdc3

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

Если с моделями именования by-label и by-uuid, как я уже говорил, мой потенциальный читатель наверняка так или иначе сталкивался, то рискну предположить, что с идентификацией by-path и by-id дела, скорее всего, не общался. Я, например, долгое время знал о них только по наслышке — пока не начал плотное знакомство.

Модель именования by-path использует имена устройств, привязанные к их положению на шине PCI и включающие номер шины и канала на ней, примерно по тому же принципу, что и при использовании devfs (кто помнит, как оно было). Практически это выглядит примерно так:

# ls -l /dev/disk/by-path
итого 0
lrwxrwxrwx ... pci-0000:00:1f.2-scsi-0:0:0:0 -> ../../sda
lrwxrwxrwx ... pci-0000:00:1f.2-scsi-0:0:0:0-part1 -> ../../sda1
lrwxrwxrwx ... pci-0000:00:1f.2-scsi-0:0:0:0-part2 -> ../../sda2
lrwxrwxrwx ... pci-0000:00:1f.2-scsi-0:0:0:0-part3 -> ../../sda3
lrwxrwxrwx ... pci-0000:00:1f.2-scsi-1:0:0:0 -> ../../sdb
lrwxrwxrwx ... pci-0000:00:1f.2-scsi-1:0:0:0-part1 -> ../../sdb1
lrwxrwxrwx ... pci-0000:00:1f.2-scsi-1:0:0:0-part2 -> ../../sdb2
lrwxrwxrwx ... pci-0000:00:1f.2-scsi-1:0:0:0-part3 -> ../../sdb3

Легко догадаться, что дисковые разделы маркируются добавлением к имени устройства суффикса part#.

Модель именования by-path идентифицирует устройства вполне однозначно, и особенно эффективна при наличии более чем одного дискового контроллера. Однако сами имена и устройств, и разделов описываются довольно сложной для восприятия последовательностью (хотя, в отличие от UUID, и не лишённой простой человеческой логики).

Модель идентификации by-id представляет имена носителей информации в форме, наиболее доступной для людского понимания. Они образованы из названия интерфейса, имени производителя, номера модели, серийного номера устройства и, при наличии раздела, номера такового:

# ls -l /dev/disk/by-id                                    22:07 pts/4
итого 0
lrwxrwxrwx 1 ... ata-SanDisk_SDSSDX120GG25_120823400863 -> ../../sda
lrwxrwxrwx 1 ... ata-SanDisk_SDSSDX120GG25_120823400863-part1 -> ../../sda1
lrwxrwxrwx 1 ... ata-SanDisk_SDSSDX120GG25_120823400863-part2 -> ../../sda2
lrwxrwxrwx 1 ... ata-SanDisk_SDSSDX120GG25_120823400863-part3 -> ../../sda3
lrwxrwxrwx 1 ... ata-SanDisk_SDSSDX120GG25_120823402786 -> ../../sdb
lrwxrwxrwx 1 ... ata-SanDisk_SDSSDX120GG25_120823402786-part1 -> ../../sdb1
lrwxrwxrwx 1 ... ata-SanDisk_SDSSDX120GG25_120823402786-part2 -> ../../sdb2
lrwxrwxrwx 1 ... ata-SanDisk_SDSSDX120GG25_120823402786-part3 -> ../../sdb3

Таким образом, все компоненты имени устройства в модели by-id не определяются условиями его подключения и не вычисляются по каким-то заумным правилам, а определяются производителем и жёстко прошиты в «железе». Более того, они практически не зависят и от операционной системы — в этом легко убедиться, сравнив имена устройств by-id в Linux’е и DragonFly. А потому эта модель является наиболее однозначной для именования устройств. Что немаловажно, она строится по понятной человеку логике и относительно легко укладывается в нормальной голове. Не случайно именно она принята по умолчанию, например, в модуле дисковой разметки системы YaST2 дистрибутива openSUSE — самом мощном и логичном из высокоуровневых инструментов этого назначения.