В сегодняшней статье мы поговорим об устройстве дисковой подсистемы в ОС Linux. Конечно, многие скажут, что на эту тему написано уже множество статей и все и так прекрасно знают, как устроен Линукс и в том числе, как он работает с дисками. Однако, как показывает практика, даже многие администраторы при работе с дисковой подсистемой ограничиваются только начальным разбиением диска при установке операционки. Да и то, с параметрами по умолчанию. Так что я предлагаю подробнее рассмотреть такие вопросы дисковой подсистемы, как: работу с правилами правила системы udev, инструменты для работы с блочными устройствами и планировщики системы ввода/вывода.
Блочные и символьные
Начнем с рассмотрения файловой системы в Линуксе. На рисунке ниже представлены компоненты операционной системы Linux.
![](https://habrastorage.org/getpro/habr/upload_files/61a/8fe/cf2/61a8fecf2ca0349c4dd77073e623bd52.png)
Помимо блочных, существуют также символьные (character device) устройства, которые используются для передачи данных побайтно, то есть без использования буфера. Здесь в качестве примеров можно упомянуть serial и parallel порт, звуковая карта, псевдоустройства /dev/random.
Посмотрим на практике, о чем идет речь:
cat /proc/devices
В начале выводятся символьные устройства:
![](https://habrastorage.org/getpro/habr/upload_files/6e4/418/af6/6e4418af695e5d22aea4ad32f4b5b007.png)
Затем блочные:
![](https://habrastorage.org/getpro/habr/upload_files/4c3/397/fd9/4c3397fd9c1502d5b89188f3cbedcb8e.png)
Также блочные устройства можно обнаружить с помощью ls -l и ls -l:
![](https://habrastorage.org/getpro/habr/upload_files/449/b10/b1b/449b10b1b74957d788e541d6228dc45d.png)
![](https://habrastorage.org/getpro/habr/upload_files/fdc/7e4/a03/fdc7e4a039d0fdcf2a68385f02ed019b.png)
Обратите внимание на индексы во втором столбце вывода. Здесь 8 это старший номер (драйвер) устройства, а 1 – 3 это младшие номера. Старший номер 8 соответствует распределению номеров для SCSI-дисков, а младший номер – это номер раздела.
Для того, чтобы сопоставить то или иное блочное устройство его имени можно воспользоваться командой blkid:
![](https://habrastorage.org/getpro/habr/upload_files/90f/6f7/3db/90f6f73dbd38a907502282052dabe54e.png)
При блочной передаче данных мы можем перемещаться по блоку данных, осуществлять в нем поиск и замену, кэшировать данные. При символьной передаче мы считываем только то, что нам передали.
Еще одна интересная команда для работы с контроллерами дисков это lspci.
![](https://habrastorage.org/getpro/habr/upload_files/e98/255/1cd/e982551cd85c6433b2d8d0ca1b9c289c.png)
Данная команда выводит информацию по контроллерам дисков в различном виде. В выделенном блоке первое число это BUS, затем DEVICE и далее FUNCTION. То есть ШИНА, УСТРОЙСТВО и выполняемые ФУНКЦИИ.
С помощью ключей можно получить более подробную информацию по устройствам, представить данные в древовидной структуре, показать ID производителей.
![](https://habrastorage.org/getpro/habr/upload_files/5e4/56b/d34/5e456bd3451aa92c4ea2c3c7727476ea.png)
Система Udev
Как мы помним, устройства в Линуксе это тоже файлы. Найти все файлы устройств можно в каталоге /dev
. Содержимое этого каталога генерируется в процессе загрузки ОС специальным сервисом udev. Генерация этих файлов-устройств осуществляется по специальным правилам уже созданных в системе. Стоит отметить, что по умолчанию в Linux уже заложены все необходимые для нормальной работы устройств правила. Но иногда может возникнуть необходимость самостоятельно настроить правила для некоторых устройств. Например, с помощью правил udev можно разрешить подключение только определенных устройств, заблокировав все остальные, переименовать или создать дополнительное имя для устройства, поменять права доступа к устройству и т. д.
Правила udev хранятся в папке /etc/udev/rules.d
. В этой папке вы можете найти несколько правил, созданных ОС по умолчанию.
Далее в качестве примера мы создадим свое правило, которое будет давать флешке с определенным ID фиксированное имя каждый раз, при ее подключении.
Для начала нам необходимо узнать, какой идентификатор используется у данной флешки. Для начала, подключим флешку и посмотрим вывод lsblk:
![](https://habrastorage.org/getpro/habr/upload_files/8a0/9d5/a15/8a09d5a1573817e996f4947c9b9b5748.png)
Теперь узнаем всю информацию для sdd1 с помощью команды:
udevadm info -n /dev/sdd1
Так как на экран будет выведено довольно много информации, можно сразу сделать выборку по ID_SERIAL
udevadm info -n /dev/sdd1 | grep ID_SERIAL
![](https://habrastorage.org/getpro/habr/upload_files/c55/838/c4f/c55838c4fb8aaeb51ac7e8a631a17180.png)
Получаем значение идентификатора. Теперь перейдем к написанию правила Udev.
Скорее всего в папке с правилами у вас еще нет файла 69-disk.rules. Если это так, тогда создадим его:
nano /etc/udev/rules.d/69-disk.rules
Правило udev состоит из нескольких пар ключ - значение, разделенных запятой. Ключи используются для проверки соответствия устройства определённому правилу (например: SUBSYSTEM == "block" или ATTR{size}=="976773168"), для указания действия, если все условия соответствия выполняются (например: NAME="mydisk" или SYMLINK+="root").
В нашем случае, содержимое файла будет следующим:
ACTION=="add", KERNEL=="sd[a-z]", ENV{ID_SERIAL_SHORT}=="0014780D6FC6FBA0A56B23B7", SYMLINK+="my_virtual_drive"
Далее сохраним изменения и проверим корректность написания правила:
udevadm test $(udevadm info --query=path --name=/dev/sda)
Далее добавим правило и перезагрузим правила в Udev.
udevadm control --reload-rules && udevadm trigger
udevadm control --reload
sudo udevadm trigger --action=add
В результате при подключении флешки в выводе
ls -l /dev/
увидим следующее:
![](https://habrastorage.org/getpro/habr/upload_files/4f6/003/234/4f6003234901a65f63c94f5440104c99.png)
Но этот пример не слишком полезен в реальной жизни, только если у вас какие-то регулярно делают копирование на съемный носитель и вам важно, чтобы этот носитель всегда имел одно и то же имя.
А вот следующий пример может оказаться более полезным на практике. В реальной жизни флешки и USB-носители могут являться источником угроз, поэтому во многих организациях блокируют доступ к USB портам различными способами. Мы решим эту проблему следующим образом: разрешим подключение клавиатуры и мыши по USB, но запретим все остальное.
Для начала предлагаю познакомиться со средством мониторинга, командой udevamd monitor
udevadm monitor
Выполним эту команду и подключим флешку:
![](https://habrastorage.org/getpro/habr/upload_files/f2b/bd0/ff7/f2bbd0ff767768422fbb4e9712f1e07b.png)
На экране будет отображен процесс успешного подключения носителя. Теперь напишем само правило.
nano /etc/udev/rules.d/10-disable-usb.rules
Первой строкой мы все запрещает (echo 0).
ACTION=="add", SUBSYSTEMS=="usb", RUN+="/bin/sh -c 'echo 0 >/sys$DEVPATH/authorized'"
Второй строкой мы разрешаем (echo 1) те устройства, в названиях которых есть упоминание USB Optical Mouse|USB Keyboard.
ACTION=="add", SUBSYSTEMS=="usb", ATTR{product}=="USB Optical Mouse|USB Keyboard", RUN+="/bin/sh -c 'echo 1 >/sys$DEVPATH/authorized'"
Применим наши изменения:
udevadm control --reload-rules && udevadm trigger
udevadm control --reload
sudo udevadm trigger --action=add
Для того, чтобы убедиться в работе нового правила используем средства отладки Udev.
Снова воспользуемся командой:
udevadm monitor
После ее запуска подключаем флешку и смотрим на отображаемые события:
![](https://habrastorage.org/getpro/habr/upload_files/570/c6e/32c/570c6e32c22ed1634b8e758c1d18a5d1.png)
Событий, связанных с подключением sdb1 не зафиксировано как и подключенного USB носителя в системе.
Планировщики ввода-вывода
Еще один интересный компонент ОС Linux о которой не все знают это планировщики ввода-вывода (I/O Scheduling). Такое название получили методы управления очередью операций ввода-вывода к жесткому диску и планировании данных операций. На практике с помощью планировщиков можно повысить производительность системы с помощью приоритезации некоторых запросов и увеличения производительности дисков.
В Linux на текущий момент существует четыре планировщика ввода-вывода:
NOOP
Anticipatory
Deadline
CFQ (Completely Fair Queuing — алгоритм полностью честной очереди)
NOOP
Планировщик NOOP получивший свое название от no operation на самом деле вовсе не является “бездельником”, который не выполняет никаких операций. Он реализует простую очередь по принципу FIFO (First In First Out) первым вошел – первым вышел. NOOP не вносит изменений в порядок следования запросов к дискам, полагаясь на контроллеры самих дисков и RAID-контроллеров.
CFQ
Планировщик CFQ (Completely fair queuing) делит пропускную способность между всеми процессами. Для синхронных запросов создается по одной очереди на процесс, в то время как асинхронные запросы объединяются в очереди по приоритетам.
Deadline
У планировщика deadline использует за основу берется время нахождения запроса в очереди. Так как большинство приложений блокируются именно на чтении, то deadline по умолчанию отдает приоритет запросам на чтение.
Anticipatory
Планировщик anticipatory при работе предполагает, что следующий запрос будет блоку, идущему после текущего, только что обработанного. После выполнения операции чтения или записи планировщик делает некоторую задержку с тем, чтобы дать приложению время послать запрос на действие со следующим блоком. Если следующий запрос действительно окажется к следующему блоку, то головка диска будет уже находиться в нужном месте и не потребуется тратить время на ее перемещение. Такой метод удобен при работе с большими файлами, последовательно размещенными на диске.
Узнать какие планировщики доступны в вашем Линуксе можно с помощью команды:
cat /sys/block/sda/queue/scheduler
На моей Ubuntu доступны два варианта:
![](https://habrastorage.org/getpro/habr/upload_files/6d0/40d/129/6d040d129caf54497f4254e057d606e9.png)
Для смены планировщика можно воспользоваться командой:
echo none >/sys/block/sda/queue/scheduler
![](https://habrastorage.org/getpro/habr/upload_files/4bb/4c7/b9d/4bb4c7b9dad3ff7e811e1aba9badcb25.png)
Рекомендации по использованию тех или иных планировщиков можно поискать в Интернете, хотя здесь все возможно несколько субъективно и необходимо тестировать. Но в общем для NVMe дисков предлагается любой из многоочередных (deadline/bfq) или NOOP для уменьшения нагрузки на процессор. Для HDD deadline если у вас сервер и bfq если десктоп.
Заключение
В этой статье мы рассмотрели некоторые аспекты архитектуры и использования дисковой подсистемы ОС Linux. Однако, за кадром осталось еще много интересного: разделы, программные и аппаратные RAID и многое другое.
В преддверии старта курса Administrator Linux. Professional приглашаю всех на бесплатный урок по теме "Каталоги /proc, /sys и /dev". Узнать подробнее о курсе и зарегистрироваться на урок можно по ссылке ниже.