如何从与内核相关的启动问题中恢复 Azure Linux 虚拟机
07/21/2020
本文内容
本文提供了一个问题的解决方案,即 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:
[] ? panic+0xa7/0x16f
[] ? do_exit+0x862/0x870
[] ? fput+0x25/0x30
[] ? do_group_exit+0x58/0xd0
[] ? sys_exit_group+0x17/0x20
[] ? 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:
[] ? __call_console_drivers+0x75/0x90
[] ? apic_timer_interrupt+0xe/0x20
[] ? vprintk+0x251/0x560
[] schedule_timeout+0x192/0x2e0
[] ? process_timeout+0x0/0x10
[] schedule_timeout_uninterruptible+0x1e/0x20
[] msleep+0x20/0x30
[] prepare_namespace+0x30/0x1a9
[] kernel_init+0x2e1/0x2f7
[] child_rip+0xa/0x20
[] ? kernel_init+0x0/0x2f7
[] ? child_rip+0x0/0x20
类似于下面的空指针错误:
Pid: 242, comm: async/1 Not tainted 2.6.32-504.12.2.el6.x86_64 #1
Call Trace:
[] ? kmem_cache_create+0x538/0x5a0
[] ? mutex_lock+0x1e/0x50
[] ? attribute_container_add_device+0x104/0x150
[] ? storvsc_device_alloc+0x4e/0xa0 [hv_storvsc]
[] ? scsi_alloc_sdev+0x1fc/0x280
[] ? scsi_probe_and_add_lun+0x4d9/0xe10
[] ? kobject_set_name_vargs+0x6d/0x70
[] ? mutex_lock+0x1e/0x50
[] ? attribute_container_add_device+0x104/0x150
[] ? get_device+0x19/0x20
[] ? scsi_alloc_target+0x2d0/0x300
[] ? __scsi_scan_target+0x121/0x740
[] ? scsi_scan_channel+0x87/0xb0
[] ? scsi_scan_host_selected+0xb0/0x190
[] ? do_scsi_scan_host+0x91/0xa0
[] ? do_scan_async+0x1c/0x150
[] ? async_thread+0x116/0x2e0
[] ? default_wake_function+0x0/0x20
[] ? async_thread+0x0/0x2e0
[] ? kthread+0x9e/0xc0
[] ? child_rip+0xa/0x20
[] ? kthread+0x0/0xc0
[] ? child_rip+0x0/0x20
BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
IP: [] 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 上未启用串行控制台,或者它不起作用,你可以按照以下步骤脱机修复系统:
将 VM 的系统磁盘作为数据磁盘附加到任何运行中的 Linux VM (恢复 VM) 。 为此,请使用 CLI 命令或 VM 恢复脚本。
按照缓解部分中的步骤操作。
卸载并分离原始虚拟硬盘,然后从原始系统磁盘创建 VM。 为此,请使用 CLI 命令或 VM 恢复脚本。
缓解步骤
修改 /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
检查启动加载程序文件 grub.conf 中 UUID 值指定的设备是否存在。
例如,当您通过查看 来检查装入的系统磁盘时,可以看到磁盘上有一个在 grub.conf 文件中引用的相应 /mnt/troubleshootingdisk /mnt/troubleshootingdisk /dev/disk/by-uuid UUID 文件。 文件实际上是一个符号链接,在指向操作系统磁盘 sda1 的 lrwxrwxrwx 属性的起始位置由字符 l 表示。 如果文件缺失,可以在系统启动期间重新创建符号链接。
如果你知道 sda1 是否是启动设备并且知道相应的 UUID,则可以通过运行以下命令手动创建符号链接:
cd /mnt/troubleshootingdisk/dev/disk/by-uuid ln -s ../../sda1 UUID
备注
sda1 文件在 Linux 中称为阻止设备。 可以在命令输出中检查它,命令输出中由 属性 ls 中的 字符 b brw-rw-- 表示。
还可以检查此文件是否存在于 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 文件:
生成基于现有版本的 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 文件。
复制相关的 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