事情是这样的,刚才突然间我的 openSUSE 13.1 在重启后 grub2 就变成这样了:
Error :attempt to read or write outside of disk hd0
简单搜索了一下,感觉主要有三种可能:
-
grub2 升级导致的配置不兼容。
-
udev 或者别的升级导致 /etc/fstab 里所谓的 UUID 发生了变化,从而找不到硬盘。
/dev/disk/by-id/ata-SAMSUNG_HN-M101MBB_S2R8J9BB808817-part6 / ext4 acl,user_xattr 1 1
/dev/disk/by-id/ata-SAMSUNG_HN-M101MBB_S2R8J9BB808817-part5 /home ext4 acl,user_xattr 1 2
/dev/disk/by-id/ata-SAMSUNG_HN-M101MBB_S2R8J9BB808817-part2 /boot ext4 acl,user_xattr 1 2
/dev/disk/by-id/ata-SAMSUNG_HN-M101MBB_S2R8J9BB808817-part1 swap swap defaults 0 0
debugfs /sys/kernel/debug debugfs noauto 0 0
usbfs /proc/bus/usb usbfs noauto 0 0
SAMSUNG_HN-M101MBB_S2R8J9BB808817 这个就是 UUID。
- /boot/grub2/grub.cfg 不在硬盘靠最前的 8GB 当中。
为了验证以上可能,我首先需要一个 Live CD/DVD。毕竟 grub rescue> 这个环境是一个限制极大的环境(基本上只能用 ls,set,insmod 这几个命令),无助于调试。当然如果是简单的 grub2 问题,你也可以试试在这个环境下修复(就是尝试把你的系统引导起来,具体见:
zh.opensuse.org/%E4%BF%AE%E5%A4%8DGRUB2
zh.opensuse.org/SDB:%E4%BF%AE%E5%BE%A9_GRUB
)
但我面临的一个首要问题就是我没有 LiveCD,甚至连 openSUSE 的 ISO 都在进不去的这个系统里面。翻箱倒柜找到一张 11.4 的光盘,可惜光驱似乎是年久失修了,无法从光驱引导… 最后找到了一块老硬盘,上面是我换 1TB 硬盘前那个 128GB 笔记本硬盘,装着 openSUSE 12.1。于是关机,换硬盘,把 openSUSE 13.1 的硬盘装到移动硬盘盒里备用。
结果发现开不了机,于是我把 /etc/fstab 里用 /dev/disk/by-id/ata-SAMSUNG_HN-M101MBB_S2R8J9BB808817-part6 这种 UUID 表示的路径全部粗快猛地替换为了 /dev/sda6。怀疑可能是拆装硬盘会导致 UUID 变化。于是进去 openSUSE 12.1 了。
可是我又忘了当初之所以换硬盘很大一部分原因是我的 openSUSE 12.1 是 btrfs 文件系统,而那时的 btrfs 是实验性的,特别卡,于是我在图形界面那里连鼠标都动不了… 只好在内核引导选项那里 init 3 了。
现在进去了,开始修复:
-
由于刚才我修 openSUSE 12.1 的时候改 UUID 的成功误导了我,于是我在
fdisk -l
mount /dev/sda6 /mnt
mount -t proc proc /mnt/proc
mount --rbind /sys /mnt/sys
mount --rbind /dev /mnt/dev
chroot /mnt
(/dev/sda6 是我的 / 根分区,看前面的 fstab,我没有 /boot 单独分区,当然这是一个坑后面会讲)
后把 openSUSE 13.1 上的 /etc/fstab 里的 UUID 也替换成 /dev/sda6 这样的格式了。接着拆硬盘,发现 openSUSE 13.1 还是启动不了。看来不是 UUID 的问题。
于是我来实验是不是 grub2 版本的问题,可能需要更新 grub2 软件包一下。下面我直接面对的一个困难就是:我现在的无线连接不是以前那个了,而 openSUSE 12.1 里只保存了以前的 wifi 连接。我这种超人又不会简简单单的去禁用 NetworkManager 然后换 ifup 联网的(那样太简单了),于是想起用 NetworkManager 的命令行版本 nmcli 来做:
nmcli nm wifi on
nmcli dev wifi list
按道理接下来使用
nmcli dev wifi con ESSID password PASSWORD name CONN_NAME
nmcli con list
nmcli con up id MY_ID
就可以连接上了。可惜第一条命令报错了,后来各种手机连无线搜索发现原来在 0.9 版本以下的 nmcli 里不支持创建连接。于是想法破灭了。
按理现在该去用 ifup 联网去升级 grub2 软件包了吧。嘿别说,在鼓捣 nmcli 的过程里我想明白了一件事:grub2 唯一可能出现的问题就是没有装到 MBR 里去,或者装在 MBR 里的和更新过的不兼容… 那我直接 grub2-mkconfig -o /boot/grub2/grub.cfg && grub2-install /dev/sdb 不就好了(注意,因为我的 openSUSE 13.1 这时在移动硬盘盒里,所以是 sdb)。
尝试,发现没有用还是开不了机。
但是在这个过程中,我发现了一件奇妙的事:我的 /dev/sdb2 居然是一个 /boot 的内容,里面的内核版本还是 3.6.7 呢。那么就说明我在几年前安装 openSUSE 的时候我是单独分了 /boot 的,那为什么现在单独的 /boot 不挂载分区了,反而在我的 / 所在分区里面又建了一个 /boot,还抹去了我的 /etc/fstab 的部分内容呢!要知道,我的 / 分区可是在扩展分区上的,sda6 啊,磁盘的最后面。肯定超出 grub 可以识别的范围了呢!
于是进行第三种尝试:把 / 所在分区的 boot 文件及里的东西装到不知多久之前我那个 /boot 分区里去!
于是很简单:
mount /dev/sdb2 /media
mount /dev/sdb6 /mnt
rm -rf /media/*
cp -r /mnt/boot/* /media
mv /mnt/boot /mnt/boot_bak
对拷完毕,挂载之:
mount /dev/sdb6 /mnt
mount /dev/sdb2 /mnt/boot
这时还没完,因为没写到 /etc/fstab 里,/boot 所在分区根本不会自动挂载,于是加了一个
/dev/sdb2 /boot ext4 acl,user_xattr 1 2
以确保我的 /boot 能挂载。顺便学了下 fstab 格式,原来之前一直以为没什么用的 1, 2,第一个数字表示 dump 的时候是否 dump 它,0 为否 1 为是 ; 第二个数字表示 fsck 时候检查的顺序,/ 根分区必须为 1 而其它的分区为 2。
然后再重新 grub2-mkconfig 了一下,不要问我为什么,你的新的 /boot 的 UUID 跟原来 / 的肯定不一样,而 grub2 是基于 UUID 来制作 grub.cfg 的。总之不这么做你肯定启动不来。
接着重启,出现了久违的 grub2 图形界面。
但问题又来了,开不了机。检查了一下,发现原来是当初 openSUSE 13.1 在移动硬盘上,是 /dev/sdb 于是 grub2-install /dev/sdb,而现在换了硬盘 openSUSE 13.1 是唯一的一块硬盘应该是 /dev/sda,而 grub2 配置里的 root=/dev/sdb6 显然不对,按 e 修改为 sda,这回进入到 openSUSE 了。
但是我发现我的引导选项里居然有两个 Windows 7,一个在 sda 上,一个在 sdb 上。原来我之前那块 openSUSE 12.1 的硬盘里也有一个 Windows 7,于是 grub2-mkconfig 的时候就也弄上了。
于是在引导起来的 openSUSE 13.1 里再次 grub2-mkconfig,现在一切都回来了。
总结一下:
Error :attempt to read or write outside of disk hd0
这个错误是由于:3. /boot/grub2/grub.cfg 不在硬盘靠最前的 8GB 当中。简单说就是你需要一个独立的 /boot 分区。
但为什么「那为什么现在单独的 /boot 不挂载分区了,反而在我的 / 所在分区里面又建了一个 /boot,还抹去了我的 /etc/fstab 的部分内容呢!」,而且之前又能正常引导呢?!我怀疑可能跟 grub2 升级有关。回头看下 YaST2 日志看看是不是升级 KDE 4.13 的时候连带升级了 grub2 吧。
结束。