如何从与内核相关的启动问题中恢复 Azure Linux 虚拟机

本文提供了一个问题的解决方案,即 Linux 虚拟机 (VM) 应用内核更改后无法重新启动。

原始产品版本:   运行 Linux 的虚拟机
原始 KB 编号:   4091524

症状

将某些内核更改 (如内核) Azure 上的 Linux 虚拟机 (VM) 后,虚拟机无法重新启动。 启动过程中将记录以下内核错误之一:

  • "未找到根设备"错误,类似于以下错误:

    dracut Warning: No root device "block:/dev/disk/by-uuid/UUID" found
    dracut Warning: Boot has failed. To debug this issue add "rdshell" to the kernel command line.
    dracut Warning: Signal caught!
    Kernel panic - not syncing: Attempted to kill init!
    Pid: 1, comm: init Not tainted 2.6.32-504.12.2.el6.x86_64 #1
    Call Trace:
    [<ffffffff8152933c>] ? panic+0xa7/0x16f
    [<ffffffff8107a5f2>] ? do_exit+0x862/0x870
    [<ffffffff8118fa25>] ? fput+0x25/0x30
    [<ffffffff8107a658>] ? do_group_exit+0x58/0xd0
    [<ffffffff8107a6e7>] ? sys_exit_group+0x17/0x20
    [<ffffffff8100b072>] ? system_call_fastpath+0x16/0x1b
    
  • 与以下错误类似的内核超时错误:

    INFO: task swapper:1 blocked for more than 120 seconds.
    Not tainted 2.6.32-504.8.1.el6.x86_64 #1
    "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
    swapper       D 0000000000000000     0     1      0 0x00000000
    ffff88010f64fde0 0000000000000046 ffff88010f64fd50 ffffffff81074f95
    0000000000005c2f ffffffff8100bb8e ffff88010f64fe50 0000000000100000
    0000000000000002 00000000fffb73e0 ffff88010f64dab8 ffff88010f64ffd8
    Call Trace:
    [<ffffffff81074f95>] ? __call_console_drivers+0x75/0x90
    [<ffffffff8100bb8e>] ? apic_timer_interrupt+0xe/0x20
    [<ffffffff81075d51>] ? vprintk+0x251/0x560
    [<ffffffff8152a862>] schedule_timeout+0x192/0x2e0
    [<ffffffff810874f0>] ? process_timeout+0x0/0x10
    [<ffffffff8152a9ce>] schedule_timeout_uninterruptible+0x1e/0x20
    [<ffffffff81089650>] msleep+0x20/0x30
    [<ffffffff81c2a571>] prepare_namespace+0x30/0x1a9
    [<ffffffff81c2992a>] kernel_init+0x2e1/0x2f7
    [<ffffffff8100c20a>] child_rip+0xa/0x20
    [<ffffffff81c29649>] ? kernel_init+0x0/0x2f7
    [<ffffffff8100c200>] ? child_rip+0x0/0x20
    
  • 类似于下面的空指针错误:

    Pid: 242, comm: async/1 Not tainted 2.6.32-504.12.2.el6.x86_64 #1
    Call Trace:
    [<ffffffff81177468>] ? kmem_cache_create+0x538/0x5a0
    [<ffffffff8152aede>] ? mutex_lock+0x1e/0x50
    [<ffffffff81370424>] ? attribute_container_add_device+0x104/0x150
    [<ffffffffa009c1de>] ? storvsc_device_alloc+0x4e/0xa0 [hv_storvsc]
    [<ffffffff8138a1dc>] ? scsi_alloc_sdev+0x1fc/0x280
    [<ffffffff8138a739>] ? scsi_probe_and_add_lun+0x4d9/0xe10
    [<ffffffff8128e62d>] ? kobject_set_name_vargs+0x6d/0x70
    [<ffffffff8152aede>] ? mutex_lock+0x1e/0x50
    [<ffffffff81370424>] ? attribute_container_add_device+0x104/0x150
    [<ffffffff81367ae9>] ? get_device+0x19/0x20
    [<ffffffff8138b440>] ? scsi_alloc_target+0x2d0/0x300
    [<ffffffff8138b661>] ? __scsi_scan_target+0x121/0x740
    [<ffffffff8138bd07>] ? scsi_scan_channel+0x87/0xb0
    [<ffffffff8138bde0>] ? scsi_scan_host_selected+0xb0/0x190
    [<ffffffff8138bf51>] ? do_scsi_scan_host+0x91/0xa0
    [<ffffffff8138c13c>] ? do_scan_async+0x1c/0x150
    [<ffffffff810a7086>] ? async_thread+0x116/0x2e0
    [<ffffffff81064b90>] ? default_wake_function+0x0/0x20
    [<ffffffff810a6f70>] ? async_thread+0x0/0x2e0
    [<ffffffff8109e66e>] ? kthread+0x9e/0xc0
    [<ffffffff8100c20a>] ? child_rip+0xa/0x20
    [<ffffffff8109e5d0>] ? kthread+0x0/0xc0
    [<ffffffff8100c200>] ? child_rip+0x0/0x20
    BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
    IP: [<ffffffffa009c0a0>] storvsc_device_destroy+0x20/0x50 [hv_storvsc]
    PGD 0
    
  • 与以下错误类似的内核内核错误:

    Invalid op code: 0000 [#2] [11427.908676] - end trace 61a458bb863d7f0f ]-
    Kernel panic - not syncing: attempted to kill the idle task!
    

分辨率

提示

如果你有 VM 的最新备份,可以尝试从备份还原 VM 以修复启动问题。

若要在 Azure 上恢复 Linux VM,必须安装较新的内核,或者使用下列修复选项之一手动回滚到早期版本。

若要执行此操作,请使用常规过程:删除受影响的 Linux VM 并保留操作系统磁盘,然后将磁盘附加到具有受影响 VM (或至少相同分发版本的新 VM) 。 然后,使用以下修复选项之一。

修复选项 1

回滚内核,然后通过编辑配置文件从以前的工作设置开始。 有关详细信息,请参阅 如何更新配置文件

备注

Linux 启动加载程序通常具有多个定义要用于启动的内核的条目。 当您执行升级以引用新安装的内核时,条目将更新。

修复选项 2

安装或重新安装内核,方法为将受影响的 VM 操作系统磁盘附加到临时的新 VM,然后运行一个工具,如 apt-get、 (Yellowdog Updater Modified YUM) 或 Zypper 。 有关详细信息,请参阅Linux 恢复:使用 CHROOT 步骤恢复不可访问的 VM。

备注

第二个选项可能是进行修复的最佳方法,因为不需要手动编辑文件。

如果 VM 无法从以前的内核启动,可以尝试重建 initramfs 文件,然后复制 Linux 内核的新压缩映像。 有关详细信息,请参阅 如何重新生成 initramfs 文件

详细信息

关于配置文件

可以使用命令 uname -a 获取所有系统信息。 例如,如果运行 CentOS 6.6 的 Linux VM 已加载内核版本 2.6.32-504.16.2.el6.x86_64,则获得以下输出:

Linux vfldev 2.6.32-504.16.2.el6.x86_64 #1 SMP Date\Time x86_64 x86_64 x86_64 GNU/Linux

启动加载程序配置文件包含有关将加载的内核版本的信息。 CentOS 的文件为 /boot/grub/grub.conf,自 RHEL 7 起的新版为 /boot/grub2/grub.cfg。

grub.conf 文件的前四行包含有关当前加载版本的以下信息:

  • title: 指定仅在菜单中显示的标题 (不适用于云环境) 。
  • root: 指定根分区。
  • 内核: 指定在启动时加载的内核命令行及其参数。
  • initrd: 指定要加载以启动的 initrd 文件的路径,该路径通常与内核的安装路径匹配。

下面是不同版本的 Linux 内核的 grub 文件示例:

title CentOS (2.6.32-504.16.2.el6.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-504.16.2.el6.x86_64 ro root=UUID=UUIDrd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM numa=off console=ttyS0 earlyprintk=ttyS0 rootdelay=300 crashkernel=auto
initrd /boot/initramfs-2.6.32-504.16.2.el6.x86_64.img
title CentOS (2.6.32-504.12.2.el6.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-504.12.2.el6.x86_64 ro root=UUID=UUIDrd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM numa=off console=ttyS0 earlyprintk=ttyS0 rootdelay=300 crashkernel=auto
initrd /boot/initramfs-2.6.32-504.12.2.el6.x86_64.img
title CentOS (2.6.32-504.8.1.el6.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-504.8.1.el6.x86_64 ro root=UUID=UUIDrd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM numa=off console=ttyS0 earlyprintk=ttyS0 rootdelay=300 crashkernel=auto
initrd /boot/initramfs-2.6.32-504.8.1.el6.x86_64.img
title CentOS (2.6.32-431.29.2.el6.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-431.29.2.el6.x86_64 ro root=UUID=UUIDrd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM numa=off console=ttyS0 earlyprintk=ttyS0 rootdelay=300
initrd /boot/initramfs-2.6.32-431.29.2.el6.x86_64.img

更新配置文件的方法

若要将启动加载程序 (grub.conf) 并强制 Linux VM 加载其他内核,需要手动干预。 若要执行此操作,请使用下列方法之一。

方法 1:串行控制台

串行控制台是解决此问题的最快方法。 这允许你直接修复此问题,而无需向恢复 VM 显示系统磁盘。 确保您已满足分发的必要先决条件。 有关详细信息,请参阅适用于 Linux 的虚拟机串行控制台。 有权访问串行控制台后,转到缓解 步骤。 完成缓解步骤后,重新启动 VM。

方法 2:脱机修复

如果 VM 上未启用串行控制台,或者它不起作用,你可以按照以下步骤脱机修复系统:

  1. 将 VM 的系统磁盘作为数据磁盘附加到任何运行中的 Linux VM (恢复 VM) 。 为此,请使用 CLI 命令或 VM 恢复脚本
  2. 按照缓解部分中的步骤操作。
  3. 卸载并分离原始虚拟硬盘,然后从原始系统磁盘创建 VM。 为此,请使用 CLI 命令或 VM 恢复脚本

缓解步骤

  1. 修改 /mnt/troubleshootingdisk /boot/grub.conf 文件。 下面是修改后的 grub.conf 文件的示例:

    #title CentOS (2.6.32-504.16.2.el6.x86_64)
    
    #root (hd0,0)
    
    #kernel /boot/vmlinuz-2.6.32-504.16.2.el6.x86_64 ro root=UUID=UUID rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM numa=off console=ttyS0 earlyprintk=ttyS0 rootdelay=300 crashkernel=auto
    
    #initrd /boot/initramfs-2.6.32-504.16.2.el6.x86_64.img
    
  2. 检查启动加载程序文件 grub.conf 中 UUID 值指定的设备是否存在。

    例如,当您通过查看 来检查装入的系统磁盘时,可以看到磁盘上有一个在 grub.conf 文件中引用的相应 /mnt/troubleshootingdisk /mnt/troubleshootingdisk /dev/disk/by-uuid UUID 文件。 文件实际上是一个符号链接,在指向操作系统磁盘 sda1 的 lrwxrwxrwx 属性的起始位置由字符 l 表示。 如果文件缺失,可以在系统启动期间重新创建符号链接。

  3. 如果你知道 sda1 是否是启动设备并且知道相应的 UUID,则可以通过运行以下命令手动创建符号链接:

    cd /mnt/troubleshootingdisk/dev/disk/by-uuid ln -s ../../sda1 UUID
    

    备注

    sda1 文件在 Linux 中称为阻止设备。 可以在命令输出中检查它,命令输出中由 属性 ls 中的 字符 b brw-rw-- 表示。

  4. 还可以检查此文件是否存在于 CentOS 6.5 上,如果该文件缺失,可以重新创建该文件。 例如,运行以下命令:

    cd /mnt/troubleshootingdisk/dev/disk/by-uuid ls -ltr ../../sda1
    

    输出类似于以下输出:

    brw-rw-- 1 root disk 8, 1 Date\Time ../../sda1
    

    可以使用以下命令确定文件类型:

    file ../../sda1 ../../sda1: block special
    

如何重新生成 initramfs 文件

在上一部分中的示例 grub 文件中可以看到 initramfs 和 (文件,) 如下所示:

  • Initramfs 文件

    initrd /boot/initramfs-2.6.32-504.16.2.el6.x86_64.img

  • 内核文件

    /boot/vmlinuz-2.6.32-504.16.2.el6.x86_64

通常,从恢复 cd 本地环境启动系统。 但是,在云环境中,您必须将系统磁盘附加到相同操作系统和版本的临时 VM,以针对无启动方案恢复或操作系统文件。 当你尝试复制或重新创建 initramfs 和内核文件时需要它。

备注

在 /mnt/troubleshootingdisk (上将操作系统磁盘附加到临时 VM 后 (首先通过从操作系统磁盘) 复制来保护任何数据,如果已注释掉引用第一个内核以启动的条目,请将以前所做的更改还原到 grub.conf。如果已注释掉引用第一个内核的条目,请重新添加这些更改。

可以按照以下步骤重新生成 initramfs 文件:

  1. 生成基于现有版本的 initramfs 文件:

    mv /mnt/troubleshootingdisk/boot/initramfs-2.6.32-504.8.1.el6.x86_64.img /mnt/troubleshootingdisk/boot/initramfs-2.6.32-504.8.1.el6.x86_64.old-img dracut /mnt/troubleshootingdisk/boot/initramfs-2.6.32-504.8.1.el6.x86_64.img 2.6.32-504.8.1.el6.x86_64

    例如,必须生成并使用临时 CentOS 6.6 Linux VM 上提供的最新版本,因为无法找到完全相同的 initramfs 文件。

  2. 复制相关的 vmlinuz 文件,然后更新 grub.conf 文件以反映新的内核值。 为此,请使用下表中的命令。

Command "输出"
ls -ltr /lib/modules/ drwxr-xr-x. 7 root root 4096 Date 2.6.32-431.11.2.el6.x86_64
drwxr-xr-x. 7 root root 4096 Date 2.6.32-431.17.1.el6.x86_64
drwxr-xr-x. 7 root root 4096 Date 2.6.32-431.29.2.el6.x86_64
drwxr-xr-x. 7 root root 4096 Date\Time 2.6.32-504.1.3.el6.x86_64
drwxr-xr-x. 7 root root 4096 Date\Time 2.6.32-504.12.2.el6.x86_64
dracut /mnt/troubleshootingdisk/boot/initramfs-2.6.32-504.12.2.el6.x86_64.img 2.6.32-504.12.2.el6.x86_64
ls -ltr /mnt/troubleshootingdisk/boot/initramfs-2.6.32-504.12.2.el6.x86_64.img
-rw---. 1 root root 19354168 Date\Time /mnt/troubleshootingdisk/boot/initramfs-2.6.32-504.12.2.el6.x86_64.img
cp /boot/vmlinuz-2.6.32-504.12.2.el6.x86_64 /mnt/troubleshootingdisk/boot/
ls -ltr /mnt/troubleshootingdisk/boot/vmlinuz*
-rwxr-xr-x. 1 root root 4128368 Date\Time /mnt/troubleshootingdisk/boot/vmlinuz-2.6.32-431.el6.x86_64
-rwxr-xr-x. 1 root root 4128688 Date\Time /mnt/troubleshootingdisk/boot/vmlinuz-2.6.32-431.3.1.el6.x86_64
-rwxr-xr-x. 1 root root 4129872 Date\Time /mnt/troubleshootingdisk/boot/vmlinuz-2.6.32-431.17.1.el6.x86_64
-rwxr-xr-x. 1 root root 4131984 Date\Time /mnt/troubleshootingdisk/boot/vmlinuz-2.6.32-431.29.2.el6.x86_64
-rwxr-xr-x. 1 root root 4153008 Date\Time /mnt/troubleshootingdisk/boot/vmlinuz-2.6.32-504.8.1.el6.x86_64
-rwxr-xr-x. 1 root root 4152720 Date\Time /mnt/troubleshootingdisk/boot/vmlinuz-2.6.32-504.12.2.el6.x86_64
vi /mnt/troubleshootingdisk/boot/grub/grub.conf title CentOS (2.6.32-504.12.2.el6.x86_64)
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-504.12.2.el6.x86_64 ro root=UUID=UUID rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet numa=off console=ttyS0 earlyprintk=ttyS0 rootdelay=300
initrd /boot/initramfs-2.6.32-504.12.2.el6.x86_64.img