1. Minix File System
Исторически так сложилось, что первой файловой системой в линуксе стала файловая система minix,
позаимствованная Линусом из одноименной операционной системы. До сих пор в исходниках ядра
присутствуют ее исходные коды. Ее можно примонтировать, и она будет работать.
В линуксовой версии этой файловой системы присутствуют ограничения, которые на данный момент уже
не позволяют эксплуатировать ее в промышленном масштабе, но в свое время она дала импульс к появлению ext2,
которая с 1994 года стала файловой системой по умолчанию.
Мы рассматриваем линуксовую реализацию файловой системы миникс, которая конечно в чем-то отличается от нативной.
В ядре линукса в ее исходниках присутствуют следы первой, второй и третьей версий.
Причем в разных ветках линуксового ядра - если сравнивать 2.6.x и 3.x.x - существуют различия
в реализациях линуксового модуля файловой системы миникс, что связано не с самой файловой ситемой,
а с реализацией VFS - виртуальной файловой системы - в самом линуксовом ядре.
Заголовок minix_fs.h в линуксовом ядре не изменился и практически полностью совпадает как в версии 2.6.32, так и в 3.4.11 .
Также, если брать основные параметры - такие как размер ноды - то они одинаковы как в линуксовой, так и в нативной
версиях - и там, и там размер ноды сначала равнялся 32 байтам, а позже стал равен 64 байтам.
Рассмотрим подробнее, как устроена фаловая система minix.
В начале диска первым блоком в любой файловой системе всегда идет загрузочный сектор размером в 512 байт.
Дальше идет суперблок, в котором записана основная информация - размер блока, число нод и т.д.
С помощью этих параметров, записываемых на диске, позже вычисляются размеры битовых карт и другие параметры.
Например, при размере блока в 1 килобайт (это один из ранних стандартов для файловой системы миникса) размер битмапа - или битовой нодоовой карты -
или просто таблицы битов, которая является хранилищем индексов нод - равен одному килобайту -
или 8 килобитам - т.е. хранит информацию о 8192 нодах.
Если например в файловой системе 10000 нод, то ей с избытком хватает всего двух блоков для размещения битмапа этих нод
(на каждую ноду - по одному биту).
Сама нода в миниксе имеет размер в 64 байта - это еще один стандарт миникса. Соответственно в одном блоке может храниться 16 нод:
64 * 16 = 1024
Суперблок миникса при записи на диск хранит следующие параметры:
число нод
число блоков, отведенных под битовую карту нод - node bit map
число блоков, отведенных под битовую карту блоков - block bit map
начальный адрес, с которого хранятся сами файлы
двоичный логарифм отношения block/zone
максимально возможный размер файла
магическое число
число блоков
struct minix_super_block {
__u16 s_ninodes; /* число нод */
__u16 s_nzones; /* число зон */
__u16 s_imap_blocks; /* число блоков */
__u16 s_zmap_blocks; /* число блоков */
__u16 s_firstdatazone; /* начало блоков с данными */
__u16 s_log_zone_size; /* размер зоны с данными */
__u32 s_max_size; /* максимальный размер файла */
__u16 s_magic; /**/
__u16 s_state; /**/
__u32 s_zones; /**/
};
После того, как суперблок считывается с диска в память, на основании этих параметров будут вычислены другие, которые на диске не хранятся:
указатель на рутовую ноду
адрес первого свободного бита в карте нод
адрес первого свободного бита в карте блоков
устанавливается флаг на чтение/запись для всей файловой системы
и т.д.
В миниксе блоки могут быть обьединены в зоны по 2, 4, 8, ... и т.д. блоков.
Зона также может быть равна одному блоку.
Битмап блоков ссылается только на блоки данных. В обоих битовых картах первый и второй биты не используются и соответственно равны 0 и 1.
Битовые карты хранят информацию о свободных/занятых блоках и нодах. Когда файл удаляется, соответствующий бит вычисляется и затем
проставляется в ноль как для карты нод, так и для карты блоков. При создании файла ищется первый свободный бит в карте нод,
проставляется в единицу, затем выделяется нода для файла. Адрес первой свободной ноды не вычисляется, он постоянно хранится
в версии суперблока, который загружен в память. Аналогично в суперблоке хранится указатель на первый свободный блок,
он не вычисляется, а сразу используется при создании файла.
Каждый файл представлен нодой. Нода хранит т.н. мета-информацию о файле: тип файла, права доступа, владельца, время создания,
размер, указатели на блоки данных. Также в ноде хранится родительская директория для файла. Указатели на блоки данных делятся на две части -
на прямые и косвенные. Прямых указателей семь штук - они указывают непосредственно на первые семь блокв данных.
Если размер данных в файле превышает семь блоков - или семь килобайт - тогда используются указатели из второй группы -
косвенный указатель и двойной косвенный указатель, которые указывают не на сами данные, а на блоки, в которых хранятся указатели
на блоки данных.
Когда файл открывается, выделяется память для его ноды, которая помещается в специальную таблицу вместе с другими открытыми нодами.
Если этот же файл открывается еще раз каким-то другим процессом, вторая нода создаваться не будет. В уже открытой ноде
будет увеличен на единицу специальный счетчик, при закрытии файла - уменьшен на единицу. Когда этот счетчик станет равен нулю,
нода будет сохранена на диск и удалена из памяти.
Адрес блока на диске имеет размер в 32 бита. Блок имеет размер в 1 килобайт. можно посчитать, сколько адресов блоков можно сохранить
в одном блоке:
1024 : 4 = 256
Т.е. один косвенный указатель может указывать еще на 256 блоков. А вот косвенный указатель второго уровня может указывать:
256 * 256 = 65536
Т.е. максимально возможный размер файла в данном случае, при наличии косвенных указателей первого и второго уровней - 64 мегабайта.
В заголовке minix_fs.h есть две версии ноды - первая и вторая:
Первая - 32-байтная, вторая - 64-байтная. Во второй присутствует дополнительный косвенный указатель третьего уровня
на блоки данных, что позволяет снять ограничение на максимальный размер в 64 мегабайта:
struct minix_inode {
__u16 i_mode;
__u16 i_uid;
__u32 i_size;
__u32 i_time;
__u8 i_gid;
__u8 i_nlinks;
__u16 i_zone[9];
};
struct minix2_inode {
__u16 i_mode;
__u16 i_nlinks;
__u16 i_uid;
__u16 i_gid;
__u32 i_size;
__u32 i_atime;
__u32 i_mtime;
__u32 i_ctime;
__u32 i_zone[10];
};
При использования косвенного указателя третьего уровня максимально возможный размер файла:
7K + 256K + 256 * 256K + 256 * 256 * 256K = 16 гигабайт
Директории в миниксе организованы в классическое дерево. Каждая директории может включать другие директории и файлы.
Директория - это файл, который имеет постоянный размер в 16 байт. Два первых байта хранят номер ноды, остальные хранят ее имя.
Т.е. все как всегда в юниксе.
Директории в том же заголовке также имеют две версии - отличие только в разрядности поля inode:
struct minix_dir_entry {
__u16 inode;
char name[0];
};
struct minix3_dir_entry {
__u32 inode;
char name[0];
};
В первом случае получаем, что для 2-байтной inode максимально возможное количество файлов во всей файловой системе равно
2^16 = 65536
Во втором случае:
2^32 = 4294967295
2. mkfs.minix
Теперь нам нужна утилита для создания партиции, куда мы положим файловую систему minix.
Эта утилита лежит в пакете util-linux.
Размер блока - MINIX_BLOCK_SIZE - ограничен и равен одному килобайту.
Как работает эта утилита ? В ее заголовке (mkfs.minix.c) по умолчанию прописана первая версия файловой системы:
int fs_version = 1;
Номер версии можно задать из командной строки с помощью параметра v:
mkfs.minix -v3 /dev/sda
В зависимости от версии утилита ведет себя по-разному. Я использовал для экспериментов чистую партицию размером в 15 гигов.
Для первой версии утилита после ее форматирования выдает следующий результат:
21856 inodes
65535 blocks
Первая зона данных=696 (696)
Размер зоны=1024
Макс. размер=268966912
Для второй версии
65535 inodes
15358108 blocks
Первая зона данных=2358 (2358)
Размер зоны=1024
Макс. размер=2147483647
Для третьей версии
5119376 inodes
15358108 blocks
Первая зона данных=60280 (322424)
Размер зоны=1024
Макс. размер=2147483647
Для первой и второй версий длина имени файла и длина директории равны соответственно 30 и 32 байтам,
для третьей - 60 и 64 байта.
Утилита mkfs.minix последовательно записывает на устройство сначала загрузочные 512 байт,
затем суперблок размером в один килобайт, затем две битовых таблицы, затем таблицу нод.
static void
write_tables(void) {
/* Mark the super block valid. */
Super.s_state |= MINIX_VALID_FS;
Super.s_state &= ~MINIX_ERROR_FS;
if (lseek(DEV, 0, SEEK_SET))
die(_("seek to boot block failed in write_tables"));
if (512 != write(DEV, boot_block_buffer, 512))
die(_("unable to clear boot sector"));
if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET))
die(_("seek failed in write_tables"));
if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE))
die(_("unable to write super-block"));
if (IMAPS*BLOCK_SIZE != write(DEV,inode_map,IMAPS*BLOCK_SIZE))
die(_("unable to write inode map"));
if (ZMAPS*BLOCK_SIZE != write(DEV,zone_map,ZMAPS*BLOCK_SIZE))
die(_("unable to write zone map"));
if (INODE_BUFFER_SIZE != write(DEV,inode_buffer,INODE_BUFFER_SIZE))
die(_("unable to write inodes"));
}
Для работы с файловой системой minix нужно включить ее поддержку в ядре:
modprobe minix
Если этого модуля не окажется, тогда его нужно будет скачать из репозиториев вашего дистрибутива,
этот модуль может называться например kmod_minix или как-то еще.
После этого файловую систему можно примонтировать командой
mount -t minix /dev/sda /mnt/sda
3. mfstools
mfstools - Minix File System Tools - пакет для работы с файловой системой миникс в обычном пользовательском режиме.
С помощью этой утилиты можно отформатировать устройство, получить статистику, добавить-удалить в устройство файл или директорию.
Она может генерировать загрузочный образ для использования в устройствах при инициализации.
Ее можно найти тут
Сгенерируем образ файловой системы в виде обычного регулярного файла и дадим ему название image_test:
dd if=/dev/zero of=image_test count=200k
Размер файла при этом 100 метров. Генерируем файловую систему minix на этом образе:
./mfstool mkfs image_test -s 100000
Дальше можно примонтировать отформатированный образ стандартным образом:
mount -t minix -o loop=/dev/loop0 image_test /mnt/test
После чего можно работать с примонтированной партицией как с нативной(при условии, что мы выполнили команду modprobe minix)
- добавлять туда каталоги и файлы.
Потом можно отмонтировать устройство:
umount /mnt/test
и мы имеем образ файловый системы на отдельном файле, который можно перенести куда угодно.
После отмонтирования устройства можно проверить, сохранились ли результаты работы:
./mfstool dir image_test /
Мы увидим, что все каталоги и файлы сохранились.
С помощью утилиты mfstool можно также на отмонтированном устройстве добавлять/удалять каталоги и файлы,
т.е. работать как с полноценной партицией, после чего можно устройство в любой момент примонтировать обратно.
|