Ошибка "xc_dom_probe_bzimage_kernel__unknown compression format" при загрузке VPS с Ubuntu 20.04 на XEN
Ошибка "xc_dom_probe_bzimage_kernel__unknown compression format" при загрузке VPS с Ubuntu 20.04 на XEN¶
Определяем, точно ли у клиента траблы с xc_dom_bzimageloader и его ядром¶
Если VPS на XEN не стартует, и в выхлопе
xm create /etc/xen/conf/OUR_ID.conf -c
мы при этом наблюдаем ошибку
xc: error: panic: xc_dom_bzimageloader.c:775: xc_dom_probe_bzimage_kernel: unknown compression format: Invalid kernel
то это — точно проблема, описанная в этой статье.
Как завести VPS, чтобы она загрузилась¶
Подкидываем на VPS заведомо рабочее ядро, не пожатое bzip2¶
Нужно остановить VPS, подмонтировать её раздел куда-то, и скопировать туда ядро из шаблона с чистым дистром, аналогичным тому, что юзает VPS.
xm destroy VPS_ID
mount /dev/OUR_VG/VPS_ID-disk /tmp/VPS_ID/boot/
Делаетя это примерно так
cd /xen/templates/
mkdir ubuntu-20.04-x86_64
tar zxf ubuntu-20.04-x86_64.tar.gz -C ./ubuntu-20.04-x86_64/
cd ubuntu-20.04-x86_64/boot
cp config-5.4.0-65-generic /tmp/VPS_ID/boot/
cp initrd.img-5.4.0-65-generic /tmp/VPS_ID/boot/
cp vmlinuz-5.4.0-65-generic /tmp/VPS_ID/boot/
cd /xen/templates/
rm -rI ./ubuntu-20.04-x86_64
После чего, если ранее эта версия ядра у клиента в /boot отсутствовала, необходимо поправить grub.cfg, прописав верхней запись со скопированной нами версией ядра. Просто копируем первую menuentry {что-то тут}
в нашем grub.cfg, и заменяем путь к vmlinuz на путь к vmlinuz-5.4.0-65-generic, а к initrd — на путь к initrd.img-5.4.0-65-generic(где вместо 5.4.0-65 вам необходимо подставить соответствующую вашей версию скопированного рабочего ядра).
Загружаемся, выбрав в меню загрузчика ядро, не пожатое с помощью bzip.
Загрузились? Самое время сравнить рабочее, и не рабочее, ядра¶
Логинимся от рута на VPS по SSH, или из консоли XEN.
Смотрим, чем отличается ядро, которое может загрузить pygrub(загрузчик XEN) от того, что он не может "прожевать".
"Хорошее" ядро выглядит так
# file vmlinuz-5.4.0-65-generic
vmlinuz-5.4.0-65-generic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=9600f316a53a0f54278885e8d9710538ec5f6a08, stripped
А "Плохое" немного иначе, у него есть вхождение bzImage в строке:
# file vmlinuz-5.15.0-52-generic
vmlinuz-5.15.0-52-generic: Linux kernel x86 boot executable bzImage, version 5.15.0-52-generic (buildd@lcy02-amd64-032) #58-Ubuntu SMP Thu Oct 13 08:03:55 UTC 2022, RO-rootFS, swap_dev 0XA, Normal VGA
Устанавливаем зависимости, и создаём скрипт, что будет автоматически распаковывать ядро, пожатое bzip2 после его установки¶
Скачиваем скрипт
wget -q -O /usr/local/bin/extract-vmlinux https://raw.githubusercontent.com/torvalds/linux/master/scripts/extract-vmlinux
chmod ug+x /usr/local/bin/extract-vmlinux
Устаналиваем зависимости
apt update
apt install elfutils lz4 lzop bzip2 binutils
Создаём файл /etc/kernel/postinst.d/extract-vmlinux
с содержимым
#!/usr/bin/env bash
KERNEL_VERSION="$1"
KERNEL_PATH="$2"
# extract-vmlinux is in /usr/local/bin
PATH="${PATH}:/usr/local/bin"
# Ensure we have the extract-linux tool
if ! command -v extract-vmlinux > /dev/null; then
echo >&2 "Command 'extract-vmlinux' is not available (https://raw.githubusercontent.com/torvalds/linux/master/scripts/extract-vmlinux), Aborting"
exit 1
fi
# The KERNEL_PATH must be valid
if [ ! -f "${KERNEL_PATH}" ]; then
echo >&2 "Kernel file '${KERNEL_PATH}' not found. Aborting"
exit 1
fi
# Create a temp file
TEMP_FILE=$(mktemp /tmp/decompress-kernel-XXXXX)
trap "rm -f ${TEMP_FILE}" 0
# If the given kernel file is still a bzimage see if its needs decompression
if echo "$(file -b "${KERNEL_PATH}")" | grep -q "^Linux kernel x86 boot executable bzImage"; then
if ! grep -qoa BZh ${KERNEL_PATH}; then
echo "No bzip2 compression headers found, skipping..."
exit 0
fi
echo "Decompressing '${KERNEL_PATH}'..."
# Extract the kernel and replace existing if successful
if extract-vmlinux ${KERNEL_PATH} > ${TEMP_FILE}; then
# Double check the kernel is a valid ELF image
if ! readelf -h ${TEMP_FILE} > /dev/null; then
echo >&2 "Decompression of kernel file '${KERNEL_PATH}' failed!, not a valid ELF image"
exit 1
fi
echo "Decompression of kernel file '${KERNEL_PATH}' successful"
cp -v ${TEMP_FILE} ${KERNEL_PATH}
else
echo >&2 "Decompression of kernel file '${KERNEL_PATH}' failed!"
exit 1
fi
# Perhaps its already been decompressed
elif echo "$(file -b "${KERNEL_PATH}")" | grep -q "^ELF 64-bit LSB executable"; then
echo "Kernel file '${KERNEL_PATH}' appears to be decompressed already. skipping"
else
echo >&2 "Unable to determine the state of kernel file '${KERNEL_PATH}'"
exit 1
fi
Поправляем права на скрипт
chmod ug+x /etc/kernel/postinst.d/extract-vmlinux
Восстанавливаем работоспособность ядра, не загружающегося на XEN¶
И пробуем, как он отработает на одном из ядре, к примеру на заведомо "проблемном" для XEN linux-image-5.15.0-52-generic:
apt install -y --reinstall linux-image-5.15.0-52-generic linux-headers-5.15.0-52-generic
Переходим в /boot VPS-ки. Проверяем, как отработал наш хук
# file vmlinuz-5.15.0-52-generic
vmlinuz-5.15.0-52-generic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=28a29b8480e5f760cc6ca2f7d53398fa4d3836d7, stripped
Проверяем, загружается ли VPS с "исправленным" ядром¶
Ребутаем VPS, проверяем что она грузится с этого ядра корректно.
Подчищаем за собой¶
Если мы копировали вручную отсутствовавшую у клиента версию ядра, как было в моём случае(копировал 5.4.0-65, у клиента такой версии ядра ранее не было, в пакетом менеджере она не значится как установленная), то:
1. в grub.cfg удаляем menuentry для этой версии ядра.
2. не забываем в таком случае подчистить сами файлы ядра командой rm vmlinuz-5.4.0-65-generic initrd.img-5.4.0-65-generic config-5.4.0-65-generic
в /boot/ VPS клиента.