Как создать файловую систему

Обновлено: 04.07.2024

Создание корневой файловой системы.

Обзор.

Корневая файловая система должна содержать все необходимое для поддержки полной Linux системы. Для этого диск должен удовлетворять минимальным требованиям Linux системы:

Базовая структура файловой системы,

Минимальный набор каталогов: /dev , /proc , /bin , /etc , /lib , /usr , /tmp ,

Базовый набор утилит: sh , ls , cp , mv , и т.д.,

Минимальный набор конфигурационных фалов: rc, inittab, fstab , и т.д.,

Устройства: /dev/hd*, /dev/tty*, /dev/fd0 , и т.д.,

Используемые утилитами библиотеки обеспечения базовых функций.

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

Проверить файловую систему другого устройства, например, проверить корневую файловую систему жесткого диска, у Вас должна быть возможность загрузить Linux с другого устройства - корневой дискеты. Затем Вы можете выполнить fsck на вашем основном корневом диске, в то время как он - не замонтирован.

Восстановить, все или часть вашего основного корневого устройства, из архива используя утилиты резервирования, такие как cpio , tar , gzip и ftape .

Мы опишем создание сжатой файловой системы, которая так называется, так как она сжата на диске и при загрузке распаковывается на ramdisk. Используя сжатую файловую систему, Вы можете разместить много файлов (приблизительно шесть мегабайт) на стандартную 1440КБ дискету. Так как файловая система намного больше, чем дискета, она не может поместиться на дискете. Мы должны создать ее в другом месте, сжать и затем скопировать на дискету.

Создание файловой системы

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

Использовать ramdisk ( DEVICE = /dev/ram0 ). В этом случае для имитации диска используется память. Ramdisk должен быть достаточного объема для размещения файловой системы соответствующего размера. Если Вы используете LILO, проверьте в вашем конфигурационном файле ( /etc/lilo.conf ) строчку RAMDISK = nnn , Которая определяет максимальный объем оперативной памяти выделяемой ramdisk. Значение по умолчанию 4096КБ, которого должно быть достаточно. Вы не должны пытаться использовать такой ramdisk на машине с объемом памяти менее 8МБ. Проверьте, что у Вас есть устройства /dev/ram0, /dev/ram или /dev/ramdisk . Если их нет - создайте /dev/ram0 командой mknod (старший номер 1, младший 0).

Если у Вас есть достаточно большой (несколько мегабайт) неиспользуемый раздел жесткого диска, это приемлемо.

Использовать петлевое (loopback) устройство , которое позволяет обращаться с файлом на диске как с устройством. При использовании петлевого устройства Вы можете создать трех мегабайтный файл на вашем жестком диске и сформировать на нем файловую систему.

Для инструкций об использовании петлевых устройств, наберите man losetup . Если у Вас нет losetup , Вы можете получить ее вместе с совместимыми версиями mount и unmount из пакета util-linux в каталоге ftp://ftp.win.tue.nl/pub/linux/utils/util-linux/ .

Если на вашей системе нет петлевого устройства ( /dev/loop0 , /dev/loop1 , и т.д.), Вы должны его создать командой `` mknod /dev/loop0 b 7 0 ''. Как только вы установите особые mount и umount , создайте на жестком диске достаточного объема временный файл (например, /tmp/fsfile ). Для создания nnn -блочного файла можно использовать команду:

После того, как вы выбрали один из этих вариантов, подготовьте DEVICE :

Эта команда обнуляет устройство.

Так что Ваша команда выглядит так:

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

Команда mke2fs автоматически обнаружит доступное пространство и соответственно сконфигурируется. Параметр `` -m═0 '' предотвращает от резервирования пространства для root, и, таким образом, обеспечивает больше используемого пространства на диске.

Затем, примонтируйте устройство: ( Если каталог монтирования /mnt не существует - Вы должны создать его.) В следующих секциях, все имена каталогов назначения полагаются относительно /mnt .

Заполнение файловой системы.

Существует разумный минимальный набор каталогов для вашей корневой файловой системы: [1] :

/dev -- Устройства, требуемые для ввода/вывода

/proc -- каталог-заглушка, необходимый для файловой системы proc

/etc -- системные конфигурационные файлы

/sbin -- критичные системные исполняемые файлы

/bin -- необходимые исполняемые файлы, часть предполагаемой системы

/lib -- общие библиотеки, для обеспечения средств динамической поддержки (run-time)

