Зацикленная корневая файловая система

Общие принципы зацикленных устройств и электронных дисков (Ramdisks)

Сначала я опишу некоторые общие принципы, используемые при настройке зацикленной файловой системы в качестве корневого устройства.

Зацикленные устройства

Зацикленное (loopback) устройство Linux - это виртуальное устройство, которое можно использовать так же, как и любой другой носитель информации.

Обычные носители информации - это, например, разделы жесткого диска /dev/hda1, /dev/hda2, /dev/sda1 или полностью диски, как, например, флоппи-диск /dev/fd0 и т.п. Все эти устройства могут содержать в себе файлы и структуры каталогов. Они могут быть отформатированы в формате необходимой файловой системы (ext2fs, msdos, ntfs и т.п.) и затем подключены (mount).

Зацикленная файловая система представляет файл на другой файловой системе как полноценное устройство. Она может быть отформатирована и подключена так же, как и любое другое устройство, описанное выше. Чтобы сделать это, устройства под названиями /dev/loop0, /dev/loop1 и т.п. сопоставляются с файлами, и затем может быть подключено новое виртуальное устройство.

Электронные диски

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

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

Электронный диск может быть создан в любой момент путем записи в устройство электронного диска /dev/ram0, /dev/ram1 и т.п. Затем его можно отформатировать и подключить так же, как и зацикленное устройство.

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

Загрузочный электронный диск

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

Когда используется загрузочный электронный диск, образ файловой системы загружается в память и подключается для того, чтобы файлы на нем были доступны. Затем запускается программа на этом диске (файл под именем /linuxrc), и, когда она заканчивает работу, другое устройство подключается в виде корневой файловой системы. Старый электронный диск также остается доступен и подключен к каталогу /initrd, если такой каталог присутствует, или может использоваться через устройство /dev/initrd.

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

Корневая файловая система

Корневая файловая система - это устройство, которое подключается первым, поэтому бывает представлено в виде каталога / после загрузки.

Существует некоторое количество проблем с корневой файловой системой благодаря тому факту, что она содержит все файлы. Когда загрузочные rc-скрипты загружаются, они содержатся в файлах /etc/rc.d или /etc/rc?.d, в зависимости от версии программы /etc/init.

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

Последовательность загрузки Linux

Чтобы понять, как загрузочный электронный диск работает в процессе загрузки системы, изучим порядок событий при загрузке системы.

Ядро загружается в память. Эту операцию производит LILO или LOADLIN. В этот момент выводится сообщение Loading...

Образ электронного диска загружается в память, это тоже делает LILO или LOADLIN. В этот момент также выводится сообщение Loading...

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

На загрузочном электронном диске запускается программа /linuxrc.

Корневое устройство переключается в соответствии с параметром ядра.

Запускается программа /etc/init, которая уже производит настраиваемую пользователем последовательность загрузки.

Это упрощенное описание того, что происходит на самом деле, но этого достаточно, чтобы описать, как запускается ядро и как используется электронный диск.

Как создать зацикленное корневое устройство

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

Требования

Создание зацикленного корневого устройства потребует от вас нескольких вещей.

Систему с работающим Linux-ом.

Способ скопировать большие файлы на DOS-раздел.

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

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

Вам также понадобится следующее программное обеспечение:

LOADLIN версии 1.6 или новее

mount, поддерживающий зацикленные устройства

ядро, поддерживающее все необходимые условия.

Это все должно входить в последние инсталляции дистрибутивов Linux.

Создаем ядро Linux

Я создал зацикленное устройство с использованием ядра версии 2.0.31, другие версии тоже должны работать, но они должны поддерживать все опции, перечисленные ниже.

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

Поддержка электронных дисков (RAM disk support) (CONFIG_BLK_DEV_RAM).

Поддержка загрузочного электронного диска (Initial RAM disk (initrd) support) (CONFIG_BLK_DEV_INITRD).

Поддержка зацикленных устройств (Loop device support) (CONFIG_BLK_DEV_LOOP).

Поддержка файловой системы FAT (fat fs support) (CONFIG_FAT_FS).

