- Исследуем процесс загрузки Linux
- Этап 3: Загрузчик 2 этапа операционной системы
- 3.2. Файл /boot/initrd и его назначение
- 3.2.1. Внутреннее устройство initrd
- 3.2.2. Загрузка системы в случае использования initrd (ядра версий 2.4.х)
- 3.2.3. Initramfs — новая модель инициализации (ядра версий 2.6.х)
- initrd — Initial RAM disk
- Что такое загрузочный RAM диск?
- Внутреннее устройство initrd
- Утилиты для создания образа initrd
- Создание вручную индивидуального образа initrd
Исследуем процесс загрузки Linux
(C) В.А.Костромин, 2007
(версия файла от 5.10.2007 г.)
Этап 3: Загрузчик 2 этапа операционной системы
3.2. Файл /boot/initrd и его назначение
Как было сказано в предыдущем разделе, в процессе начальной загрузки вначале монтируется временный виртуальный диск, содержащий корневую файловую систему (очевидно, тоже временную), с помощью которой осуществляется запуск на выполнение ядра операционной системы. Образ этой корневой системы хранится на загрузочном устройстве в каталоге /boot и обычно носит имя initrd-2.x.yy-zzzz (точное наименование файла смотрите в вашей системе, далее он будет именоваться просто initrd). Загрузчик переносит образ корневой файловой системы из файла initrd в оперативную пямять одновременно с образом ядра, ядро преобразует initrd в «нормальный» RAM диск, монтирует временную корневую файловую систему, извлекает из нее нужные драйверы и другие служебные файлы, с помощью которых инициализирует все необходимые устройства. После этого происходит перемонтирование корневой файловой системы, временная ФС заменяется на постоянную, размещающуюся уже на долговременном носителе и процесс загрузки системы продолжается.
После того, как будет смонтирована корневая файловая система с жесткого диска, файл initrd уже никак не используется и место, занимаемое им в памяти, тоже освобождается. А теперь давайте подробнее рассмотрим как устроен этот файл. При этом надо сразу сказать, что внутреннее устройство initrd и его применение в ядрах версий 2.6 было изменено по сравнению с ядрами версий 2.4, так что придется рассмотреть эти случаи по отдельности.
3.2.1. Внутреннее устройство initrd
Как сказано в статье [10] в дистрибутиве Fedora Core 3 (и его предшественниках) файл initrd создавался с использованием виртуального loop-устройства. В этом случае сделать содержимое файла initrd доступным для просмотра можно с помощью следующих команд (напомню, что имя вашего образа initrd может отличаться):
В таких дистрибутивах, как Fedora Core 4, SUSE 10, . файл initrd представляет собой cpio-архив, сжатый упаковщиком gzip. Чтобы просмотреть его содержимое, надо выполнить команды, приведенные в листинге 3
/tmp вы найдете каталоговую структуру, аналогичную структуре каталогов обычной Linux-системы. В ней вы обнаружите обычные для корневого каталога подкаталоги, а также файл linuxrc. Могут там оказаться и другие файлы, например, файл bootsplash (судя по названию он содержит картинку, которая отображается при запуске).
Познакомившись с внутренним содержанием файла initrd можно вернуться к рассмотрению его роли в процессе загрузки.
3.2.2. Загрузка системы в случае использования initrd (ядра версий 2.4.х)
Приводимое ниже описание последовательности операций на этапе загрузки я позаимствовал из [11,12].
1. Загрузчик загружает ядро и содержимое initrd в память (очевидно, по вполне определенным адресам . ), после чего передает управление ядру.
2. Ядро содержит в себе небольшую несжатую часть, которая вначале разархивирует само ядро. Видимо как раз на этом этапе на экране монитора отображается сообщение «Uncompressing Linux. Ok, booting the kernel.»
3. Ядро инициализирует устройства, создает файловую систему устройств /dev, разархивирует initrd и копирует его содержимое на устройство /dev/ram0, а затем освобождает память, занятую initrd.
4. Ядро монтирует устройство /dev/ram0 для чтения и записи в качестве начальной корневой файловой системы.
5. Если в начальной корневой файловой системе находится исполняемый файл /linuxrc, он исполняется с uid 0. Этот файл должен иметь разрешения на исполнение, он может быть как обычным исполняемым файлом, так и просто скриптом оболочки, но в последнем случае должен быть и интерпретатор скриптов.
6. Cкрипт /linuxrc монтирует нормальную корневую файловую систему.
7. Корневая файловая система помещается в корневую директорию. Смена корневого устройства выполняется системным вызовом pivot_root, который также доступен через утилиту pivot_root (см. pivot_root(8); pivot_root распространяется в составе util-linux версии не ниже 2.10h ). Смена корневой директории не включает её демонтирование. Следовательно, при выполнении данной процедуры можно сохранить процессы, запущенные с файловой системы initrd.
8. Если нормальная корневая файловая система имеет каталог /initrd, то устройство /dev/ram0 перемещается из / в /initrd. Иначе, если каталог /initrd не существует, устройство /dev/ram0 размонтируется.
9. На нормальной корневой файловой системе следует обычная процедура загрузки (например, вызов /sbin/init).
10. Теперь можно демонтировать /dev/ram0 и освободить память, занятую RAM диском.
3.2.3. Initramfs — новая модель инициализации (ядра версий 2.6.х)
Во-первых, виртуальный диск, как и все блочные устройства, требует драйвер файловой системы для интерпретации данных во время выполнения. Этот драйвер приходилось включать в ядро.
Во-вторых, неэфективно используется оперативная память, так как размер виртуального диска фиксирован и не может изменяться во время работы без его переформатирования (даже если диск не заполнен, невозможно отдать эту память под другие нужды).
В третьих, в Linux осуществляется кэширование всех файлов и записей каталогов, прочитанных или записанных на блочное устройство. Виртуальный диск тоже кешируется, как и обычные диски, то есть часть данных будет храниться не только на RAM диске, но и в страничном кэше «page cache» (для файловых данных) и в кэше для записей каталогов «dentry cache», что еще больше снижает эффективность использования памяти.
Для устраненеия этих недостатков Линус Торвальдс предложил монтировать кэш ядра Линукс как особую файловую систему, работающую полностью в кэше ядра. При этом нет лишнего дублирования информации между блочным устройством и кэшем, так как блочного устройства попросту нет. Файловая система, реализующая эти идеи, была разработана и получила название initramfs. Ее использование имеет следующие преимущества:
- Система, использующая initramfs в качестве корневой файловой системы, более не нуждается в соответствующем драйвере файловой системы, встроенном в ядро, так как нет блочных устройств для интерпретации файловых систем.
- Размер этой файловой системы автоматически изменяется в соответствии с обьёмом данных, которые она содержит. При добавлении новых файлов (как и при расширении существующих) автоматически выделяется память, при удалении или уменьшении файла происходит высвобождение памяти.
- Достоинством initramfs является также то, что это не новый код, а новое применение уже существующего кода кэширования ядра Линукс, что практически не влечёт увеличение размера ядра, выполнение будет очень простым и основано на чрезвычайно хорошо протестированной инфраструктуре.
- Исчезают некоторые проблемы загрузки с SATA-дисков.
- Initramfs загружается немного быстрее, чем initrd.
Формат initramfs используется по умолчанию для всех ядер, начиная с версии 2.6.15.
В каталоге /boot такая файловая система хранится, по-прежнему, в файле в виде сжатого cpio-архива. Только имя включаемого в этот архив скрипта изменилось с linuxrc на init. Например, в системе ASP Linux 11 после разархивирования файла initrd-2.6.14-1.1653.1asp.img по приведенному в листинге 3 алгоритму я увидел скрипт init и следующую структуру каталогов:
В подкаталоге /bin обнаружилось всего 4 исполняемых файла и две ссылки, в подкаталоге /dev — 8 файлов устройств, в /etc — конфигурационный файл udev/udev.conf, в каталоге lib — два файла: ext3.ko и jbd.ko. Остальные подкаталоги — пустые. Файл init оказался скриптом оболочки следующего вида:
Листинг 4. Содержимое файла init в дистрибутиве ASP Linux версии 11. Обратите внимание на первую строку этого файла: это скрипт для оболочки nash, которая является сильно урезанной версией командного процессора и тоже включена в состав initramfs. Другие, более мощные оболочки на этом этапе еще недоступны.
Как видно из листинга 4, скрипт init монтирует файловые системы /sys и /dev, инициализирует несколько устройств, загружает модули из подкаталога /lib и монтирует корневую файловую систему. Сколько я ни вглядывался в экран при перезагрузках системы, я не увидел сообщений, которые вроде бы должны выдаваться командами echo, включенными в этот скрипт.
Образ виртуальной файловой системы initramfs хранится на диске по-прежнему в файле /boot/initrd-version и создается такой файл как и ранее командой mkinitrd. Прочитать о том, как создать такой файл, можно в статье [10]. Перечень модулей (иначе говоря, драйверов), которые будут включены в эту файловую систему, приведен в переменой INITRD_MODULES в файле /etc/sysconfig/kernel. Если вам требуется включить в /boot/initrd-version какие-то дополнительные модули (например, в случае изменения состава оборудования), вы можете скорректировать соответствующим образом список модулей в файле /etc/sysconfig/kernel, после чего заново создать файл /boot/initrd-version.
Источник
initrd — Initial RAM disk
Начальный RAM диск для загрузки Linux (initrd) это временная корневая файловая система, которая монтируется в процессе загрузки системы в оперативную память для поддержки 2х уровневой модели загрузки. Initrd состоит из различных исполняемых файлов и драйверов, которые позволяют смонтировать настоящую корневую файловую систему, после чего initrd
размонтируется и освобождается память. Во многих встраиваемых системах initrd так и остаётся корневой файловой системой. В этой статье исследуется загрузочный RAM диск для ядра Linux 2.6, включая процесс его создания и использования в ядре линукса.
Что такое загрузочный RAM диск?
Загрузочный RAM диск (Initrd) это образ корневой файловой системы, который монтируется до того как настоящая корневая фс будет доступна. Initrd связан с ядром и загружается как часть ядра в процессе загрузки системы. Ядро монтирует образ initrd в котором находятся необходимые модули для монтирования корневой фс и уже дальнейшего перехода в этот корень как основной.
В initrd содержится минимальный набор директорий и исполняемых файлов для загрузки модулей, например insmod для загрузки модулей ядра.
В случае настольной системы или сервера, initrd временная файловая система. Её время жизни коротко и служит лишь связующим звеном к корневой фс. Во встраиваемых системах нет записываемых устройств хранения данных, поэтому initrd является постоянной корневой фс. В этой статье исследуются оба варианта.
Внутреннее устройство initrd
В образе initrd содержится необходимый минимум исполняемых и системных файлов для осуществления второй стадии загрузки linux. В зависимости от версии linux которую вы используете, различаются методы создания initrd.
Начиная с Fedora Core 3, по умолчанию образ initrd это сжатый cpio архив. Вместо монтирования файла с использованием loop device, нужно использовать программу cpio. Чтобы исследовать содержимое cpio архива, используйте следующую последовательность команд:
Листинг 2. Исследование initrd (FC3 и более поздние версии)
# mkdir temp ; cd temp
# cp /boot/initrd-2.6.14.2.img initrd-2.6.14.2.img.gz
# gunzip initrd-2.6.14.2.img.gz
# cpio -i —make-directories bin
drwxr-xr-x 2 root root 4096 May 7 02:48 sys
drwxr-xr-x 2 root root 4096 May 7 02:48 sysroot
#
Интерес в листинге 3 представляет файл init в корне. Это файл, как и в традиционном процессе загрузки linux, запускается когда образ initrd распаковывается в память. Мы разберем этот процесс позже в этой статье.
Утилиты для создания образа initrd
Давайте вернемся в начало и формально разбремся как создается образ initrd. Для традиционных linux систем образ initrd содается в процессе установки. Огромное количество программ, таких как mkinitrd, могут быть использованны для создания initrd с необходимыми библиотеками и модулями для связи с реальной корневой фс. Mkinitrd это по сути обычный shell
скрипт, так что вы можете посмотреть каким образом достигается нужный нам результат. Есть так же YAIRD (Yet Another Mkinitrd) — программа, которая позволяет настроить практически любой параметр в initrd.
Команда cpio Используя команду cpio, вы можете манипулировать cpio файлами. Файл Cpio это по сути простая конкатенция файлов с заголовками. Формат файла cpio позволяет работать как с ascii файлами, так и с бинарными. Для совместимости используйте ascii, для уменьшения размера — бинарную версию.
Создание вручную индивидуального образа initrd
По причине того что на многих встраиваемых системах, основанных на linux нет жесткого диска, initrd так же является и постоянной фс. Листинг 4 показывает как создавать образ initrd. Я использую стандартный десктоп с linux’ом, так что вы можете опробовать эти действия не имея под рукой встраиваемой системы с linux’ом. Не считая компиляции под другую
платформу, концепция создания образа initrd одинакова для встраиваемых систем и обычных компьютеров (включая сервера).
Листинг 4. Утилита (mkird) для создания индивидуального образа initrd
# Housekeeping…
rm -f /tmp/ramdisk.img
rm -f /tmp/ramdisk.img.gz
# Ramdisk Constants
RDSIZE=4000
BLKSIZE=1024
# Create an empty ramdisk image
dd if=/dev/zero of=/tmp/ramdisk.img bs=$BLKSIZE count=$RDSIZE
# Make it an ext2 mountable file system
/sbin/mke2fs -F -m 0 -b $BLKSIZE /tmp/ramdisk.img $RDSIZE
# Mount it so that we can populate
mount /tmp/ramdisk.img /mnt/initrd -t ext2 -o loop=/dev/loop0
# Populate the filesystem (subdirectories)
mkdir /mnt/initrd/bin
mkdir /mnt/initrd/sys
mkdir /mnt/initrd/dev
mkdir /mnt/initrd/proc
# Grab busybox and create the symbolic links
pushd /mnt/initrd/bin
cp /usr/local/src/busybox-1.1.1/busybox .
ln -s busybox ash
ln -s busybox mount
ln -s busybox echo
ln -s busybox ls
ln -s busybox cat
ln -s busybox ps
ln -s busybox dmesg
ln -s busybox sysctl
popd
# Grab the necessary dev files
cp -a /dev/console /mnt/initrd/dev
cp -a /dev/ramdisk /mnt/initrd/dev
cp -a /dev/ram0 /mnt/initrd/dev
cp -a /dev/null /mnt/initrd/dev
cp -a /dev/tty1 /mnt/initrd/dev
cp -a /dev/tty2 /mnt/initrd/dev
# Equate sbin with bin
pushd /mnt/initrd
ln -s bin sbin
popd
# Create the init file
cat >> /mnt/initrd/linuxrc kernel /bzImage-2.6.1
[Linux-bzImage, setup=0x1400, size=0x29672e]
grub> initrd /ramdisk.img.gz
[Linux-initrd @ 0x5f2a000, 0xb5108 bytes]
Uncompressing Linux. OK, booting the kernel.
После того как ядро запущенно, оно проверяет доступен ли initrd
(подробнее об этом позже) и образ initrd доступе, ядро загружает его в
память и монтирует как корневую фс. Вы можете посмотреть на процесс
загрузки в листинге 6. Когда initrd загружен, становится доступна
оболочка ash. В этом примере я исследую корневую фс и опрашиваю
виртуальную файловую систему /proc. Я так же демонстрирую возможность
писать на файловую создавая файл командой touch. Обратите внимание на то
что первый созданный процесс это linuxrc (обычно init).
Листинг 6. Загрузка ядра linux с простым initrd
.
md: Autodetecting RAID arrays
md: autorun
md: . autorun DONE.
RAMDISK: Compressed image found at block 0
VFS: Mounted root (ext2 file system).
Freeing unused kernel memory: 208k freed
/ $ ls
bin etc linuxrc proc sys
dev lib lost+found sbin
/ $ cat /proc/1/cmdline
/bin/ash/linuxrc
/ $ cd bin
/bin $ ls
ash cat echo mount sysctl
busybox dmesg ls ps
/bin $ touch zfile
/bin $ ls
ash cat echo mount sysctl
busybox dmesg ls ps zfile
Процесс загрузки с начальным RAM диском
Теперь вы знаете как собрать свой образ initrd, в этой часте астатьи мы
рассмотрим как ядро идентифицирует и монтируется initrd как корневую фс.
Я прошелся через этот процесс останавливаясь на некоторых важных
функциях в цепочке загрузки, объясняя что происходит.
Загрузчик, например GRUB, идентифицирует ядро, которое нужно загрузить и
копирует образ ядра и initrd в память. Вы можете найти описание всех
необходимых функций в каталоге /init в дереве исходных кодов ядра.
После того как ядро и initrd распакованы и скопированны в память,
исполняется ядро. В этом месте происходит много разных инициализационных
процедур, в конечном счете вы оказываетесь в функции init/main.c:init()
(поддиректория/файл:функция). Эта функция как раз и представляет собой
подсистему инициализации. Отсюда идет вызов функции
init/do_mounts.c:prepare_namespaces(), которая подготавливает рабочее
пространство (монтирует файловую систему dev, RAID или md устройства и,
в итоге, сам initrd). Загрузка initrd выполняется вызовом
init/do_mounts_initrd.c:initrd_load().
Функция initrd_load() вызывает init/do_mounts_rd.c:rd_load_image()
которая определяет браз RAM диска, чтобы загрузить его в
init/do_mounts_rd.c:identify_ramdisk_image(). Это функция проверяет
«магическое число» образа чтобы определить какая фс в этом образе:
minux, ext2, romfs,cramfs или формат gzip. Возвраящаясь к функции
initrd_load_image, происходит вызов init/do_mounts_rd:crd_load(). Эта
функция выделяет в памяти место под RAM диск и считает контрольную сумму
(CRC), после этого распаковывает и загружает RAM диск в память. Теперь
ваш образ initrd находится в подходящем для монтирования блочном
устройстве.
Монтирование блочного устройства в качестве корневого раздела начинается
в функции init/do_mounts.c:mount_root(). Создаётся корневой раздел и
происходит вызов init/do_mounts.c:mount_block_root(). Отсюда вызывается
init/do_mounts.c:do_mount_root(), который вызывает
fs/namespace.c:sys_mount(), чтобы уже смонтировать корневую фс и перейти
в неё. Это то место где выводится в консоль знакомое нам по листингу 6
сообщение VFS: Mounted root (ext2 file system).
В конце, вас возвращает в функцию init и происходит вызов
init/main.c:run_init_process. Это происходит в результате вызова execve
чтобы запустился процесс init (в данном случае linuxrc). Linuxrc может
быть как исполняемым файлом, так и скриптом (если для скрипта есть
интерпретатор).
В листинге 7 показана иерархия функций. Не все функции учавствующие в
процессе копирования и монтирования инициализационного RAM диска
показаны здесь, но общее представление об общем процессе здесь дано.
Листинг 7. Иерархия основных функций участвующих в процессе загрузки и
монтирования initrd
init/main.c:init
init/do_mounts.c:prepare_namespace
init/do_mounts_initrd.c:initrd_load
init/do_mounts_rd.c:rd_load_image
init/do_mounts_rd.c:identify_ramdisk_image
init/do_mounts_rd.c:crd_load
lib/inflate.c:gunzip
init/do_mounts.c:mount_root
init/do_mounts.c:mount_block_root
init/do_mounts.c:do_mount_root
fs/namespace.c:sys_mount
init/main.c:run_init_process
execve
Загрузка бездисковых систем
Почти как во встраиваемых системах, локальный диск (флоппи или CD-ROM)
не обязательны чтобы загрузить ядро и корневую фс в RAM. Протокол
динамического назначения адресов или просто DHCP может быть использован
для того чтобы определить такие параметры как IP адресс и маску подсети.
Упрощенный протокол передачи данных (TFTP) может быть использован для
передачи образа ядра и образа initrd на локальную машину. После
передачи, ядро может быть загружено, а initrd смонтирован, так как будто
это загрузка с локальной машины.
Уменьшение размера образа initrd
Когда вы создаёте встраиваемую систему и хотите добится наименьшего
размера от образа initrd, если несколько хитростей чтобы это сделать.
Первый совет — используйте BusyBox (описано в статье). BusyBox включает
в себя несколько мегабайт утилит и сжимает их всего до нескольких сотен
килобайт.
В этом примере BusyBox скомпилирован статически, т.е. ему не нужно для
работы никаких библиотек. Однако, еесли вам нужны стандартные библиотеки
языка C (для дополнительных программ), есть нескольно путей решить эту
проблемму не используя массивный glibc. Первая маленькая библиотека
подходящая для наших целей это uClibc, которая является минимизированной
версией стандартной библиотеки C для систем с ограниченным местом.
Другая библиотека, идеальная с точки зрения занимаемого дискового
пространства это dietlib. Не забывайте что для того чтобы ваши программы
работали с урезанными версиями, эти программы нужно перекомпилировать
используя эти библиотеки, потребуется некоторая дополнительная работа,
но оно того стоит.
Источник