Segfault при запуске виртуальной машины в LinuxKVM
- Дано: виртуальная машина (далее VM) запускается и сразу завершается.
- В dmesg и /var/log/syslog появляется сообщение:
Dec 20 19:26:23 proxmox-server1 kernel: [1426017.156968] kvm[24299]: segfault at 0 ip 0000560db309e7bf sp 00007ffc817b1550 error 6 in qemu-system-x86_64[560db2aa7000+8df000]
Полное содержимое /var/log/syslog:
Dec 12 11:22:33 proxmox-server1 qm[24281]: starting task UPID:proxmox-server1:00005EE1:087FE37D:5C1BC2AE:qmstart:100:root@pam:
Dec 12 11:22:33 proxmox-server1 qm[24289]: start VM 100: UPID:proxmox-server1:00005EE1:087FE37D:5C1BC2AE:qmstart:100:root@pam:
Dec 12 11:22:33 proxmox-server1 systemd[1]: Started 100.scope.
Dec 12 11:22:33 proxmox-server1 systemd-udevd[24302]: Could not generate persistent MAC address for tap100i0: No such file or directory
Dec 12 11:22:33 proxmox-server1 kernel: [1426016.978762] vmbr0: port 7(tap100i0) entered blocking state
Dec 12 11:22:34 proxmox-server1 qm[24281]: end task UPID:proxmox-server1:00005EE1:087FE37D:5C1BC2AE:qmstart:100:root@pam: OK
Dec 12 11:22:34 proxmox-server1 kernel: [1426017.156968] kvm[24299]: segfault at 0 ip 0000560db309e7bf sp 00007ffc817b1550 error 6 in qemu-system-x86_64[560db2aa7000+8df000]
Dec 12 11:22:34 proxmox-server1 kernel: [1426017.179860] vmbr0: port 7(tap100i0) entered disabled state
Dec 12 11:22:34 proxmox-server1 qmeventd[979]: Starting cleanup for 100
Dec 12 11:22:34 proxmox-server1 qmeventd[979]: Finished cleanup for 100
Проблема исчезает, если запускать VM без образов жёсткого диска (далее HDD).
Если подключить к VM образ LiveCD, то загрузка с него происходит успешно, но VM закрывается при первом же обращении к HDD.
Проблема проявляется у нас только на одном сервере, но с почти 100% вероятностью. Разумеется, процессоры, память и диски неоднократно проверены и проблем с ними не выявлено.
Версия qemu-kvm — 2.12.1-1. На тот момент — самая последняя для нашего дистрибутива — Proxmox PVE 5.2.
Что мы пробовали менять, но безуспешно?
- Форматы образа HDD — raw и qcow2.
- Тип эмуляции HDD — IDE, SATA, SCSI и virtio.
Как мы искали проблему?
- Сначала узнаём, какую полную системную команду оболочка Proxmox использует для запуска VM. Для этого в консоли выполняем:
qm showcmd 100
Вывод будет примерно такой (у нас он занял 12 строк, поэтому приводить его полностью не станем):
/usr/bin/kvm -id 100 -name bugtest1 -chardev ... -machine 'type=pc'
Эту команду мы будем выполнять вручную. Но вначале установим отладчик GDB и отладочную информацию для утилиты /usr/bin/kvm:
apt install gdb pve-qemu-kvm-dbg
И разрешим создание coredump'ов:
ulimit -c unlimited
sysctl kernel.core_pattern
По умолчанию в kernel.core_pattern установлена маска /var/tmp/core.%e.%p, т.е. снимки аварийно завершённых
процессов ядро сохраняет в каталог /var/tmp с именами вида core.имя_команды.pid_процесса.
После этого выполняем команду /usr/bin/kvm -id 100 ...
— она завершается и оставляет после себя файл /var/tmp/core.kvm.1234.
Теперь запускаем отладчик (замените 1234 на фактический номер):
gdb /usr/bin/kvm /var/tmp/core.kvm.1234
И в отладчике смотрим стек вызова функций процесса, сохранённый системой в coredump в момент ошибки:
(gdb) bt
#0 laio_attach_aio_context (s=0x0, new_context=new_context@entry=0x7fd2649a1c80) at block/linux-aio.c:466
#1 0x0000558e04f3bf7b in aio_get_linux_aio (ctx=0x7fd2649a1c80) at util/async.c:329
#2 0x0000558e04eab7f1 in raw_aio_plug (bs=0x7fd2649e6000) at block/file-posix.c:1613
#3 0x0000558e04eb7840 in bdrv_io_plug (bs=0x7fd2649dc000) at block/io.c:2778
#4 0x0000558e04ea6306 in blk_io_plug (blk=) at block/block-backend.c:1960
#5 0x0000558e04bb2e6b in virtio_blk_handle_vq (s=0x7fd05c17b170, vq=0x7fd05c183000) at /home/builder/source/qemu.tmp/hw/block/virtio-blk.c:602
#6 0x0000558e04be15d6 in virtio_queue_notify_aio_vq (vq=0x7fd05c183000) at /home/builder/source/qemu.tmp/hw/virtio/virtio.c:1515
#7 0x0000558e04f3e72c in aio_dispatch_handlers (ctx=ctx@entry=0x7fd2649a1c80) at util/aio-posix.c:406
#8 0x0000558e04f3efd8 in aio_dispatch (ctx=0x7fd2649a1c80) at util/aio-posix.c:437
#9 0x0000558e04f3bc6e in aio_ctx_dispatch (source=, callback=, user_data=) at util/async.c:261
#10 0x00007fd27342b7f7 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#11 0x0000558e04f3e278 in glib_pollfds_poll () at util/main-loop.c:215
#12 os_host_main_loop_wait (timeout=) at util/main-loop.c:263
#13 main_loop_wait (nonblocking=) at util/main-loop.c:522
#14 0x0000558e04b34b8f in main_loop () at vl.c:1948
#15 main (argc=, argv=, envp=) at vl.c:4757
Далее переходим к изучению функции laio_attach_aio_context в исходных текстах Qemu: https://github.com/qemu/qemu/blob/master/block/linux-aio.c
Сразу становится ясно, что проблема вызвана передачей нулевого указателя.
Поиск исправления и написание патча для qemu являются отдельной задачей, которая выходит за рамки данной заметки.
Ищем обходной вариант:
- Обходной вариант может заключаться в отказе от использования вызовов Linux AIO. Это может снизить быстродействие, но решит проблему.
- Для этого попробуем поменять не формат образа диска или способ эмуляции, а порядок обращения к нему — с быстрого асинхронного на более медленный синхронный.
- Список доступных режимов перечислен в https://pve.proxmox.com/wiki/Performance_Tweaks#Disk_Cache:
- none
- writethrough
- writeback
- directsync
- unsafe
- По умолчанию используется режим Default (no cache).
- Меняем его в свойствах диска на Write through и получаем нормально запускающуюся VM.