Поддержка файловой системы MSDOS (msdos fs support) (CONFIG_MSDOS_FS).

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

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

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

Ядра версий до 2.0.0 - у меня нет информации по этому поводу.

Ядра версий 2.0.0 - 2.0.34 - вам придется использовать патч для ядер 2.0.х, приведенный ниже.

Ядра версий 2.0.35 - 2.0.x - патч не требуется.

Ядра версий 2.1.x - вам придется использовать патч для ядер 2.0.х или 2.2.х, приведенный ниже, в зависимости от конкретной версии ядра 2.1.x.

Ядра версий 2.2.0 - 2.2.10 - вам придется использовать патч для ядер 2.2.х, приведенный ниже.

Ядра версий 2.3.x - вам придется использовать патч для ядер 2.2.х, приведенный ниже.

Для ядер версий 2.0.x в файл /init/main.c надо добавить одну строку, в соответствии с уже измененной версией, приведенной ниже. В строке, которую надо добавить написано "loop", 0x0700.

static void parse_root_dev(char * line)
{
int base = 0;
static struct dev_name_struct {
const char *name;
const int num;
} devices[] = {
{ "nfs",     0x00ff },
{ "loop",    0x0700 },
{ "hda",     0x0300 },

...

                               { "sonycd",  0x1800 },
{ NULL, 0 }
};

...

}

Для ядер версий 2.2.x в файл /init/main.c надо добавить три строки, в соответствии с уже измененной версией, приведенной ниже. Надо добавить строку, в которой написано "loop", 0x0700, а также предшествующую и следующую за ней:

static struct dev_name_struct {
const char *name;
const int num;
} root_dev_names[] __initdata = {
#ifdef CONFIG_ROOT_NFS
{ "nfs",     0x00ff },
#endif
#ifdef CONFIG_BLK_DEV_LOOP
{ "loop",    0x0700 },
#endif
#ifdef CONFIG_BLK_DEV_IDE
{ "hda",     0x0300 },

...

                { "ddv", DDV_MAJOR << 8},
#endif
{ NULL, 0 }
};

После того, как ядро настроено, его необходимо собрать в файл zImage (команда make zImage). Этот файл будет находиться в каталоге arch/i386/boot/zImage.

Создаем загрузочный электронный диск

Загрузочный электронный диск проще всего создавать, как зацикленное устройство с самого начала. Вы должны делать это в качестве root-а. Список команд, которые вы должны запустить, приведен ниже. Они предполагают запуск из личного каталога root-а (/root).

mkdir /root/initrd
dd if=/dev/zero of=initrd.img bs=1k count=1024
mke2fs -i 1024 -b 1024 -m 5 -F -v initrd.img
mount initrd.img /root/initrd -t ext2 -o loop
cd initrd
[create the files]
cd ..
umount /root/initrd
gzip -c -9 initrd.img > initrdgz.img

Здесь производится несколько действий, которые можно вкратце описать так:

Создаем точку подключения загрузочного электронного диска (пустой каталог).

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

Создаем файловую систему ext2 в пустом файле.

Подключаем этот файл к точке подключения, с использованием зацикленного устройства.

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

Создадим там все необходимые файлы (см. ниже).

Выходим из подключенного зацикленного устройства.

Отключаем устройство.

Создаем компрессированную версию для дальнейшего использования.

Содержимое загрузочного электронного диска

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

/linuxrc скрипт, который подключает файловую систему msdos (см. ниже).