/mnt -- точка монтирования для поддержки других дисков

/usr -- дополнительные утилиты и приложения

Три из этих каталогов должны быть пусты на корневой файловой системе, т.о. они должны быть просто созданы командой mkdir . Каталог /proc - просто заглушка, в которой размещается файловая система proc. Каталоги /mnt и /usr - всего лишь точки монтирования для использования после того, как загрузочная/корневая система будет запущена. Следовательно, эти каталоги должны быть только созданы.

Оставшиеся четыре каталога описаны в следующих секциях.

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

Если Вы хотите пойти трудным путем, используйте ls -l , для вывода старших(major) и младших (minor) чисел нужных вам устройств, и создайте их на дискете, используя mknod .

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

Обратите внимание, что для каждого файла устройства требуется один inode, и inode может быть дефицитным ресурсом, особенно для файловой системы дискеты. Вам следует быть переборчивым при копировании файлов устройств. Например, если у Вас нет SCSI дисков, Вы можете с уверенностью игнорировать /dev/sd* ; если Вы не предполагаете использовать последовательный порт, вы может игнорировать /dev/ttyS* .

Если при копировании файлов вы получаете ошибку No space left on device , а df показывает что свободное место все еще есть, возможно, вы исчерпали inodes. Использование inodes вам покажет df -i

Каталог /etc содержит конфигурационные файлы. Его предполагаемое содержимое зависит от состава предполагаемых к использованию программ. На большинстве систем, они могут быть разделены на три группы:

Требуемые всегда, такие как rc , fstab , passwd .

Которые могут потребоваться, но не обязательно.

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

Те, которые я должен сконфигурировать для загрузочной/корневой системы:

