作者簡介: 黃偉亮(Huang weller),畢業于蘇州大學,就職于蘇州博世汽車部件汽車多媒體事業部,從事汽車多媒體娛樂系統的平臺開發工作六年有余, 接觸Linux 系統近10年。感興趣的方向有Linux系統性能優化,多媒體框架, 文件系統和存儲器件, USB以及虛擬化等。
前言
我們的學習習慣基本都是由淺入深的, 比如我們先學習如何使用fdisk工具來給磁盤分區, 之后才想到去看看fdisk到底對磁盤做了什么, 許久以后看到除了fdisk還有別的分區工具可以給磁盤分區. 通常我們只需要知道怎么用就可以了, 也有很多原因促使我們去思考它的背后到底發生了什么,這些原因可能是你碰到了具體問題, 不得不讓你往下去看, 去看你認為肯定不會出問題的那一部分, 也有可能是你覺得現在的自己技術太浮于表面, 想深入一些, 也可能是受周圍人的影響, 一起學習.
佛家講究因果, 使用者往往接觸的是果, 因為使用者在乎的是可用性, 開發者或者說設計者則要考慮因, 因為什么樣的因就會導致什么樣的果, 因為這樣的設計, 所以就有那樣的bug, 就像黑客帝國中的Neo 要找到architecture!
本文由來于心中的兩個疑問,即平凡的存儲器件是怎么從分區變成一個個塊設備的, 根是怎么被mount的.
Romcode 說
通常,在processor上電后, 最早執行的代碼是固化在CPU ROM中的程序, 它其實就是最早被執行的bootloader, 它的終極目的是從存儲介質(包含uart, USB)加載另外一個bootloader, 比如u-boot. 拿啟動介質是eMMC或者SD的例子來說, romcode一般會從offset = sector_size * 1的位置開始讀取程序, 這么做的原因其實是為了跳開分區表.
當然筆者也見過一個奇葩的例子, 海思的一款ARM9的芯片, ROMCODE直接從eMMC data partition offset 0的位置開始讀取程序, 這就導致當你從emmc 上的u-boot啟動, 興沖沖的進到ramdisk對eMMC進行分區, 格式化, 燒寫系統之后, 發現系統再也起不來了, 那是因為分區表已經覆蓋了第一個分區,破壞了bootloader. 整個系統沒有使用分區工具來劃分分區, 而是通過u-boot的boot arguments描述分區信息. 不管怎樣, 本文描述的是前者,而非這個特例.
從分區表到塊設備: 我不是表, 我是塊設備
Linux 下Storage device 通常是作為塊設備被訪問的,例如mtdblock, mmcblock 和宇宙第一強的nandblk 塊設備(實在太崇拜該設備了,將NAND發揮到了極致). Storage device的設備驅動作為底層支撐, 負責注冊塊設備并且直接和存儲器件打交道, 接受, 執行和響應塊設備層的過來的訪問請求. 比如說, 一次文件讀取的操作會變成文件系統提交到塊設備的塊讀取請求, 該塊設備的讀訪問請求, 在塊設備驅動和Host controller driver會把它被轉化為MMC協議的CMD17或者CMD18指令給到EMMC物理設備.
Storage device的設備驅動注冊到塊設備層,并且掃描分區表, 識別分區表, 然后解析分區表, 把磁盤上的分區注冊為塊設備. 所以, 當你奇怪為什么沒有mmcblkp0這個設備時, 其實不是沒有mmcblk0p0,而是p0被定義為就是mmcblk0. 代表了整個磁盤. 下面從代碼上來看一下一個塊設備驅動的初始化過程:
根: 木葉的根
我們知道u-boot的boot argument 會把root device的設備名稱帶給內核, 例如通過參數root=/dev/mmcblk0p2來告知內核, 根目錄所在的分區. 事情真的那么簡單嗎?
原來這里面有一點點小彎彎:
原來在天地混沌的時候, 內核已經為了自己的未來初始化了一個ramfs, 并在ramfs中創建了一些必要的目錄和設備節點, 例如/dev , /dev/console, /root.
然后, 為了mount mmcblk0p2, 它又根據設備文件名/dev/mmcblk0p2查找設備變量, 在ramfs下創建設備節點/dev/root, 這個設備文件指向的就是設備mmcblk0p2. 然后把ramfs下的設備/dev/mmcblk0p2掛載到ramfs的/root下. 切換當前路徑到ramfs的/root下. 至此已經完成了設備mmcblk0p2的掛載工作, 但是此時它還不是根.
接著, 內核掛載devtmpfs到dev目錄, 然后調用sys_chroot(“.”)把change root 到當前路徑, 也就是ramfs的/root.
反映到代碼上:
因此在系統起來后, cat /proc/mounts, 我們可以看到以下信息:
可以看到有一個文件系統的類型是rootfs, 它被mount到了“/”.
這個文件系統在init/do_mount.c中被定義, 它就是ramfs的一個實例,
該類型的文件系統在init_rootfs()中被注冊.
從mount命令的輸出上, 我們可以看到/dev/mmcblk0p2被掛載在了”/”, 殊不知這里的根已經不是原來的根.
結束語
本文沒有對代碼的細節作過多的分析, 一方面本文不是為了做代碼分析的, 另一方面網絡上有很多朋友也做過塊設備的代碼分析, 本文羅列了代碼的脈絡是為了來更好的表達分析的結果. Block layer是個很復雜的子系統, 有很多關于它的內容,比如IO-schecduler, buffer cache等, 相信自己可以越來越深入的研究這個子系統.
-
Linux
+關注
關注
87文章
11232瀏覽量
208961
原文標題:黃偉亮: 探秘Linux的塊設備和根
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論