bootup - 系統啟動流程
在系統啟動過程中要涉及多個不同的元件。
按下電源按鈕後,首先BIOS/UEFI做最基本的硬體自檢與初始化,
然後載入預設/手動選擇的磁碟/網路上的引導載入器(例如GRUB2),
引導載入器進一步從磁碟/網路上載入作業系統核心(例如Linux)。
對於Linux來說,核心將會(可選的)解壓一個initrd(initial
RAM disk)映象(可以用
dracut(8)
之類的工具生成),
並執行由"rdinit="核心引導選項指定的init程式(例如
systemd(1))
以尋找並掛載根檔案系統。
完成根檔案系統的掛載之後,核心啟動由"init="核心引導選項指定的init程式(例如
systemd(1))
以接管系統的控制權。
該init程式將會負責檢測所有其他的硬體裝置、掛載必要的檔案系統、啟動所有必要的服務,等等。
關機時,
init程式將會停止所有服務、
解除安裝所有檔案系統、
(可選的)返回initrd環境解除安裝根檔案系統,
最後關閉電源。
其他有關係統啟動流程的資訊可以參考
boot(7) 手冊。
當成功掛載了"root="核心引導選項指定的根檔案系統之後,核心將啟動由"init="核心引導選項指定的init程式,
從這個時間點開始,即進入了"常規啟動流程":
檢測硬體裝置並載入驅動、掛載必要的檔案系統、啟動所有必要的服務,等等。對於
systemd(1)
系統來說,上述"init程式"就是
systemd 程序,
而整個"常規啟動流程"也以幾個特殊的
target 單元(詳見
systemd.target(5))
作為節點,被劃分為幾個階段性步驟。
在每個階段性步驟內部,任務是高度並行的,
所以無法準確預測同一階段內單元的先後順序,
但是不同階段之間的先後順序總是固定的。
當啟動系統時, systemd
將會以 default.target
為啟動目標,
藉助單元之間環環相扣的依賴關係,即可完成"常規啟動流程"。
default.target
通常只是一個指向
graphical.target(圖形介面) 或
multi-user.target(文字控制檯)
的軟連線。
為了強制啟動流程的規範性以及提高單元的並行性,
預先定義了一些具有特定含義的
target 單元。詳見
systemd.special(7)
手冊。
下面的圖表解釋了
這些具有特定含義的
target
單元之間的依賴關係
以及各自在啟動流程中的位置。
圖中的箭頭表示了單元之間的依賴關係與先後順序,
整個圖表按照自上而下的時間順序執行。
local-fs-pre.target
|
v
(各個 mounts 與 (各個 swap (各個加密塊裝置
fsck services...) devices...) devices...) (各個底層服務: (各個底層虛擬
| | | udevd, tmpfiles, 檔案系統 mounts:
v v v random seed, mqueue, configfs,
local-fs.target swap.target cryptsetup.target sysctl, ...) debugfs, ...)
| | | | |
\__________________|_________________ | ___________________|____________________/
\|/
v
sysinit.target
|
____________________________________/|\________________________________________
/ | | | \
| | | | |
v v | v v
(各個 (各個 | (各個 rescue.service
timers...) paths...) | sockets...) |
| | | | v
v v | v rescue.target
timers.target paths.target | sockets.target
. | | |
. \_________________ | ___________________/
.................................... \|/
v
basic.target
|
____________________________________/| emergency.service
/ | | |
| | | v
v v v emergency.target
display- (圖形介面所必需 (各個系統服務)
manager.service 的各個系統服務) |
| | |
| | v
| | multi-user.target
| | |
\_________________ | _________________/
\|/
v
graphical.target
用
斜體標識的目標單元經常被用作啟動目標。
有兩種方法可以指定啟動目標:
(1)使用
systemd.unit=
核心引導選項(參見
systemd(1)); (2)使用 default.target
軟連線。
因為 timers.target
以非同步方式包含在
basic.target 中, 所以 timer
單元可以依賴於在 basic.target
之後才啟動的服務。
在initrd內部, 也可以將 systemd
用作init程式(由"rdinit="核心引導選項指定)。
此時 initrd.target
將是預設目標。
initrd內部啟動流程的上半部分與前一小節
basic.target
之前的部分完全相同。
隨後的啟動流程將以
initrd.target
為目標(如下圖所示)。
當根檔案系統裝置可用時,將到達
initd-root-device.target 目標。
如果成功的將根檔案系統掛載到
/sysroot 目錄,那麼 sysroot.mount
單元將被啟動,然後進一步到達
initrd-root-fs.target 目標。 initrd-parse-etc.service
將會分析 /sysroot/etc/fstab
檔案以掛載 /usr (若需要)
與帶有
x-initrd.mount
標記的掛載點。
所有這些掛載點都將被掛載到
/sysroot
之下,然後流程到達
initrd-fs.target 目標。再接下來
initrd-cleanup.service 將會使用
systemctl
--no-block isolate 命令啟動
initrd-switch-root.target 目標。 因為 isolate
表示立即停止所有在新的目標單元中不需要的程序,
所以此動作實際上是為接下來切換根目錄做預先的準備(也就是清理環境)。
最後,啟動 initrd-switch-root.service
服務,將系統的根目錄切換至
/sysroot 目錄。
(之前的流程與上一小節完全相同)
:
v
basic.target
| emergency.service
______________________/| |
/ | v
| initrd-root-device.target emergency.target
| |
| v
| sysroot.mount
| |
| v
| initrd-root-fs.target
| |
| v
v initrd-parse-etc.service
(各個自定義的 |
initrd services...) v
| (sysroot-usr.mount 以及
| fstab 中帶有 x-initrd.mount
| 標記的各個掛載點)
| |
| v
| initrd-fs.target
\______________________ |
\|
v
initrd.target
|
v
initrd-cleanup.service
(使用 isolates 啟動 initrd-switch-root.target)
|
v
______________________/|
/ v
| initrd-udevadm-cleanup-db.service
v |
(各個自定義的 |
initrd services...) |
\______________________ |
\|
v
initrd-switch-root.target
|
v
initrd-switch-root.service
|
v
切換到主機上的作業系統
systemd
系統在關機時同樣遵循固定的流程,
具體如下圖所示:
(與所有系統服務互斥) (與所有檔案系統 mounts, swaps, cryptsetup devices 互斥)
| |
v v
shutdown.target umount.target
| |
\____________________________________ ______/
\ /
v
(各個底層 services)
|
v
final.target
|
_____________________________________/ \_________________________________
/ | | \
| | | |
v v v v
systemd-reboot.service systemd-poweroff.service systemd-halt.service systemd-kexec.service
| | | |
v v v v
reboot.target poweroff.target halt.target kexec.target
用
斜體標識的目標單元經常被用作關機目標。
systemd(1),
boot(7),
systemd.special(7),
systemd.target(5),
dracut(8)
本頁面中文版由中文 man
手冊頁計劃提供。
翻譯人員:金步國
金步國作品集:
http://www.jinbuguo.com
中文 man 手冊頁計劃:
https://github.com/man-pages-zh/manpages-zh