Початковий 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 У підсумку ми маємо маленьку кореневу ФС, вміст якої показано в лістингу 3. Маленький, але необхідний набір додатків присутній в каталозі / bin, включаючи nash (not a shell, інтерпретатор скриптів), insmod для завантаження модулів ядра і lvm (утиліта для управління lvm ). Лістинг 3. Структура initrd за замовчуванням (для FC3) Інтерес в лістингу 3 представляє файл init в корені. Це файл, як і в традиційному процесі завантаження linux, запускається коли образ initrd розпаковується в пам'ять. Ми розберемо цей процес пізніше в цій статті. Давайте повернемося в початок і формально разбремся як створюється образ initrd. Для традиційних linux систем образ initrd сода в процесі установки. Величезна кількість програм, таких як mkinitrd, можуть бути використані для створення initrd з необхідними бібліотеками і модулями для зв'язку з реальною кореневої ФС. Mkinitrd це по суті звичайний shell Команда cpio Використовуючи команду cpio. ви можете маніпулювати cpio файлами. Файл Cpio це по суті проста конкатенція файлів з заголовками. Формат файлу cpio дозволяє працювати як з ascii файлами, так і з бінарними. Для сумісності використовуйте ascii, для зменшення розміру - бінарну версію. У зв'язку з тим що на багатьох вбудованих системах, заснованих на linux немає жорсткого диска, initrd так само є і постійної ФС. Лістинг 4 показує як створювати образ initrd. Я використовую стандартний десктоп з Linux'ом, так що ви можете випробувати ці дії не маючи під рукою вбудовується системи з Linux'ом. Крім компіляції під іншу Лістинг 4. Утиліта (mkird) для створення індивідуального образу initrd # Housekeeping ... # Ramdisk Constants # Create an empty ramdisk image # Make it an ext2 mountable file system # Mount it so that we can populate # Populate the filesystem (subdirectories) # Grab busybox and create the symbolic links # Grab the necessary dev files # Equate sbin with bin # Create the init file Лістинг 4. Скрипт mkird для автоматичного створення образу Щоб створити образ initrd, почнемо зі створення порожнього файлу, використовуючи Наступним кроком є створення необхідних підкаталогів: / bin, / sys, Щоб така коренева ФС предоставляля необхідний функціонал використовуйте Наступний крок - це створення необхідних файлів устройст. Я копіюю їх Передостанній крок - створення файлу linuxrc. Після того як ядро У підсумку ми отримуємо готову кореневу ФС. Образ размонтіруйте і Щоб створити початковий RAM диск, можна просто запустити mkinitrd і він Дистрибутив linux в initrd Був розроблений цікавий open Альтернатива файлової системи ext2 Ext2 це стандарт Тестування індивідуального образу initrd Отже, ваш новий образ initrd лежить в каталозі / boot, наступним кроком Лістинг 5. Ручне завантаження ядра і initrd використовуючи GRUB grub> kernel /bzImage-2.6.1 grub> initrd /ramdisk.img.gz Uncompressing Linux. OK, booting the kernel. Лістинг 6. Завантаження ядра linux з простим initrd Процес завантаження з початковим RAM диском Тепер ви знаєте як зібрати свій образ initrd, в цій частині астату ми Завантажувач, наприклад GRUB, ідентифікує ядро, яке потрібно завантажити і Після того як ядро і initrd розпаковані і скопірованни в пам'ять, Функція initrd_load () викликає init / do_mounts_rd.c: rd_load_image () Монтування блочного пристрою в якості кореневого розділу починається В кінці, вас повертає в функцію init і відбувається виклик У лістингу 7 показана ієрархія функцій. Не всі функції учавствующие в Лістинг 7. Ієрархія основних функцій беруть участь в процесі завантаження і init / main.c: init Завантаження бездискових систем Зменшення розміру образу initrd Коли ви створюєте вбудовану систему і хочете добитися найменшого У цьому прикладі BusyBox скомпільовано статично, тобто йому не потрібно для
# 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 Програми для створення образу initrd
скрипт, так що ви можете подивитися яким чином досягається потрібний нам результат. Є так само YAIRD (Yet Another Mkinitrd) - програма, яка дозволяє налаштувати практично будь-який параметр в initrd.Створення вручну індивідуального образу initrd
платформу, концепція створення образу initrd однакова для вбудованих систем і звичайних комп'ютерів (включаючи сервера).
rm -f /tmp/ramdisk.img
rm -f /tmp/ramdisk.img.gz
RDSIZE = 4000
BLKSIZE = 1024
dd if = / dev / zero of = / tmp / ramdisk.img bs = $ BLKSIZE count = $ RDSIZE
/ Sbin / mke2fs -F -m 0 -b $ BLKSIZE /tmp/ramdisk.img $ RDSIZE
mount /tmp/ramdisk.img / mnt / initrd -t ext2 -o loop = / dev / loop0
mkdir / mnt / initrd / bin
mkdir / mnt / initrd / sys
mkdir / mnt / initrd / dev
mkdir / mnt / initrd / proc
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
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
pushd / mnt / initrd
ln -s bin sbin
popd
cat >> / mnt / initrd / linuxrc <
псевдопристроїв / dev / zero (просто потік нулів) в якості вхідного
потоку в файл ramdisk.img. В результаті отримаємо файл розміром 4
мегабайта (4000 блоків по першій кілобайт). Потім, використовуючи команду
mke2fs, створимо в цьому файлі файлову систему ext2. Після того як файл
відформатований в ext2, змонтуємо його в каталог / mnt / initrd як
пристрій loop. У точці монтування у вас тепер є директорія,
яка відображає ext2 файлову систему файлу і там ви вже можете
збирати свій образ initrd.
/ 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) щоб зберегти атрибути файлів.
монтує ram диск, воно шукає init скрипт для виконання. Якщо файл init
не знайдений, ядро виконує файл linuxrc замість init. У цьому файлі
виконуються основні операції для установки оточення, наприклад
монтується файлова система / proc. У доповненні до / proc у мене так само
монтується файлова система / sys і виводить повідомлення в консоль. В кінці
запускається ash (клон Bourne shell) щоб можна було взаємодіяти з
кореневої ФС. Файлу linuxrc ставиться прапор наповнюваності (+ x) використовуючи
команду chmod.
стискається за допомогою gzip. Результуючий файл (ramdisk.img.gz)
копіюється в каталог / boot для того щоб можна було завантажити GRUB'ом
або lilo.
автоматично збере образ і скопіює його в каталог / boot
source проект, в якому весь дистрибутив linux містився в образ
initrd, називається він MiniMax. Він займає 32 мегабайта. включає в
себе BusyBox і uClibc для меншого розміру. Незважаючи на маленький
розмір, це дистрибутив на основі ядра 2.6 і несе в собі досить
велика кількість корисних утиліт.
де-факто для linux, але якщо альтернативи, які дозволяють зменшити
розмір підсумкового образу initrd. Наприклад romfs (файлова система ROM),
cramfs (стисла файлова система ROM) і squashfs (сильно стиснута файлова
система тільки для читання). Якщо вам потрібно щось писати на ФС, ext2
цілком для цього підходить. Наостанок є ще e2compr - це розширення
для драйвера ext2, яке підтримує стиснення.
потрібно оттестировать його з вашим ядром. Перезавантажте систему і коли
з'явиться запрошення GRUB, натисніть клавішу C, це переведе GRUB в
режим командного рядка. Ви можете взаимодествовать з GRUB'ом наприклад
щоб передати ядру специфічні параметри або завантажити свій образ
initrd. Команда kernel визначити яке ядро завантажувати, а команда
initrd вибрати образ initrd. Коли ці параметри определнного, наберіть
boot і завантажувач завантажить зазначені ядро і initrd.
[Linux-bzImage, setup = 0x1400, size = 0x29672e]
[Linux-initrd @ 0x5f2a000, 0xb5108 bytes]
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
розглянемо як ядро ідентифікує і монтується initrd як кореневу ФС.
Я пройшовся через цей процес зупиняючись на деяких важливих
функціях в ланцюжку завантаження, пояснюючи що відбувається.
копіює образ ядра і initrd в пам'ять. Ви можете знайти опис всіх
необхідних функцій в каталозі / init в дереві вихідних кодів ядра.
виповнюється ядро. У цьому місці відбувається багато різних ініціалізацій
процедур, в кінцевому рахунку ви опиняєтеся в функції init / main.c: init ()
(Піддиректорія / файл: функція). Ця функція якраз і є
підсистему ініціалізації. Звідси йде виклик функції
init / do_mounts.c: prepare_namespaces (), яка готує робоче
простір (монтує файлову систему dev, RAID або md пристрою і,
в результаті, сам initrd). Завантаження initrd виконується викликом
init / do_mounts_initrd.c: initrd_load ().
яка визначає Браз 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 / main.c: run_init_process. Це відбувається в результаті виклику execve
щоб запустився процес init (в даному випадку linuxrc). Linuxrc може
бути як виконуваним файлом, так і скриптом (якщо для скрипта є
інтерпретатор).
процесі копіювання і монтування ініціалізації RAM диска
показані тут, але загальне уявлення про загальний процес тут дано.
монтування initrd
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, якщо декілька хитрощів щоб це зробити.
Перша порада - використовуйте BusyBox (описано в статті). BusyBox включає
в себе кілька мегабайт утиліт і стискає їх всього до кількох сотень
кілобайт.
роботи ніяких бібліотек. Однак, Ееслі вам потрібні стандартні бібліотеки
мови C (для додаткових програм), є нескольно шляхів вирішити цю
проблемму не використовуючи масивний glibc. Перша маленька бібліотека
підходяща для наших цілей це uClibc, яка є мінімізованої
версією стандартної бібліотеки C для систем з обмеженим простором.
Інша бібліотека, ідеальна з точки зору займаного дискового
простору це dietlib. Не забувайте що для того щоб ваші програми
працювали з урізаними версіями, ці програми потрібно перекомпілювати
використовуючи ці бібліотеки, буде потрібно деяка додаткова робота,
але воно того варто.