понедельник, 2 мая 2016 г.

KDump - диагностика сбоев ядра Linux

Если у вас в Windows хотя бы раз выпадал синий экран смерти (Blue Screen of Death, ака BSOD), то вы знаете, что после него создаётся так называемый дамп (dump) памяти, в который включается информация об ошибке, о сбойном адресе в памяти и какие процессы были в памяти на момент сбоя. Потом этот дамп можно прочитать утилитой Blue Screen View. В Linux есть похожая технология, созданная инженерами компании Red Hat, под названием KDump, а также утилиту для их чтения под названием Crash. О них пойдёт речь.

Хочу заранее предупредить, что на момент написания статьи, Crash не работал с ядрами выше 4.3. Имейте ввиду. Также хочу обратить внимание на то, что если у вас ядро установлено из Debian Backports - ставьте оттуда же и KDump. Иначе не будет работать.

Итак, есть Debian 8, ядро Linux 4.3, пара рук (желательно прямых), и немного времени на настройку. Устанавливаем:

sudo apt install kdump-tools, crash, linux-image-`uname -r`-dbg

Отладочные символы ядра (debugging symbols) весят много, на диске займут около 3 гигабайт (на корневом разделе). Во премя установки пакета kexec-tools, он спросит активировать или перезагрузку через него. Если вы ответите Да, то ваш компьютер вместо перезагрузки будет просто перезапускать ядро. Таким образом вы, к примеру, не сможете выйти в меню GRUB. Поэтому отвечаем Нет. Как и на вопрос о чтении файла /etc/default/grub. Теперь проводим настройку:

sudo nano /etc/default/kdump-tools

# kdump-tools configuration
# ---------------------------------------------------------------------------
# USE_KDUMP - controls kdump will be configured
#     0 - kdump kernel will not be loaded
#     1 - kdump kernel will be loaded and kdump is configured
# KDUMP_SYSCTL - controls when a panic occurs, using the sysctl
#     interface.  The contents of this variable should be the
#     "variable=value ..." portion of the 'sysctl -w ' command.
#     If not set, the default value "kernel.panic_on_oops=1" will
#     be used.  Disable this feature by setting KDUMP_SYSCTL=" "
#     Example - also panic on oom:
#         KDUMP_SYSCTL="kernel.panic_on_oops=1 vm.panic_on_oom=1"
#
USE_KDUMP=1
#KDUMP_SYSCTL="kernel.panic_on_oops=1"


# ---------------------------------------------------------------------------
# Kdump Kernel:
# KDUMP_KERNEL - A full pathname to a kdump kernel.
# KDUMP_INITRD - A full pathname to the kdump initrd (if used).
#     If these are not set, kdump-config will try to use the current kernel
#     and initrd if it is relocatable.  Otherwise, you will need to specify
#     these manually.
KDUMP_KERNEL=/var/lib/kdump/vmlinuz
KDUMP_INITRD=/var/lib/kdump/initrd.img


# ---------------------------------------------------------------------------
# vmcore Handling:
# KDUMP_COREDIR - local path to save the vmcore to.
# KDUMP_FAIL_CMD - This variable can be used to cause a reboot or
#     start a shell if saving the vmcore fails.  If not set, "reboot -f"
#     is the default.
#     Example - start a shell if the vmcore copy fails:
#         KDUMP_FAIL_CMD="echo 'makedumpfile FAILED.'; /bin/bash; reboot -f"
# KDUMP_DUMP_DMESG - This variable controls if the dmesg buffer is dumped.
#     If unset or set to 1, the dmesg buffer is dumped. If set to 0, the dmesg
#     buffer is not dumped.
KDUMP_COREDIR="/var/crash"
#KDUMP_FAIL_CMD="reboot -f"
#KDUMP_DUMP_DMESG=


# ---------------------------------------------------------------------------
# Makedumpfile options:
# MAKEDUMP_ARGS - extra arguments passed to makedumpfile (8).  The default,
#     if unset, is to pass '-c -d 31' telling makedumpfile to use compression
#     and reduce the corefile to in-use kernel pages only.
#MAKEDUMP_ARGS="-c -d 31"