rc.d/* -- скрипты запуска системы и изменения уровня выполнения

fstab -- список монтируемых файловых систем

inittab -- параметры init процесса, - первого запускаемого во время начальной загрузки процесса.

gettydefs -- параметры для процесса init , первого запускаемого при загрузке процесса.

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

passwd -- список необходимых пользователей, домашних каталогов, и т.д.

termcap -- база данных возможностей терминалов.

Если безопасность важна, passwd , и shadow должны быть урезаны, чтобы избежать копирования паролей пользователей вне системы, и, таким образом, при загрузке с дискеты нежелательные входы в систему будут отвергаться.

termcap , база данных терминалов, обычно несколько сотен килобайт. Версия этого файла на вашей загрузочной дискете должна быть урезана, чтобы содержать параметры только используемого Вами терминала(ов), обычно это всего лишь элемент linux или linux-console .

Остальные. В данный момент они работают, так что я их оставлю.

Помимо этого, мне остается сконфигурировать всего лишь два файла, и их содержимое удивительно невелико.

fstab должен содержать, по крайней мере: Вы можете скопировать элементы из вашего существующего fstab , но Вам не следует автоматически монтировать все разделы вашего жесткого диска; используйте для них ключевое слово noauto . Когда используется загрузочная дискета, Ваш жесткий диск может быть поврежден или мертв.

Ваш inittab должен быть изменен так, чтобы строка sysinit выполняла rc , или любой другой основной сценарий начальной загрузки, который будет использоваться. Также, если Вы хотите запретить пользователям входить в систему по последовательным портам, закомментируйте все записи для getty , которые в конце строки содержат устройства ttys или ttyS . Оставьте порты tty , чтобы Вы могли входить в систему с консоли.

Обратите внимание, что некоторые программы не могут быть размещены в другом месте, так как другие программы жестко связаны с их расположением. Например, в моей системе, /etc/shutdown жестко связан с /etc/reboot . Если я перемещу reboot в /bin/reboot , и затем подам команду shutdown , она не выполнится, так как не сможет найти файл reboot .

Большинство теперешних систем использует каталог /etc/rc.d/ , содержащий сценарии оболочки для различных уровней выполнения. Минимум - одиночный rc скрипт, но может быть проще скопировать из вашей существующей системы inittab и каталог /etc/rc.d , и сократить сценарии оболочки в каталоге rc.d , для удаления всего, не относящегося к окружению системной дискеты.

/bin и /sbin

В этом случае Вам нужна libc-2.1.1.so . Чтобы найти другие библиотеки, Вы должны пройтись по всем исполняемым файлам, которые Вы планируете включить, и командой ldd проверить их зависимости. Например: Каждый файл справа - нужен. Имейте в виду, что перечисленные библиотеки могут быть символическими ссылками.

Обеспечение PAM и NSS.

Ваша система может требовать динамически загружаемые библиотеки, которые не видны ldd . Если вы их не предусмотрите, у Вас могут возникнуть проблемы при входе в систему или использовании вашего загрузочного диска.

PAM (Pluggable Authentication Modules)

Если ваша система использует PAM (Pluggable Authentication Modules), Вы должны это предусмотреть в вашем загрузочном диске. PAM - изощренный модульный метод идентификации пользователей и управления их доступом к службам. Простой способ проверки того, использует ли ваша система PAM, состоит в запуске ldd для исполняемого файла login . Если выдаваемая информация включает libpam.so - вам нужен PAM.

К счастью, безопасность не имеет значения для загрузочных дисков, т.к. если кто-либо имеет физический доступ к машине, он может сделать все, что захочет. Следовательно, вы можете фактически запретить PAM, создав в вашей корневой файловой системе простой файл /etc/pam.conf , который выглядит примерно так: Также скопируйте в вашу корневую файловую систему файл /lib/security/pam_permit.so . Эта библиотека приблизительно 8Кб, т.о. она налагает минимальные накладные расходы.

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

Вы также должны включить в ваш загрузочный диск /lib/libpam.so . Но Вы уже это знаете, т.к. запускали ldd для /bin/login , которая показала эту зависимость.

NSS (Name Service Switch)

Если Вы используете glibc (иначе называемый libc6) Вы должны обеспечить name services или вы не сможете войти в систему. Файл /etc/nsswitch.conf управляет поиском по базам данных различных служб. Если вы не планируете доступ к сетевым службам (таким как DNS, NIS), то Вы должны подготовить простой файл nsswitch.conf , который выглядит так: Это указывает, что каждая служба будет использовать только локальные файлы. Также Вы должны включить /lib/libnss_files.so. X , где X равен 1 для glibc2.0 и равен 2 для glibc2.1. Эта библиотека динамически загружается для поиска по файлам.

Если вы планируете доступ к сети с вашего загрузочного диска, вы должны создать более продуманный файл nsswitch.conf . Для подробностей смотрите man страницу nsswitch . Для каждого указанного типа службы service Вы должны включить файл /lib/libnss_ service .so.1

Модули

Если у Вас модульное ядро, Вы должны обдумать, какие модули Вы захотите загружать с вашего загрузочного диска после загрузки. Если у Вас есть ленточные устройства резервирования, то Вы, возможно, захотите включить модули ftape и zftape , модули для SCSI устройств, если они у Вас есть, и, возможно, модули PPP или SLIP, если хотите иметь доступ к сети при аварии.

Эти модули могут быть помещены в /lib/modules . Вы должны также включить insmod , rmmod и lsmod . В зависимости от того, хотите ли Вы загружать модули автоматически, Вы можете также включить modprobe , depmod и swapout . Если Вы используете kerneld , включите его вместе с /etc/conf.modules .

Некоторые заключительные подробности.

Перенос.

Представленная здесь структура каталогов - только для использования в корневой дискете. Реальные Linux системы имеют более полный и четкий набор правил размещения файлов, называемый Стандарт Файловой Иерархии (File Hierarchy Standard).

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

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

В этой статье мы рассмотрим как выполняется работа с файловой системой Linux в терминале. За основу возьмем семейство файловых систем ext2/3/4, так как они самые распространенные среди большого многообразия дистрибутивов Linux.

Основные команды

Для управления файловой системой ext в Linux используется целый набор команд из пакета e2progs. Сюда входят как команды для управления флагами файлов, создания и изменения файловых систем, так и утилиты для отладки файловой системы.

Рассмотрим основные утилиты, которые будем использовать:

  • badblocks - если у вас старый жесткий диск и на нем накопилось много битых блоков, вы можете с помощью этой утилиты пометить их все на уровне файловой системы, чтобы больше не использовать.
  • e2label - позволяет изменить метку раздела с файловой системой ext.
  • fsck - проверка файловой системы linux и исправление найденных ошибок
  • mkfs - позволяет создать файловую систему Linux.
  • resize2fs - изменить размер раздела с файловой системой
  • tune2fs - позволяет изменить файловую систему Linux, настроить ее параметры.

А теперь будет рассмотрена работа с файловой системой linux на примерах.

Работа с файловой системой в Linux

Перед тем как переходить к работе с реальным жестким диском важно попрактиковаться. Если сменить метку или проверить на битые сектора можно и рабочий диск, то создавать новую файловую систему, изменять ее размер, рискуя потерять данные на реальном диске не рекомендуется. Можно отделить небольшой раздел диска для экспериментов с помощью Gparted и выполнять все действия в нем. Допустим, у нас этот раздел будет называться /dev/sda6.

Создание файловой системы

Создать файловую систему linux, семейства ext, на устройстве можно с помощью команды mkfs. Ее синтаксис выглядит следующим образом:

sudo mkfs -t тип устройство

Доступны дополнительные параметры:

  • -с - проверить устройство на наличие битых секторов
  • -b - размер блока файловой системы
  • -j - использовать журналирование для ext3
  • -L - задать метку раздела
  • -v - показать подробную информацию о процессе работы
  • -V - версия программы

Создаем файловую систему на нашем устройстве. Будем создавать ext3:

sudo mkfs -t ext4 -L root /dev/sda6

Creating filesystem with 7847168 4k blocks and 1962240 inodes
Filesystem UUID: 3ba3f7f5-1fb2-47af-b22c-fa4ca227744a
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000
Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

Изменение метки файловой системы

Утилита e2label позволяет изменить или посмотреть метку раздела диска. Принимает всего два параметра - устройство и новую метку если нужно.

sudo e2label /dev/sda6

sudo e2label /dev/sda6 root1

Настройка файловой системы linux

Различные параметры файловой системы, такие как размер блока данных, иноды или зарезервированное место под данные пользователя root можно настроить. Для этого существует утилита tune2fs.

Синтаксис команды очень прост:

$ tune2fs опции устройство

Поддерживаются следующие опции:

  • -j - создать файл журнала. Позволяет превратить файловую систему ext2 в ext3.
  • -J - настроить параметры журнала
  • -l - получить содержимое суперблока
  • -L - изменить метку раздела
  • -m - изменить процент дискового пространства, зарезервированного для суперпользователя
  • -M - изменить последнюю папку монтирования
  • -U - задать UUID файловой системы
  • -C - изменить значение счетчика монтирования
  • -T - изменить последнюю дату проверки файловой системы
  • -с - изменить периодичность проверок файловой системы с помощью fsck
  • -O - изменить опции файловой системы.

Изменить размер зарезервированного места для суперпользователя до пяти процентов:

sudo tune2fs -m 5 /dev/sda6

Setting reserved blocks percentage to 5% (392358 blocks)

Посмотреть информацию из суперблока, эта команда показывает всю доступную информацию параметрах файловой системы:

Изменить счетчик количества монитрований:

tune2fs -C 0 /dev/sda6

Setting current mount count to 0

Думаю тут смысл понятен, нужно только немного со всем этим поэкспериментировать.

С помощью опции -O мы вообще можем превратить нашу ext3 в ext4 следующей командой:

sudo tune2fs -O extents,uninit_bg,dir_index

После этого действия нужно выполнить проверку файловой системы на ошибки в fsck. Подробнее об этом поговорим ниже.

sudo fsck -np /dev/sda6

Таким образом вы можете изменить файловую систему linux, и настроить по своему усмотрению любые ее параметры.

Изменение размера файловой системы Linux

Раньше такая функция поддерживалась в утилите parted, но потом ее убрали и для этого действия приходится использовать утилиту из набора e2fsprogs - resize2fs.

Запустить утилиту очень просто. Ей нужно передать всего два параметра:

$ resize2fs [опции] устройство размер

Доступны также опции:

  • -M уменьшить файловую систему до минимального размера
  • -f - принудительное изменение, не смотря на потерю данных
  • -F - очистить буфер файловой системы

Размер передается, как и во многих других утилитах, целым числом с указанием единиц измерения, например, 100М или 1G.

Для примера уменьшим размер нашего раздела до 400 Мегабайт:

sudo resize2fs /dev/sda6 400M

Resizing the filesystem on /dev/sda7 to 102400 (4k) blocks.
The filesystem on /dev/sda7 is now 102400 blocks long

Проверка файловой системы Linux

При неправильном отключении носителей или неожиданном отключении питания, файловая система Linux может быть повреждена. Обычно проверка корневой файловой системы и домашнего каталога на ошибки выполняется во время загрузки. Но если эта проверка не была выполнена или нужно поверить другой носитель, придется все делать вручную. Для этого есть утилита fsck.

$ fsck [опции] устройство

  • -p - автоматическое восстановление
  • -n - только проверка, без восстановления
  • -y - ответить да на все запросы программы
  • -с - проверить на битые сектора (аналог badblocks
  • -f - принудительная проверка, даже если раздел помечен как чистый
  • -j - внешний журнал файловой системы

Проверка файловой системы Linux выполняется такой командой, проверим диск /dev/sda6, заметьте, что диск должен быть не примонтирован:

sudo fsck -a /dev/sda6

root: clean, 11/32704 files, 37901/102400 blocks

Дефрагментация файловой системы

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

Чтобы проверить нужна ли дефрагментация в Linux выполните эту же команду с опцией -c:

Total/best extents 26247/24953
Average size per extent 1432 KB
Fragmentation score 0
[0-30 no problem: 31-55 a little bit fragmented: 56- needs defrag]
This device (/dev/sda6) does not need defragmentation.
Done.

В поле Fragmentation score отображен процент фрагментации, как видите, у меня 0, нормой считается до 30, 31-55 небольшие проблемы, и больше 56 - нужна дефрагментация.

Выводы

В одной из предыдущих статей мы рассмотрели как выполняется разметка диска с помощью parted. Из этой статьи вы узнали все что нужно о работе с файловой системой. Теперь у вас не возникнет проблем если у вас вдруг не будет доступа к графическим утилитам и нужно будет исправлять ошибки или настраивать файловую систему. Если остались вопросы, спрашивайте в комментариях!


Если знаком с утилитой CyberSafe Top Secret, то ты, наверное, тоже столкнулся с тем, что добавлять файлы в контейнер неудобно. Совсем другое дело — VeraCrypt: монтируешь локальный диск, и файлы шифруются на лету. Именно так будет работать наш проект.

Теория



Получив список занятых букв, файловый менеджер последовательно опрашивает систему о том, какие метки тома у этих дисков, сколько на них осталось места, какая файловая система и так далее. Каждый такой запрос передается первому драйверу в цепочке. Если тот не знает, что ответить, он спрашивает следующий, тот в свою очередь — дальше. И так, пока какой-либо из них не ответит, что нужная инфа найдена (или не найдена). В реальности эта схема несколько сложнее, но для общего понимания этого достаточно.

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

Любой драйвер средствами все того же диспетчера ввода-вывода может что-нибудь спросить у любого приложения, работающего в user-mode, что и используется в драйвере FUSE.

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

Результат создания своего драйвера ФС

Результат создания своего драйвера ФС

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

Dokan

В теории существует версия FUSE для Windows, однако заставить ее работать мне не удалось. Возможно, это было бы само по себе интересным опытом, но я избрал другой путь.

От изначального проекта Dokan сейчас осталось очень мало. После версии 0.6.0 появился серьезно доработанный форк под названием Dokany. Теперь жив только Dokany, и, соответственно, мы будем использовать его. В дальнейшем, говоря о Dokan, я буду подразумевать именно Dokany.

Подготовка

Чтобы использовать Dokan, нам понадобится драйвер. К нашему счастью, есть уже готовые собранные драйверы, которые нужно только установить. Тут есть три варианта. Первый — воспользоваться автоматическим установщиком. Второй — скачать собранные бинарники (они уже подписаны) и встроить их в свой установщик. Ну и третий — скачать исходный код, благо он открыт (часть проекта распространяется по лицензии LGPLv3, часть — по MIT), и собрать все самостоятельно.

Загруженный драйвер dokan1.sys

Загруженный драйвер dokan1.sys

Чтобы установить вручную, придется скачать более объемный файл. Кроме драйверов, он содержит и нужные тебе библиотеки (если ты знаешь C++), так что не спеши удалять его после установки.

Нас же сейчас интересует папка x64 (у тебя ведь 64 бита?). В ней — набор папок, как на картинке.

Содержимое папки x64

Содержимое папки x64

У меня Windows 8.1, так что иду в соответствующую папку (рекомендую Release) и, ткнув по inf-файлу правой кнопкой мышки, выбираю «Установить». Подтверждаю запрос UAC и жду окончания процесса, после чего перезагружаю машину.

Теперь установка должна пройти успешно. Если что-то не получилось — убедись, что ставишь ту версию драйвера.

В этом может помочь утилита DriverView.

Кроме Dokan, нам еще понадобится Visual Studio. Недавно вышла версия 2019, так что, даже если у тебя уже установлена, советую обновиться. С приготовлениями все, переходим к кодингу.

WARNING

Любые вмешательства в файловую систему, в том числе создание своей ФС, могут повредить или уничтожить твои данные. Все описанное в статье ты повторяешь на свой страх и риск. Ни автор, ни редакция «Хакера» не несут ответственности за твои действия. Все операции рекомендуем предварительно выполнять в виртуальной машине.

Кодинг



Проект создали, и теперь нашему взору предстала заглушка метода Main. Ты ведь установил NuGet вместе со «Студией»? Если нет, устанавливай. Оттуда мы ставим пакет DokanNet (Tools → NuGet Package Manager → Manage NuGet Packages for Solution). Любители командной строки могут открыть PowerShell-консоль NuGet (Tools → NuGet Package Manager → Package Manager Console) и выполнить Install-Package DokanNet .



Чтобы создать свою ФС, нам нужен класс, реализующий IDokanOperations . Создаем новый класс ( Ctrl + Shift + A ) и добавляем туда using DokanDet; . Наш класс должен реализовывать интерфейс IDokanOperations , так что исправляем class XakepFSClass на class XakepFSClass : IDokanOperations .



Как ты видишь, в 10-й строке ошибка. Конечно, мы же унаследовали кучу методов от интерфейса, но не реализовали их. Я знаю, ты не хочешь объявлять каждый метод вручную, поэтому поставь курсор на неугодное выражение ( IDokanOperations в 10-й строке) и нажми Alt + Enter . В появившемся меню выбери Implement interface.



Теперь порядок! Но все методы выкидывают исключение NotImplementedException, что нам никак не подходит. Давай-ка реализуем Hello World, а затем — ФС, хранящую все данные в JSON.

HelloWorldFS

Поскольку это просто Hello World, я не хочу изменять файл, который мы только что создали. Сделаем его копию, переименуем для лучшего восприятия (для переименования выбери файл в правой панели и нажми F2). Теперь откроем наш новый класс и переименуем и его, а то компилятор не поймет наши фокусы. У тебя должно получиться как на скриншоте.

Продолжение доступно только участникам

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Исходные данные и результаты работы программ должны где-то храниться для дальнейшего использования. Их хранение нужно организовать так, чтобы мы могли быстро получить нужную информацию. За эту задачу отвечает Файловая система (FS): она предоставляет абстракцию для устройств, на которых физически хранятся данные.

В этом посте мы больше узнаем о концепциях, используемых файловыми системами, и о том, как, зная их, можно написать свою файловую систему на языке Rust.


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

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

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

На следующем рисунке приведен пример того, как файловая система структурирует информацию на диске:


Далее мы разберёмся, какие бывают типы блоков.

Суперблоки и битовые карты (bitmaps)

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

Битовые карты являются одним из способов отслеживания того, какие блоки данных и индексные дескрипторы (иноды) являются свободными. Каждому сектору в файловой системе соответствует один бит карты. Если сектор занят, то значение соответствующего бита в битовой карте устанавливается в 1, если свободен — в 0.

Инод — это структура, в которой хранятся метаданные о файле: разрешения, размер, расположение блоков данных, из которых состоит файл и многое другое.

Иноды хранятся вместе с блоками, которые вместе образуют таблицу инодов, как показано на следующем рисунке.


Для каждого сектора в битовой карте инодов с индексом, установленным в 1, в таблице будет соответствующий инод. Индекс сектора совпадает с индексом в таблице.

Блоки данных

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

Указатели на блоки данных

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


Чтобы получить представление о максимальном размере файла для каждого уровня, давайте возьмём фиксированный размер блока в 4 КиБ. Большинство файлов имеют небольшой размер, поэтому 12 прямых указателей позволят хранить файлы размером до 48 КиБ. Учитывая, что каждый указатель занимает 4 байта, один косвенный указатель позволит увеличить размер файла до 4 МиБ:


С введением двойных косвенных указателей размер файла вырастает до 4 ГиБ:


С добавлением тройных косвенных указателей мы получаем 4 TиБ:


Поэтому такой подход может быть не очень эффективным для обработки больших файлов.

Например, файл размером 100 МБ потребует 25600 блоков. В случае фрагментации блоков на диске производительность может сильно пострадать.

Некоторые файловые системы используют экстенты, которые позволяют объединить несколько логических блоков. В этом случае мы используем один указатель и задаём длину диапазона объединённых блоков. В нашем примере выше для описания файла будет использован один экстент размером 100 МБ. Для работы с более крупными файлами можно использовать несколько экстентов.

Каталоги

Возможно, вы заметили, что у каталогов нет собственной структуры. Дело в том, что инод представляет как файлы, так и каталоги. Разница заключается в том, что именно хранится в соответствующих блоках данных. Каталог — это по сути список всех файлов, которые он включает. Каждая запись имеет вид (имя, порядковый номер), поэтому при поиске определённого файла (или другого каталога) система использует имя для поиска соответствующего инода.

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

Чтение и запись

Чтение

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

Запись

Для записи в файл нужно выполнить тот же поиск, чтобы найти соответствующий инод. Если для записи требуется новый блок, файловая система должна выделить этот блок, обновить соответствующую информацию (битовую карту и инод) и выполнить запись в него. Таким образом, для одной операции записи требуется пять операций ввода-вывода: одна операция чтения в битовую карту, одна запись, чтобы пометить новый блок как занятый, две операции чтения и записи в инод и одна запись данных в блок. А при создании нового файла это количество может увеличиться, поскольку теперь понадобится обновление данных его каталога и создание новых инодов.

Моя файловая система (GotenksFS)

Я некоторое время изучал язык Rust и решил написать на нём свою собственную файловую систему. Я во многом опирался на ext4, а также использовал FUSE, свободный модуль для ядер UNIX-подобных ОС. Вместо диска я использовал обычный файл. Размер блока можно выставить в 1 КиБ, 2 КиБ или 4 КиБ. Файлы могут иметь размер до 4 ГиБ для блоков размером 4 КиБ. Потенциально файловая система может занимать до 16 ТиБ.

Начинаем

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


После выполнения команды создаётся образ с общим размером 10 ГиБ, а каждый блок в файловой системе имеет размер 4 КиБ.

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

Монтирование

После создания образа нам нужно смонтировать его, чтобы мы могли начать его использовать. Для этого используем команду mount:



Основные структуры

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


Следующие два блока — это битовые карты для данных и для инода. Для таблицы инодов используется набор из n блоков. А в последующие блоки будут записываться пользовательские данные.

Инод я сформировал так:


Я реализовал поддержку двойных косвенных указателей — то есть, для диска с размером блока 4 КиБ максимальная ёмкость файла составит 4 ГиБ. Количество прямых указателей я ограничил двенадцатью:


При первом запуске FS она создаёт корневой каталог:

Формируем группы блоков

Размер битовой карты для инода равен 4 КиБ, то есть в каждом блоке можно разместить 32768 инодов. Округлим это число до 128 байт: соответствующая таблица инодов потребует 4 МБ свободного места. Один из способов их структурирования выглядит так: есть множество блоков, выделенных для битовых карт, затем соответствующие числовые блоки для хранения инодов и оставшиеся блоки для пользовательских данных.

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


Реализуем чтение и запись

Когда наш «диск» создан, можно заняться файловыми операциями. Создадим новый каталог с помощью mkdir:

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

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

Аргументами функции записи служат путь, буфер с данными, смещение и структура с информацией о файле, которая может содержать дескриптор файла вместе с другой, дополнительной, информацией о нём:

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


Теперь, когда FS имеет информацию о том, какие блоки данных выделены для инода, она может использовать их для поиска точного адреса, чтобы записать туда данные. Новые блоки сначала добавляются в массив прямых указателей, и если размер файла превышает (12 * BLOCK_SIZE), FS выдаёт косвенный указатель (поле indirect_block). Для очень больших файлов система добавляет двойной косвенный указатель, используя поле double_indirect_block. Чтение из файла реализуется аналогично.

Ниже вы можете увидеть, как у меня работают чтение и запись:

Вывод

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

Важный момент — реализация косвенных указателей для хранения больших файлов. Если вам интересно узнать о файловых системах больше, я бы рекомендовал почитать о таких вещах, как журналирование, копирование при записи (Copy-On-Write), Лог-структурированные файловые системы.

На правах рекламы

Эпичные серверы — это надёжные серверы на Linux или Windows с мощными процессорами семейства AMD EPYC и очень быстрой файловой системой, используем исключительно NVMe диски от Intel. Попробуйте как можно быстрее!

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