1. 简介

本文主要记录博主在日常使用 Linux 系统时,遇到的一些导致 Linux 系统 Grub 引导失败的问题。

2. Windows 更新导致

若电脑上存在双系统,则 Windows 系统大更新时会导致 Linux 系统的 Grub 引导失败。具体原因及分析见下文:

问题

我的电脑装有 Windows 10 和 Manjaro 双系统,最近我把 Windows 10 升级了,没想到原来漂亮的 Manjaro Grub 菜单界面就再也出不来了,只见终端弹出一下信息:

1
2
error:unknow filesystem
grub rescue>

此时进入的是 Grub 修复模式,此模式下可以使用的终端命令很少,大部分 Linux Shell 命令无法使用。

解决

  • 使用 ls 命令查看系统分区信息

    1
    grub rescue> ls

    此时一般显示如下信息(以下是我的系统显示的信息):

    1
    2
    (hd0,gpt1),(hd0,gpt2),(hd0,gpt3),(hd0,gpt4),(hd0,gpt5),(hd0,gpt6),(hd1,gpt1),
    (hd1,gpt2),(hd1,gpt3),(hd1,gpt4),(hd1,gpt5),(hd1,gpt6)

    其中,hdx 表示系统的磁盘号,我电脑装有双磁盘,故有 hd0 和 hd1 ;gpty 表示分区号,一般装有系统的磁盘的第一个分区 gpt1 为引导分区,其存有系统的 .efi 引导文件 。

  • 使用 set 命令查看 grub 信息

    1
    grub rescue> set

    此时一般显示如下信息(以下是我的系统显示的信息):

    1
    2
    3
    cmdpath=(hd1,gpt1)/EFI/MANJARO    # 该环境变量表明 UEFI 的 .efi 镜像文件(系统引导文件)的绝对路径
    prefix=(hd1,gpt3)/boot/grub # 该环境变量表明 grub 的安装目录,用于载入系统
    root=hd1,gpt3 # 该环境变量表明启动的分区
  • efi 文件一般确实是存放在一个磁盘的第一个分区的,一般不会有问题;于是可以再使用 ls 命令查看显示的 prefix 对应的分区是否是 Linux 文件系统

    1
    grub rescue> ls (hd1,gpt3)/

    结果报错:

    1
    2
    error:unknow filesystem
    grub rescue>

    说明该文件系统不是 Linux 文件系统,然后我顺着查找下一个分区

    1
    grub rescue> ls (hd1,gpt4)/

    结果正确显示出 Linux 文件系统结构出来了:

    1
    / ../ lost+found/ boot/ etc/ medita/ ...
  • 于是乎利用 set 命令修改环境变量 prefix 和 root (因为 cmdpath 并没有问题)

    1
    2
    grub rescue> set prefix=(hd1,gpt4)/boot/grub
    grub rescue> set root=hd1,gpt4
  • 然后使用 insmod 命令加载正常模块并进入 Linux 系统

    1
    2
    grub rescue> insmod normal    # 加载正常模块(如果修改正确则输出的 grub rescue> 颜色会改变)
    grub rescue> normal # 载入 Linux 系统
  • 最后成功进入 Manjaro 操作系统

分析

由于我的电脑 Windows 10 系统是安装在 Manjaro 之前的,根据 prefix 环境变量可知,除去 gpt1 引导分区外,就说明 gpt2 是 Windows 10 的系统分区,而之前 gpt3 是 Manjaro 系统的分区,那为什么 Windows 10 更新后就变成 gpt4 了呢?

答案是 Windows 10 更新新增了一个分区,导致系统分区号发生变化。

已经进入 Manjaro 系统的我打开 Gparted 分区助手软件一查看,果然是 Windows 10 更新搞的鬼,Windows 10 更新后为了保证系统能够回退,又再原系统分区尾部分出一块分区用于保存旧版本信息,所以导致后续所有的分区号往后增加了一个单位,所以导致 prefixroot 环境变量失效。

修复

进入系统后,需要更新引导信息,否则下次还得如此复杂才能进入系统:

1
2
sudo update-grub        
sudo grub-install /dev/sdb # /dev/sdb 是系统所在的磁盘标号(可以使用 fdisk -l 命令查看)