/lib/* система динамических связей (dynamic linker) и библиотеки, необходимые программам.

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

/bin/* Интерпретатор оболочки (shell) (ash, потому что он меньше размером, чем bash. Программыmount и losetup для работы с DOS-диском и настройки зацикленных устройств.

/dev/* Устройства, которые будут использоваться. Вам потребуется устройство /dev/zero для библиотеки ld-linux.so, /dev/hda* для подключения msdos-диска и /dev/loop* для зацикленных устройств.

/mnt Пустой каталог для подключения msdos-диска.

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

total 18
drwxr-xr-x   2 root     root         1024 Jun  2 13:57 bin
drwxr-xr-x   2 root     root         1024 Jun  2 13:47 dev
drwxr-xr-x   2 root     root         1024 May 20 07:43 etc
drwxr-xr-x   2 root     root         1024 May 27 07:57 lib
-rwxr-xr-x   1 root     root          964 Jun  3 08:47 linuxrc
drwxr-xr-x   2 root     root        12288 May 27 08:08 lost+found
drwxr-xr-x   2 root     root         1024 Jun  2 14:16 mnt

./bin:
total 168
-rwxr-xr-x   1 root     root        60880 May 27 07:56 ash
-rwxr-xr-x   1 root     root         5484 May 27 07:56 losetup
-rwsr-xr-x   1 root     root        28216 May 27 07:56 mount
lrwxrwxrwx   1 root     root            3 May 27 08:08 sh -> ash

./dev:
total 0
brw-r--r--   1 root     root       3,   0 May 20 07:43 hda
brw-r--r--   1 root     root       3,   1 May 20 07:43 hda1
brw-r--r--   1 root     root       3,   2 Jun  2 13:46 hda2
brw-r--r--   1 root     root       3,   3 Jun  2 13:46 hda3
brw-r--r--   1 root     root       7,   0 May 20 07:43 loop0
brw-r--r--   1 root     root       7,   1 Jun  2 13:47 loop1
crw-r--r--   1 root     root       1,   3 May 20 07:42 null
crw-r--r--   1 root     root       5,   0 May 20 07:43 tty
crw-r--r--   1 root     root       4,   1 May 20 07:43 tty1
crw-r--r--   1 root     root       1,   5 May 20 07:42 zero

./etc:
total 3
-rw-r--r--   1 root     root         2539 May 20 07:43 ld.so.cache

./lib:
total 649
lrwxrwxrwx   1 root     root           18 May 27 08:08 ld-linux.so.1 -> ld-linux.so.1.7.14
-rwxr-xr-x   1 root     root        21367 May 20 07:44 ld-linux.so.1.7.14
lrwxrwxrwx   1 root     root           14 May 27 08:08 libc.so.5 -> libc.so.5.3.12
-rwxr-xr-x   1 root     root       583795 May 20 07:44 libc.so.5.3.12

./lost+found:
total 0

./mnt:
total 0

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

Файл /linuxrc

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

Скрипт, приведенный ниже пытается подключить /dev/hda1 как раздел msdos, и если это происходит удачно, то он настраивает файлы /linux/linuxdsk.img как /dev/loop0 и /linux/linuxswp.img как /dev/loop1.

#!/bin/sh

echo INITRD: Trying to mount /dev/hda1 as msdos
# echo INITRD: Попытка подключить /dev/hda1 как msdos

if /bin/mount -n -t msdos /dev/hda1 /mnt; then

   echo INITRD: Mounted OK
# echo INITRD: Подключение  успешно
/bin/losetup /dev/loop0 /mnt/linux/linuxdsk.img
/bin/losetup /dev/loop1 /mnt/linux/linuxswp.img
exit 0

else

   echo INITRD: Mount failed
# echo INITRD: Подключение не удалось
exit 1

fi

Первое устройство /dev/loop0 станет корневым, а второе - /dev/loop1 - станет swap-пространством.

Если вы хотите иметь возможность писать на DOS-раздел, не будучи root-ом, когда все будет завершено, то вы должны использовать команду mount -n -t msdos /dev/hda1 /mnt -o uid=0,gid=0,umask=000,quiet, вместо приведенной выше. В этом режиме доступ к DOS-разделу буду исполняться так, как будто это делает root.

Создаем корневое устройство

Корневое устройство, которое вы будете использовать - это файл linuxdsk.img. Его вам придется создать самим так же, как вы создавали загрузочный электронный диск, но значительно большего размера. Вы можете установить любой дистрибутив Linux, который вам понравится, на этот диск.

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

Файл /etc/fstab должен ссылаться на корневой раздел и swap-пространство через два зацикленных устройства, настроенных загрузочным электронным диском.

/dev/loop0     /      ext2   defaults 1 1
/dev/loop1     swap   swap   defaults 1 1

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

Если хотите иметь возможность читать DOS-раздел под Linux-ом? вам придется внести еще несколько небольших изменений.

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

Создайте символьную ссылку /DOS, которая будет указывать на /initrd/mnt, куда, в свою очередь, будет подключен реальный DOS-раздел.

Добавьте строку в rc-файл, которая будет подключать диски. Там должна быть команда mount -f -t msdos /dev/hda1 /initrd/mnt, которая создаст 'поддельное' подключение DOS-раздела, чтобы программы (например, df) знали, что DOS-раздел подключен, и где его найти. Если вы использовали другие опции в файле /linuxrc, то, очевидно, вам придется их использовать и здесь.

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

Создаем Swap-устройство

Swap-устройство, которое вы будете использовать - это файл linuxswap.img. Swap-устройство очень просто создать. Создайте пустой файл так же, как делали это для загрузочного электронного диска, и затем запустите mkswap linuxswap.img для его инициализации.

Размер swap-устройства, которое вы будете использовать, зависит от ваших планов по использованию новой системы, но я бы рекомендовал его от 8 Мб до размера вашей оперативной памяти.

Создаем каталог MSDOS

Файлы, которые будут нами использоваться, необходимо переписать на DOS-раздел.

В DOS-каталоге C:\LINUX должны находиться следующие файлы:

LINUXDSK.IMG Образ диска, который станет корневой файловой системой.

LINUXSWP.IMG Swap-пространство.

Создаем загрузочный флоппи-диск

Загрузочный флоппи-диск, который мы будем использовать, является простым загрузочным диском DOS.

Он создается командой DOS format a: /s.

На этом диске вам надо создать файл AUTOEXEC.BAT (пример приведен ниже) и скопировать туда ядро, компрессированный загрузочный электронный диск и программу LOADLIN.

AUTOEXEC.BAT Автоматически запускаемый командный файл DOS.

LOADLIN.EXE Программа LOADLIN.

ZIMAGE Ядро Linux.

INITRDGZ.IMG Компрессированный образ загрузочного электронного диска.

В файле AUTOEXEC.BAT должна быть только одна строка.

\loadlin \zImage initrd=\initrdgz.img root=/dev/loop0 ro

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

Загрузка системы

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

Вы увидите следующую последовательность событий.

Загрузка DOS

Запуск AUTOEXEC.BAT

Запуск LOADLIN

Загрузка в память ядра Linux

Загрузка в память загрузочного электронного диска

Запуск ядра Linux

Запуск файла /linuxrc с загрузочного электронного диска

Подключение DOS-раздела и настройка корневого и swap-устройств

Последовательность загрузки продолжается с зацикленного устройства

Когда все это пройдет, вы можете убрать флоппи-диск и использовать Linux.

Возможные проблемы и их решение

Существует ряд причин, по которым что-то в этом процессе идет не так. Я попытаюсь объяснить, в чем они заключаются, и что необходимо проверить.

Загрузку DOS легко узнать по сообщению MS-DOS Starting ... на экране. Если его нет, то диск либо не является загружаемым, либо сам компьютер не может загрузиться с этого дисковода.

Когда запускается файл AUTOEXEC.BAT, то команды, входящие в него, выводятся на экран. В нашем случае, это одна строка, содержащая запуск LOADLIN.

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

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

Когда запускается файл /linuxrc, тогда нет диагностических сообщения, но их вы можете добавить сами для того, чтобы помочь себе в поисках причин возможных проблем. Если на этой фазе не удается настроить зацикленное устройство, вы увидите сообщение о том, что "Не найдено корневое устройство (No root device)", и ядро прекратит работу.

Затем должна продолжиться нормальная последовательность загрузки уже с новой корневой файловой системой, и она также насыщена сообщениями. Могут появиться проблемы типа "Корневое устройство подключено в режиме чтение/запись", но с этим должна справиться опция 'ro' команды LOADLIN. Другая проблема, которая может возникнуть - это вопрос о реальном местоположении корневой файловой системы, это возникнет, возможно, из-за проблем с файлом /etc/fstab.

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