TL;DR
开始之前
目前普遍部署的的grub是,依据官方的叫法,grub legacy和grub。社区常见的称呼是grub(或者grub1)和grub2。我们引用的文档可能遵循社区的用法;这里我们遵循官方的用法。比如,我们说CentOS 6上默认部署的是grub legacy,而CentOS 7上默认部署的是grub;而不说我们说CentOS 6上默认部署的是grub1,而CentOS 7上默认部署的是grub2。
除了要注意不同版本的grub,排查、诊断或者确认时,有可能需要使用文件系统的元数据或者数据。因此,需要了解如何检查文件系统状态和确认文件在文件系统上的信息(比如文件使用的磁盘块信息)。同样,这也涉及了不止一个文件系统和不同工具。比如,CentOS 6一般使用的是Ext 3文件系统,CentOS 7也可以使用Ext 3/Ext4文件系统,但是默认使用的是XFS文件系统。
因为我们要修复的是引导器损坏,不了解磁盘分区几乎是不可能的。当然,相对而言,磁盘分区的种类要单调些。
因此,修复有问题的grub,需要较多的了解之。当然,简单的修复操作只需要大家对grub有粗略的了解即可。
grub是如何工作的?
grub是由某些固件启动的。无论是BIOS还是UEFI,引导grub进而引导操作系统时,都要解决一个问题:如何加载可以使用文件系统的模块。毕竟,无论是丰富的功能(比如菜单和各种选项支持),还是固件、内核乃至各种驱动模块,都以文件的方式存储在本地存储或者远端存储媒介上。
以MBR为例,可以供grub使用的空间不超过446字节。这种限制下不可能支持目前普遍使用的多种文件系统。所以grub必须提供一种解决方案来解决这个问题。
解决方案之一,只支持一种文件系统。比如UEFI就要求EFI系统分区必须是FAT32的文件系统。
解决方案之二,以模块的方式支持多文件系统。MBR模式下的grub legacy和grub其实都是以这种方案工作的,虽然两者的设计和实现迥然不同。
还有其他理论上可行的方案,这里我们只考虑上面那两种普遍使用的方案。这两种方案--无论是只支持一种文件系统,还是以模块的方式支持多种文件系统--都表明,在引导过程中,存在着一个不支持文件系统阶段和支持文件系统的阶段。
毫无疑问,对于在文件系统中如何找到一个文件我们是驾轻就熟。但是,如果文件系统不存在时,我们怎么定位和使用一个文件呢?答案是逻辑区块地址:LBA (Logical Block Addressing):即直接使用磁盘固件接口提供的定位和索引方案。所以,引导过程中,grub至少会使用两种文件定位方案:文件系统方案和LBA方案。
grub至少会使用两种文件定位方案,这引申出一个问题:如果grub以LBA的方式定位和使用一个文件,那么,这样的文件存储在哪里呢?
存储方式一。既然grub不通过文件系统接口使用这个文件,那么,这个文件完全没有必要存储在文件系统上。因为现在磁盘分区和文件系统都因效率或者兼容的原因,要满足对齐的约束。因此,分区之间,或者文件系统内部,都会有一些空闲不用的扇区。因此我们可以把这个文件存储在,比如,相邻两个分区之间的空闲扇区上。毫无疑问,这要求分区间的空闲扇区至少不小于这样文件需要的大小。我们会看到grub就采取的这种方案(把core.img存储在第一个分区前的空闲扇区中)。
存储方式二。把文件就存储在文件系统中。这种存储方式要求,虽然grub并不使用文件系统接口来定位和使用这个文件,但是,我们必须在文件系统中为这个文件建立记录。否则文件系统就对这个文件一无所知。文件系统的写操作可能覆盖之或者改动之。不在文件系统中为这个文件建立记录,这种被写操作破坏的问题就难以解决和避免。grub legacy就使用了这种存储方案。
虽然常见的情形是grub安装在磁盘的第一扇区,用作MBR。但是也存在着grub安装在跟文件系统的第一扇区,用作VBR,由其他MBR加载启动而已。比如,SUSE 11默认就是以Master Boot LoaDeR为MBR,而把grub安装在根文件系统第一扇区。
因此,检查、核实和修复grub,可能面临多种情形,需要考虑多种情况。幸好,grub提供了良好的封装。在简单情形下,修复grub有可能是一个简单任务。
比如,如果我们已经确认了是grub损坏,或者我们只是需要重新安装grub,那么,重新安装grub是很简单的一个任务。
重新安装grub:grub-install方法
grub legacy和grub默认都提供了grub-install工具。比如,如果我们要在/dev/vda盘上重新安装grub,那么,简单执行如下命令即可
grub-install /dev/vda
但是,使用grub-install过程中,需要注意以下几个问题。
- 不同的发行版提供的grub-install名称可能不同。比如,CentOS 6提供了grub-install,但是,CentOS 7提供的是grub2-install。
- grub默认使用的磁盘路径是底层(比如,BIOS、UEFI)提供的,与Linux启动后提供的磁盘路径并不一致。因此,grub使用(/boot/grub或者/boot/grub2目录下的)device.map文件来完成这两种路径之间的映射。在使用grub-install工具前,需要核实和确认device.map的内容是合适的。具体可以参考How to specify devices文档。
- CentOS、Debian和Ubuntu等系统,一般都有系统层级的grub的配置文件。其中也有关于磁盘映射的选项或者配置项,也需要调整。这样的配置文件,在CentOS系统上是/etc/sysconfig/grub文件,而在Debian或者Ubuntu则是/etc/default/bootloader或者/etc/default/grub文件。
- 因为grub-install工具不能处理/dev/xvda*路径,所以在磁盘路径是/dev/xvd*这种路径时,我们需要适当调整grub-install工具。
- 对grub,官方手册只提供了使用grub-install的安装方式;对grub legacy,则有手工安装方法。
- 我们这里只是修复grub,而不是(初次)安装之。
手工安装grub
grub-install工具是封装了grub legacy的底层工具来执行安装操作的。
比如,在[device.map]与grub legacy各类镜像文件和工具安装、部署完毕的情况下,如果/boot不是独立分区,则我们可以这样手工执行安装操作(更多请参考GInstalling GRUB natively)
[root@grub-demo ~]# grub
Probing devices to guess BIOS drives. This may take a long time.
GNU GRUB version 0.97 (640K lower / 3072K upper memory)
[ Minimal BASH-like line editing is supported. For the first word, TAB
lists possible command completions. Anywhere else TAB lists the possible
completions of a device/filename.]
grub> find /boot/grub/stage1
find /boot/grub/stage1
(hd0,0)
grub> root (hd0,0)
root (hd0,0)
Filesystem type is ext2fs, partition type 0x83
grub> setup (hd0)
setup (hd0)
Checking if "/boot/grub/stage1" exists... yes
Checking if "/boot/grub/stage2" exists... yes
Checking if "/boot/grub/e2fs_stage1_5" exists... yes
Running "embed /boot/grub/e2fs_stage1_5 (hd0)"... 27 sectors are embedded.
succeeded
Running "install /boot/grub/stage1 (hd0) (hd0)1+27 p (hd0,0)/boot/grub/stage2 /boot/grub/grub.conf"... succeeded
Done.
grub>
修复grub的步骤
我们讨论了grub如何工作、其使用存储和文件系统的特点,以及如何修复之。简单计,我们总结下修复grub的步骤
- 从存储和文件系统的角度排查和诊断grub的状态,确定是否是grub损坏。
- 核实并且必要时调整,使grub的修复环境和工具可用。
- 选择适当的方法修复之。