# ---------------------------------------------------------------------------
# Kexec/Kdump args
# KDUMP_KEXEC_ARGS - Additional arguments to the kexec command used to load
#     the kdump kernel
#     Example - Use this option on x86 systems with PAE and more than
#     4 gig of memory:
#         KDUMP_KEXEC_ARGS="--elf64-core-headers"
# KDUMP_CMDLINE - The default is to use the contents of /proc/cmdline. 
#     Set this variable to override /proc/cmdline.
# KDUMP_CMDLINE_APPEND - Additional arguments to append to the command line
#     for the kdump kernel.  If unset, it defaults to "irqpoll maxcpus=1 nousb"
#KDUMP_KEXEC_ARGS=""
#KDUMP_CMDLINE=""
#KDUMP_CMDLINE_APPEND="irqpoll maxcpus=1 nousb systemd.unit=kdump-tools.service"

# ---------------------------------------------------------------------------
# Architecture specific Overrides:

# ---------------------------------------------------------------------------
# Remote dump facilities:
# SSH - username and hostname of the remote server that will receive the dump
#       and dmesg files.
# SSH_KEY - Full path of the ssh private key to be used to login to the remote
#           server. use kdump-config propagate to send the public key to the
#           remote server
# HOSTTAG - Select if hostname of IP address will be used as a prefix to the
#           timestamped directory when sending files to the remote server.
#           'ip' is the default.
# NFS -     Hostname and mount point of the NFS server configured to receive
#           the crash dump. The syntax must be {HOSTNAME}:{MOUNTPOINT}
#           (e.g. remote:/var/crash)
#
# SSH=""
#
# SSH_KEY=""
#
# HOSTTAG="hostname|[ip]"
#
# NFS=""
#


Раскоментируем строку USE_KDUMP и ставим ей значение 1. Остальные параметры, в принципе, трогать необязательно. В строках KDUMP_KERNEL и KDUMP_INITRD можно указать путь к ядру и начальному рамдиску конкретного ядра, однако по умолчанию будет использоваться текущее загруженное ядро. По ссылке в конце статьи вы можете ознакомиться с прочими опциями. Теперь активируем перезагрузку компьютера после снятия дампа:

sudo nano /etc/sysctl.conf

Добавляем строки:

# Enable reboots on panic to allow kdump make dumps
kernel.hung_task_panic = 1
kernel.panic = 1
kernel.panic_on_io_nmi = 1
kernel.panic_on_oops = 1
kernel.panic_on_unrecovered_nmi = 1
kernel.softlockup_panic = 1
kernel.unknown_nmi_panic = 1
vm.panic_on_oom = 1
kernel.sysrq = 1


Сохраняем и применяем:

sudo sysctl -p

Теперь отредактируем GRUB:

sudo nano /etc/default/grub

В строку GRUB_CMDLINE_LINUX_DEFAULT дописываем crashkernel=128M@32M . Столько будет выделяться памяти для дампа. Теперь:

sudo update-grub
sudo reboot

Настало время проверить работу KDump. Для этого искусственно "повалим" ядро, или иными словами - вызовем Kernel Panic:

echo e | sudo tee /proc/sysrq-trigger

Если всё прошло успешно, система наглухо повиснет, экран возможно покроется разноцветными артефактами, KDump снимет дампа ядра и перезагрузит систему. После перезагрузки, дамп ядра и дамп последнего лога загрузки будут лежать в /var/crash. Давайте прочитаем:

sudo crash /usr/lib/debug/vmlinux-4.3.0-0.bpo.1-amd64 /var/crash/201604301449/dump.201604301449

crash 7.1.4
Copyright (C) 2002-2015  Red Hat, Inc.
Copyright (C) 2004, 2005, 2006, 2010  IBM Corporation
Copyright (C) 1999-2006  Hewlett-Packard Co
Copyright (C) 2005, 2006, 2011, 2012  Fujitsu Limited
Copyright (C) 2006, 2007  VA Linux Systems Japan K.K.
Copyright (C) 2005, 2011  NEC Corporation
Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc.
Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc.
This program is free software, covered by the GNU General Public License,
and you are welcome to change it and/or distribute copies of it under
certain conditions.  Enter "help copying" to see the conditions.
This program has absolutely no warranty.  Enter "help warranty" for details.

GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu"...

      KERNEL: /usr/lib/debug/vmlinux-4.3.0-0.bpo.1-amd64
    DUMPFILE: /var/crash/201604301449/dump.201604301449  [PARTIAL DUMP]
        CPUS: 4
        DATE: Sat Apr 30 14:48:42 2016
      UPTIME: 00:11:27
LOAD AVERAGE: 0.41, 0.34, 0.33
       TASKS: 402
    NODENAME: Debian-PC
     RELEASE: 4.3.0-0.bpo.1-amd64
     VERSION: #1 SMP Debian 4.3.5-1~bpo8+1 (2016-02-23)
     MACHINE: x86_64  (3192 Mhz)
      MEMORY: 7.8 GB
       PANIC: "sysrq: SysRq : Trigger a crash"
         PID: 7930
     COMMAND: "tee"
        TASK: ffff88022fdd8f00  [THREAD_INFO: ffff88022cdd8000]
         CPU: 3
       STATE: TASK_RUNNING (SYSRQ)


В строке PANIC мы видим причину - искусственно вызванная паника. Утилита Crash имеет собственный набор команд, список которых можно получить командой help. Если вы введёте команду bt, то получите трассировку ядра:

PID: 7930   TASK: ffff88022fdd8f00  CPU: 3   COMMAND: "tee"
 #0 [ffff88022cddbc38] machine_kexec at ffffffff810552d9
 #1 [ffff88022cddbc90] crash_kexec at ffffffff810f667d
 #2 [ffff88022cddbd58] oops_end at ffffffff81018c94
 #3 [ffff88022cddbd78] no_context at ffffffff81060ce0
 #4 [ffff88022cddbdd0] page_fault at ffffffff8158cbb8
    [exception RIP: sysrq_handle_crash+18]
    RIP: ffffffff813ba8f2  RSP: ffff88022cddbe88  RFLAGS: 00010286
    RAX: 000000000000000f  RBX: ffffffff81abf760  RCX: 0000000000000000
    RDX: 0000000000000000  RSI: ffff88023bccdef8  RDI: 0000000000000063
    RBP: 0000000000000063   R8: 00000000000000c2   R9: 0000000000000002
    R10: ffff8800b4d8bd64  R11: 0000000000000002  R12: 0000000000000007
    R13: 0000000000000000  R14: 0000000000000002  R15: 0000000000000008
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
 #5 [ffff88022cddbe88] __handle_sysrq at ffffffff813bb04f
 #6 [ffff88022cddbeb0] write_sysrq_trigger at ffffffff813bb48b
 #7 [ffff88022cddbec0] proc_reg_write at ffffffff812355c3
 #8 [ffff88022cddbed8] vfs_write at ffffffff811d0114
 #9 [ffff88022cddbf10] sys_write at ffffffff811d0e72
#10 [ffff88022cddbf50] system_call_fast_compare_end at ffffffff8158a9f6
    RIP: 00007f4c58050e50  RSP: 00007ffc558a4d38  RFLAGS: 00000246
    RAX: ffffffffffffffda  RBX: 0000000000000002  RCX: 00007f4c58050e50
    RDX: 0000000000000002  RSI: 00007ffc558a4df0  RDI: 0000000000000003
    RBP: 00007ffc558a4df0   R8: 0000000000000000   R9: 0000000000000001
    R10: 00007ffc558a4ba0  R11: 0000000000000246  R12: 00007f4c5831b2a0
    R13: 0000000000000002  R14: 0000000000000002  R15: 0000000000000000
    ORIG_RAX: 0000000000000001  CS: 0033  SS: 002b


Конечно, не факт что вы сами в этом всё разберётесь, но вы можете показать эти данные более опытным людям, которые помогут вам определить причину сбоя.

Ссылки:

Статья на Habrahabr
Документация к KDump 
Документация к Crash
Книга, посвящённая проблемам диагностики сбоев ядра

 

2 комментария:

  1. Анонимный28 мая 2016 г., 0:51

    На build.opensuse.org можно с ускоренными ядрами сборки делать?

    ОтветитьУдалить