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

У підсумку ми маємо маленьку кореневу ФС, вміст якої показано в лістингу 3. Маленький, але необхідний набір додатків присутній в каталозі / bin, включаючи nash (not a shell, інтерпретатор скриптів), insmod для завантаження модулів ядра і lvm (утиліта для управління lvm ).

Лістинг 3. Структура initrd за замовчуванням (для FC3)

Інтерес в лістингу 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 <

Лістинг 4. Скрипт mkird для автоматичного створення образу

Щоб створити образ initrd, почнемо зі створення порожнього файлу, використовуючи
псевдопристроїв / dev / zero (просто потік нулів) в якості вхідного
потоку в файл ramdisk.img. В результаті отримаємо файл розміром 4
мегабайта (4000 блоків по першій кілобайт). Потім, використовуючи команду
mke2fs, створимо в цьому файлі файлову систему ext2. Після того як файл
відформатований в ext2, змонтуємо його в каталог / mnt / initrd як
пристрій loop. У точці монтування у вас тепер є директорія,
яка відображає ext2 файлову систему файлу і там ви вже можете
збирати свій образ initrd.

Наступним кроком є ​​створення необхідних підкаталогів: / bin, / sys,
/ Dev і / proc. Потрібно тільки необхідне, для забезпечення необхідної
функціональності, наприклад не потрібно ніяких бібліотек (це умова вірна
коли всі виконувані файли знаходяться в образі initrd скомпілірованни
статично).

Щоб така коренева ФС предоставляля необхідний функціонал використовуйте
BusyBox. Ця програма є єдиним чином для багатьох утиліт,
які зазвичай використовуються в linux системах (такі як ash, awk, sed,
insmod etc.). Приемущество BusyBox в тому що він, включаючи в себе
функціональність багатьох необхідних утиліт, має значно менший розмір.
Це Ідеальна вихід для вбудованих систем. Скопіюйте BusyBox в каталог
/ Bin в кореневої файлової системи вашого образу initrd. створіть
необхідні символічні посилання (на ті ж ash, awk, sed і т.д.) в
каталозі / bin на BusyBox. BusyBox з'ясовує яка утиліта була запущена і
надає необхідні функції. Невелика кількість посилань створюється
в цьому каталозі щоб запрацював init скрипт (посилання ці вказують знову
ж на BusyBox).

Наступний крок - це створення необхідних файлів устройст. Я копіюю їх
прямо з каталогу / dev зі своєї робочої системи використовуючи опцію -a (для
cp) щоб зберегти атрибути файлів.

Передостанній крок - створення файлу linuxrc. Після того як ядро
монтує ram диск, воно шукає init скрипт для виконання. Якщо файл init
не знайдений, ядро ​​виконує файл linuxrc замість init. У цьому файлі
виконуються основні операції для установки оточення, наприклад
монтується файлова система / proc. У доповненні до / proc у мене так само
монтується файлова система / sys і виводить повідомлення в консоль. В кінці
запускається ash (клон Bourne shell) щоб можна було взаємодіяти з
кореневої ФС. Файлу linuxrc ставиться прапор наповнюваності (+ x) використовуючи
команду chmod.

У підсумку ми отримуємо готову кореневу ФС. Образ размонтіруйте і
стискається за допомогою gzip. Результуючий файл (ramdisk.img.gz)
копіюється в каталог / boot для того щоб можна було завантажити GRUB'ом
або lilo.

Щоб створити початковий RAM диск, можна просто запустити mkinitrd і він
автоматично збере образ і скопіює його в каталог / boot

Дистрибутив linux в initrd Був розроблений цікавий open
source проект, в якому весь дистрибутив linux містився в образ
initrd, називається він MiniMax. Він займає 32 мегабайта. включає в
себе BusyBox і uClibc для меншого розміру. Незважаючи на маленький
розмір, це дистрибутив на основі ядра 2.6 і несе в собі досить
велика кількість корисних утиліт.

Альтернатива файлової системи ext2 Ext2 це стандарт
де-факто для linux, але якщо альтернативи, які дозволяють зменшити
розмір підсумкового образу initrd. Наприклад romfs (файлова система ROM),
cramfs (стисла файлова система ROM) і squashfs (сильно стиснута файлова
система тільки для читання). Якщо вам потрібно щось писати на ФС, ext2
цілком для цього підходить. Наостанок є ще e2compr - це розширення
для драйвера ext2, яке підтримує стиснення.

Тестування індивідуального образу initrd

Отже, ваш новий образ initrd лежить в каталозі / boot, наступним кроком
потрібно оттестировать його з вашим ядром. Перезавантажте систему і коли
з'явиться запрошення GRUB, натисніть клавішу C, це переведе GRUB в
режим командного рядка. Ви можете взаимодествовать з GRUB'ом наприклад
щоб передати ядру специфічні параметри або завантажити свій образ
initrd. Команда kernel визначити яке ядро ​​завантажувати, а команда
initrd вибрати образ initrd. Коли ці параметри определнного, наберіть
boot і завантажувач завантажить зазначені ядро ​​і initrd.

Лістинг 5. Ручне завантаження ядра і initrd використовуючи GRUB

grub> 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.

Лістинг 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

Завантаження бездискових систем

Зменшення розміру образу initrd

Коли ви створюєте вбудовану систему і хочете добитися найменшого
розміру від способу initrd, якщо декілька хитрощів щоб це зробити.
Перша порада - використовуйте BusyBox (описано в статті). BusyBox включає
в себе кілька мегабайт утиліт і стискає їх всього до кількох сотень
кілобайт.

У цьому прикладі BusyBox скомпільовано статично, тобто йому не потрібно для
роботи ніяких бібліотек. Однак, Ееслі вам потрібні стандартні бібліотеки
мови C (для додаткових програм), є нескольно шляхів вирішити цю
проблемму не використовуючи масивний glibc. Перша маленька бібліотека
підходяща для наших цілей це uClibc, яка є мінімізованої
версією стандартної бібліотеки C для систем з обмеженим простором.
Інша бібліотека, ідеальна з точки зору займаного дискового
простору це dietlib. Не забувайте що для того щоб ваші програми
працювали з урізаними версіями, ці програми потрібно перекомпілювати
використовуючи ці бібліотеки, буде потрібно деяка додаткова робота,
але воно того варто.