轉載此文章是確實幫助到我,也希望能幫助到其它人;
解決 VFS:Unable to mount root fs on Unknown-block(0,0) 的問題,有可能是內核升級過程中引導文件損壞造成,如有老內核,可進入系統重新重成新內核的引導文件放到/boot/ 下即可。:) 重新生成引導文件方法參見下文“四、GRUB(GRand Unified Bootloader)、加載內核” -> “如何製作 initramfs”
我們在使用Linux操作系統的時候,我們只需按下電源鍵,等待,然後輸入賬戶和密碼就可以使用Linux操作系統了。那麼在按下電源到輸入賬號和密碼之前,操作系統都做了些什麼?下面就來講述在這段時間發生的動作。
下面以CentOS6系列爲例來講解Linux的啓動流程。
一、Linux啓動流程詳解
下圖就是啓動流程的大致過程:
二、POST加電自檢
POST(PowerOnSelfTest)首先對每一個設備進行檢查。完成後會尋找存有引導記錄的設備,找到後讀入操作系統引導記錄,然後將系統控制權交給引導記錄,並由引導記錄來完成系統的順利啓動。
三、MBR引導
MBR(Master Boot Record) MBR記錄一般是在磁盤 0 磁道 1 扇區,共512個字節。前446個字節是BootLoder,後 4*16 的 64 個字節是存放分區信息的,最後 2 個字節是校驗信息,一般是 55AA。
四、GRUB(GRand Unified Bootloader)、加載內核
就是MBR中的前 446 個字節,是BooTLoader的一種,它的作用是要選擇要啓動的內核。
1、GRUB程序的組成:
主要是由device.map,menulst,stage1,stage2,以及一系列的stage1_5組成。對於這些部分我的理解是這樣:
- device.map:存放的是內核文件的根分區
- menu.lis:是grub.conf的鏈接文件,但是這個名字我覺得更與它的功能接近,就是菜單列表。裏賣弄設置了可以選擇的內核菜單。存放於stage2中。
- stage:用於grub引導程序過大,所以分2段引導,第一段存放在MBR中,第二段存放於內核文件系統中,第一段引導完成後可以找到第二段。 但是,第二段是存放於內核文件系統中的,此時還沒有格式化文件系統,如何可以訪問到第二段的 menu.lst 呢??就需要藉助於中間層 stage1_5,有它來協助 stage1 段來訪問 stage2 段。stage1_5通常位於 stage1 字段後的 63 個扇區。 由於stage2 在內存中存放可以使用的文件系統不確定,所以這就是有多個 stage1_5 的原因了。
2、grub.conf 文件參數意義
- default=1 # 默認啓動的內核title, 0 表示是第一個
- timeout=5 # 默認等待時間
- splashimage=(hd0,0)/grub/splash.xpm.gz # 指定菜單的背景圖片的路徑。爲xpm格式,採用gzip壓縮,只能爲14bits色
- hiddenmenu # 隱藏菜單
- title CentOS (2.6.32-358.el6.x86_64) # 標題名,用戶可自定義
- root (hd0,0) # 指定 grub 的根位置
- # 指定 kernel 文件的位置,還要指出 root(系統啓動後) 的位置,掛載方式 ro,這項很關鍵。
- # 加載後會啓動 init 進程。
- kernel /vmlinuz-2.6.32-358.el6.x86_64 ro root=/dev/mapper/vg0-root rd_NO_LUKS rd_NO_DM LANG=en_US.UTF-8 rd_LVM_LV=vg0/swap rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg0/root KEYBOARDTYPE=pc KEYTABLE=us rhgb crashkernel=auto quiet rhgb quiet
- # 在內核啓動過程中裝載根文件系統時有用
- initrd /initramfs-2.6.32-358.el6.x86_64.img
- # initramfs 是以 gzip 壓縮的 cpio 格式的文件。內核啓動時將他作爲一個臨時的根文件系統。
- # grub 的 stage2 將initrd加載到內存裏,讓後將其中的內容釋放到內容中,
- # 內核便去執行init腳本,這時內核將控制權交給了init文件處理。
- # init 它也主要是加載各種存儲介質相關的設備驅動程序。當所需的驅動程序加載完後,
- # 會創建一個根設備,然後將根文件系統rootfs以只讀的方式掛載。
- # 這一步結束後,釋放未使用的內存,轉換到真正的根文件系統上面去,同時運行/sbin/init程序,
- # 執行系統的1號進程。此後系統的控制權就全權交給/sbin/init進程了。
如何製作 initramfs 呢?
- # 可以使用 dircut 命令,用法如下:
- # 只有在 initramfs 文件損毀的時候會使用到
- [root@server ~]# dracut /mnt/initramfs-`uname -r`.img `uname -r`
- [root@server ~]# du -sh /mnt/initramfs-2.6.32-358.el6.x86_64.img
- 16M /mnt/initramfs-2.6.32-358.el6.x86_64.img
- [root@server ~]# du -sh /boot/initramfs-2.6.32-358.el6.x86_64.img
- 16M /boot/initramfs-2.6.32-358.el6.x86_64.img
- # 詳細介紹,可使用這個鏈接:https://zh.opensuse.org/index.php?title=SDB:Dracut&variant=zh-cn#.E5.90.AF.E7.94.A8_dracut_.E7.94.9F.E6.88.90.E7.9A.84_initramfs
3、grub的功能
1)提供菜單,並提供交互式接口
e: 進入編輯模式
2)選擇要啓動的內核或系統
允許傳遞引導參數給內核
選擇界面可隱藏
- # 可以自啓動是通過 grub 像內核傳遞參數。
- # 應用之一是:修改 root 密碼(忘記密碼),使用 e 選項,傳遞單用戶指令。
3)爲編輯功能提供保護機制
啓用內核文件
選擇運行指定的內核得先輸入密碼
傳遞參數
使用e命令得先輸入密碼
- [root@server root]# grub-md5-crypt
- Password:
- Retype password:
- $1$Mp7Rp1$l2wzOILNUqpUhAR7zXvQb0
- # 上面是生成的加密字符串
- # 然後將信息加入到 grub.conf 文件中,格式如下:
- password --md5 $1$Mp7Rp1$l2wzOILNUqpUhAR7zXvQb0
- # 當然加入 grub.conf 文件的位置不同,加密效果也不一樣。
- # 加入到 title 之前的話,會加密整個菜單。
- # 加入到 title 指內的話,會加密對應的操作系統的入口。
4、安裝grub的方式
1)使用grub-install命令
- # grub-install [--root-directory=/path/to/somewhere] DEVICE
2)grub交互是命令
在這裏我們自制一個精簡grub,當然啓動的時候只啓動一個bash就可以。示例是在 VMware 虛擬機下完成的。
第一步:準備好塊新磁盤,分 2 個區出來
第二步:模擬啓動時的boot目錄,和根目錄,並掛載。如下
- [root@server ~]# df -H | tail -n 2
- /dev/sdd1 518M 11M 481M 3% /mnt/boot
- /dev/sdd2 2.2G 71M 2.0G 4% /mnt/sysroot
第三步:製作 grub,並生成 grub 的配置文件
製作grub
拷貝內核文件和 initramfs 文件到 /mnt/boot 目錄下,並生成 grub.conf 文件
- [root@server ~]# cp /boot/vmlinuz-2.6.32-358.el6.x86_64 /mnt/boot/vmlinuz
- [root@server ~]# cp /boot/initramfs-2.6.32-358.el6.x86_64.img /mnt/boot/initramfs.img
- [root@server ~]# ll /mnt/boot/
- total 20106
- drwxr-xr-x 2 root root 1024 Jul 24 20:58 grub
- -rw-r--r-- 1 root root 16542269 Jul 24 21:06 initramfs.img
- -rwxr-xr-x 1 root root 4043888 Jul 24 21:05 vmlinuz
- # 生成的 grub.conf 文件
- [root@server ~]# cat /mnt/boot/grub/grub.conf
- default=0
- timeout=10
- title Mini Linux
- root (hd0,0)
- kernel /vmlinuz ro root=/dev/sda2 selinux=0 init=/bin/bash
- initrd /initramfs.img
第四步: 生成根文件系統
第五步:拷貝使用命令和庫到對應根目錄下
將剛纔的磁盤鏡像作爲另一個虛擬機的啓動盤。
五、啓動 init 進程
init 進程是系統啓動的第一個進程。其他進程都是有此進程控制fork出來的,也就是說,init是其他進程的“祖先”,PID=1。當然,PID=0進程我們稱爲空閒進程是屬於內核的。
init啓動後所做的事情:
1、讀取/etc/inittab來讀取默認級別 假設:讀取到的默認級別是 3
/etc/init/*.conf
- # 啓動級別:(runlevel)
- # 0:關機
- # 1:單用戶模式
- # 2:多用戶模式,不支持 NFS 功能
- # 3:完全多用戶模式,支持文本接口
- # 4:預留模式
- # 5:完全多用戶模式,支持圖形模式
- # 6:關機
- # /etc/inittab文件格式如下,這是遵循了CentOS5的風格。
- id:3:initdefault:
2、執行初始化系統腳本 /etc/rc.d/rc.sysinit 來初始化腳本
這個大家有機會可以讀讀,腳本主要的作用如下:
- # 獲取網絡環境與主機類型。首先會讀取網絡環境設置文件"/etc/sysconfig/network",獲取主機名稱與默認網關等網絡環境。
- # 答應文本歡迎信息。
- # 掛載/etc/fstab文件中定義的其它文件系統。
- # 激活swap
- # 檢測根文件系統,並以讀寫方式重新掛載
- # 決定是否啓動SELinux和udev。
- # 接口設備的檢測與即插即用(pnp)參數的測試。
- # 用戶自定義模塊的加載。用戶可以再"/etc/sysconfig/modules/*.modules"加入自定義的模塊,此時會加載到系統中。
- # 加載核心的相關設置。按"/etc/sysctl.conf"這個文件的設置值配置功能。
- # 設置系統時間(clock)。
- # 設置終端的控制檯的字形。
- # 設置raid及LVM等硬盤功能。
- # 以方式查看檢驗磁盤文件系統。
- # 進行磁盤配額quota的轉換。
- # 重新以讀取模式載入系統磁盤。
- # 啓動quota功能。
- # 啓動系統隨機數設備(產生隨機數功能)。
- # 清楚啓動過程中的臨時文件。
- # 將啓動信息加載到"/var/log/dmesg"文件中。
3、然後執行 /etc/rc.d/rc 腳本
此腳本運行的時候此腳本的時候,會讀取/etc/rc.d/rc3.d/下的所有腳本,來控制系統啓動的時候啓動或者關閉那些服務
- # 這裏面的腳本大致分爲 2 類,以 S 開頭的和以 K 開頭的腳本。
- # S 代表開機時啓動的,K 表示開機時不啓動。
- # 每個文件的命名格式,例如:S01sysstat S 開機啓動 01 啓動次序 sysstat 啓動腳本名
- # 啓動的定義是在每個腳本中定義的:例如
- # # chkconfig: - 85 15
- # 默認級別 啓動次序 不啓動次序
這些腳本是否開機自啓動,可由 chkconfig 命令來管理。
- # 常用選項:
- # chkconfig --add SRV_SCRIPT 可以將自己寫的一些腳本,讓此命令統一管理。例如:chkconfig --add httpd
- # chkconfig --del SRV_SCRIPT 將服務刪除,意思就是服務不由chkconfig這種機制來管理
- # chkconfig SRV_SCRIPT {on|off} 設置服務開機是否自啓動,默認管理的級別是2345.
- # --level 2345 等,指定默認級別,可以與其他選項一起使用
4、執行/etc/rc.d/rc.local腳本,此腳本是啓動過程中最後啓動的一個腳本。
最後會執行 /bin/login 登錄用戶。至此係統啓動過程完成。