Настройка окружения для тестирования изменений в ядре Linux
Иногда (редко, но все-же) возникает потребность что-то дописать или переделать в ядре всеми нами любимого линукса. И тогда возникает вопрос: А как все эти изменения запустить и проверить быстро и без перекуров?
Одно дело, если мы можем организовать нашу новую функциональность в виде модуля, тогда нам довольно просто можно тестировать его без перезагрузки самого ядра, простым включением и выключением через insmod. Но что делать, если концепция модульности неприменима? Например, как в моем случае, когда потребовалось добавить новую подсистему контрольных групп (cgroups) для Jet9 и нужно было перезапускать ядро каждый раз, чтобы проверить внесенные изменения?
В этом нам поможет система виртуализации qemu (или qemu-kvm), т.к. она умеет принимать в качестве параметров не только раздел с системой, но и сам файл с ядром (bzImage) и initramfs. Используя данную функциональность мы можем быстро настроить и использовать тестовое окружение. Настройка состоит всего из двух шагов:
- Создание initramfs
- Запуск qemu-kvm с новым ядром и созданным initramfs
Далее я кратко опишу эти два шага, а на все доп. вопросы отвечу в комментариях.
Создание initramfs
Создадим структуру каталогов:
mkdir -p initramfs/{bin,sbin,etc,proc,sys,cgroup,usr/bin,usr/sbin}
Добавим все необходимые unix-утилиты. Для этого проще всего использовать busybox. Бинарник можно скачать отсюда и положить в /bin/busybox. Обязательно надо добавить симлинк для sh, чтобы запустился init:
cd initramfs
ln -s bin/busybox bin/sh
Добавим следующий скрипт в ./init (он должен находиться в корне нашего образа):
#!/bin/sh
#Create unix-utils symlinks to /bin/busybox
/bin/busybox --install -s
#Mount pseudo-fs
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t cgroup cgroup /cgroup
#Create null device
mknod /dev/null c 1 3
exec sh
Он при запуске создаст симлинки на все основные unix-утилиты, примонтирует удобные для нас pseudo-fs, создаст устройство /dev/null (чтобы его можно было потом использовать в своих скриптах и подавлять ненужный вывод) и запустит шелл.
Конечно, если вам нужно что-то сверх этого, вы можете легко изменить этот скрипт по своему усмотрению. Я, например, в него перед запуском шелла добавил запуск тестов, чтобы каждый раз вручную их не запускать. Точно так же можно поступить и с дополнительными утилитами — просто добавьте их в образ по тем путям, которые вам нужны. Аналогично с модулями — если вы их используете при тестировании, просто добавьте их в /lib/modules/
Далее, запакуем все в один файл:
find . | cpio -H newc -o | gzip -c > ../initramfs.gz
Все, initramfs готов.
Запуск kvm
Тут все довольно просто, все запускается командой:
kvm -m 128 -kernel ./arch/x86/boot/bzImage -initrd initramfs.igz -serial stdio -append "console=ttyAMA0 console=ttyS0" -display none
параметры:
-m — сколько оперативки выделяем на машину
-kernel — новоскомпилированное ядро
-initrd — созданный выше initramfs
-append — параметры ядру
самое интересное — это параметр -append, в нем мы перенаправляем ввод/вывод в serial port (помните такой? ;), а параметром -serial перенаправляем последовательный порт в stdin/stdout. Это позволит нам получить вывод ядра прямо в консоль, минуя черное окошко 80×25, в котором не радует решительно все. Кстати, параметр -display none позволяет убрать и его, чтобы не отсвечивало (нам же ядро интересно, а не gui).
Profit! Теперь ядро загружается и готово к проверке меньше чем за 3 секунды.