分类: LINUX
2009-12-16 23:17:08
由于拿到别人的一台装有RHEL5系统机器,无意中发现了一个有趣的现象。
在这台机器中有四个分区,sda1(boot分区), sda2(系统所在的分区) sda3(也是一个装有系统的分区,双系统)swap。
问题在这个地方:
在/boot/grub/grub.conf里,根是这样定义的:
kernel /vmlinuz-2.6.18-128.el5 ro root=/dev/sda2 vga=773
在/etc/fstab里却有点变化:
/dev/sda3 / ext3 defaults 1 1
这显然是一个错误的写法。按照我的理解,如果这样写的话,最终进到系统里,系统的根分区应该是/dev/sda3。可是实际上却不是这样,进入系统后,看到的情况是,用,df或mount查看,会看到分区与挂载点的关系是/dev/sda3 on / type ext3 (rw),但进入到根目录,正在使用的内容却是/dev/sda2上面的。
其实是一个很简单的问题,因为从系统的启动来看,根分区是最先也是一直被挂载的,而且在grub里面被定义了位置。但疑惑的是,在系统看来,为什么/dev/sda2变成了/dev/sda3,引起了对应关系的错乱,是哪个操作过程引起的bug呢?于是,我的爱折腾的心又起。
我首先测试了mount的特点,发现了几个以前常以为不应该的问题(RHEL5,RHEL4没测,忘了):
1、 在/etc/fstab里面,/的挂载信息不一定要放在第一行。
2、 一个挂载点可以被挂载多次,后挂载的会覆盖新挂载的内容。
3、 一个分区可以被挂载多次到不同的挂载点下。
4、 一个挂载点正在被使用也可以被其他的分区覆盖挂载,只是不能umount。
虽然弄清了上述问题,但还是不能想不通我的疑惑,因为系统启动的时候,根分区是以只读挂载的,在加载完kernel和initrd以及系统初始化后,会以rw的方式重新挂载根文件系统。那么根据第二点,和第四点,就说不通了,而且为什么会出现设备号混乱的情况。
看来问题出在重新挂载的过程。
通过查看系统启动时的屏幕显示,可以知道系统启动的大致过程。
1、 BIOSàMBRàgrub
2、 kernel boot
3、 waiting for driver initialization
4、 Creating root device ; Mounting root filesystem(readonly).
5、 注意这一段:
EXT3-fs:INFO:recovery required on readonly filesystem.
EXT3-fs:write access will be enabled during recovery.
kjournald starting. Commit interval 5 seconds.
EXT3-fs:recovery complete.
EXT3-fs:mounted filesystem with ordered data mode.
Setting up other filesystem.
Setting up new root fs
no fstab.sys,mounting internal defaults.
Switching to new root and running init.
unmounting old /dev
unmounting old /proc
unmounting old /sys
6、 INIT:version 2.86 booting
通过第五段来看,似乎对rootfs加入的写访问的支持。
于是我进行了如下测试:
在grub.conf中修改:
kernel /vmlinuz-2.6.18-128.el5 ro root=/dev/sda2 vga=773 init=/bin/bash
目的是使启动进行到第6步时,暂停,并提供一个交互的shell。
我通过shell执行:
df –h
/dev/sda3 …… /
mount
/dev/sda3 on / type ext3 (rw)
proc on /proc type proc (rw)
cat /etc/mtab
/dev/sda3 / ext3 rw 0 0
proc /proc proc rw 0 0
cat /proc/mounts
rootfs / rootfs rw 0 0
/dev/root / ext3 ro,data=ordered 0 0
/dev /dev tmpfs rw 0 0
/proc /proc proc rw 0 0
/sys /sys sysfs rw 0 0
此时的根文件系统是只读的,而且除了/分区(实际是/dev/sda2)被只读挂载外,其他的分区均没有被挂载(比如/boot,有可能在某些情况下(非正常关机)可以看得到其他分区被挂载的信息,但实际上挂载点内是空的)。所以可以认为:
1、 df mount命令查看的/etc/mtab当中的内容(是根据fstab来的)。
2、 系统进行到这一步,还不涉及fstab。
3、 真正挂载到根目录下的是/dev/root这个设备,挂载的参数是ro, data=ordered
接下来再继续系统的正常启动:
接上面的第6步:7.init(配置文件/etc/inittab) àrc.sysinit(系统初始化脚本)àinitàrc(运行级别对应启动的服务和预执行的脚本)àinitàmingettyàloginàshell.
在系统初始化的过程中,看到:
Checking filesystems
/dev/sda3: ……
/boot: ……
Remounting root filesystem in read-write mode:
Mouting local filesystems:
Enabling local filesystems quotas:
Enabling /etc/fstab swaps:
到这里就关/etc/fstab的事了。查看rc.sysinit:
vim /etc/rc.d/rc.sysinit
……
# Remount the root filesystem read-write.
update_boot_stage RCmountfs
if remount_needed ; then
action $"Remounting root filesystem in read-write mode: " mount -n -o remount,rw /
fi
……
关键就在这里了,因为此时的根文件系统是被挂载的,当执行”mount –n –o remount,rw /”时,remount 这个参数并不会执umount的过程,只是更改了挂载的参数,而remount分区和挂载点对应的依据是fstab。这个时候,原本是/dev/sda2挂在/下的,没umount ,但一remount,和fstab里面的内容一匹配,好,乱套了。
注意,系统初始化的时候会依据fstab的最后一列的顺序对分区进行完整性检查(Checking)。如果这里出错的话,系统将无法启动,可以修复模式(Repair filesystem)
为了验证上述判断,我将fstab中的/对应的的设备改为/dev/xxxx的错误形式,再启动。
果然在Checking的时候过不了,此时按ctrl+d将重启,输入root密码回车将进入Repair filesystem。
说明不管正确与否,mtab都会记录fstab的挂载信息(尝试挂载过的),所以df 或mount命令就会读到不匹配的信息。
执行mount –o rw,remount /,报错,说没有这个设备,证明此操作会找fstab。
执行mount –o rw,remount /dev/root / ,成功,根目录可写了,证明/dev/root就是根分区。其实通过查看设备号也可以知道:ls –l /dev/root /dev/sda2,但两者是同一分区又不是同一设备文件,所以当/dev/root被挂载时,/dev/sda2没有挂载。
还是有问题解决不了,那就是当我在重复实验的时候,得到的结果会不一样了,有时候看到的/etc/mtab 里面是/dev/xxxx ,有时候是/dev/sda3, 有时候是/dev/sda2。当把mtab里面的内容清空,将/etc/fstab里面的写成/dev/xxxx,在修复模式下居然我所不能理解的是,mtab是怎样与fstab保持同步的?
做了最后一个实验:用init=/bin/bash将系统启动暂停,查看mtab内容,然后在修改fstab里的根文件系统的对应关系与现在的mtab不同,执行/etc/rc.d/rc.sysinit,查看mtab。
得到如下结论:
启动时,在初始化之前,mtab里记录的内容与根文件系统上一次挂载的对应关系相同。在执行完rc.sysinit脚本后,则变成与fstab的内容相同。而实际的分区始终未变化。这样或许能解释上面的疑问。
看来,要确切的清楚细节,是需要看源码才行啊。