1、瞭解分區
在路由器的flash上時有分區的。
openwrt首次刷機完成後,再過一段時間會有以下提示
jffs2: notice: (246) jffs2_build_xattr_subsystem: complete building xattr subsystem, 1 of xdatum (0 unchecked, 0 orphan) and 9 of xref (0 dead, 2 orphan) found.
block: extroot: no root or overlay mount defined
這段話的意思是,使用jfffs2文件系統完成了格式化。
不用管上面話的意思,先說說分區。
在linux系統中對閃存類存儲器是採用MTD(內存技術設備)類設備驅動實現的,MTD是用於訪問閃存類設備(ROM,FLASH)的linux驅動子系統。它的主要目的是使Flash閃存類設備更加容易的被訪問,爲此它在硬件和上層提供了一個抽象的接口使得在操作系統下我們可以像操作硬盤一樣操作這類設備。仔細觀察過linux啓動信息的朋友會看到以下一段話。
[ 1.556000] Creating 5 MTD partitions on "raspi":
[ 1.564000] 0x000000000000-0x000001000000 : "ALL"
[ 1.576000] 0x000000000000-0x000000030000 : "Bootloader"
[ 1.588000] 0x000000030000-0x000000040000 : "Config"
[ 1.600000] 0x000000040000-0x000000050000 : "Factory"
[ 1.612000] 0x000000050000-0x000001000000 : "firmware"
[ 1.624000] 0x0000001853f2-0x000001000000 : "rootfs"
[ 1.632000] mtd: partition "rootfs" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only
[ 1.660000] mtd: partition "rootfs_data" created automatically, ofs=0x670000, len=0x990000
這段話的意思是,系統在SPI(SPI是我們所使用的flash接口標準,路由器一般都用它)設備上創建了是4個分區,這幾個分區的說明如表所示
分區id號 | 分區位置 | 分區大小 | 分區作用 |
Bootloader | 0x000000000000-0x000000030000 | 192KB | 引導程序 |
Config | 0x000000030000-0x000000040000 | 64KB | 引導程序配置 |
Factory | 0x000000040000-0x000000050000 | 64KB | MT7628初始參數 |
firmware | 0x000000050000-0x000001000000 | 15.68MB | 固件分區 |
rootfs | 0x0000001853f2-0x000001000000 | 14827KB | 固件分區 文件系統子集 |
rootfs_data | 0x000000670000-0x000001000000 | 9792KB | 固件分區 文件系統子集 可寫分區子集 |
由於嵌入式的Flash容量很小,沒有調整的必要,所以分區都是固定的,也因此不需要"分區表"這種在計算機上有的東西。在路由器的flash中,分區的位置都是固化好的。
MTK7628配置的flash是16MB的,分區如圖所示
(1) 分區存在子分區,比如kernel和rootfs就是firmware的子分區。而rootfs_rom,rootfs_data就是rootfs的子分區。
(2)整個分區從0x000000000000開始到0x000001000000結束。
(3)kernel分區的容量計算公式如下,firmware大小減去rootfs大小。
2、查看系統MTD分配
root@OpenWrt:/# cat /proc/mtd
dev: size erasesize name
mtd0: 01000000 00010000 "ALL"
mtd1: 00030000 00010000 "Bootloader"
mtd2: 00010000 00010000 "Config"
mtd3: 00010000 00010000 "Factory"
mtd4: 00fb0000 00010000 "firmware"
mtd5: 00e7ac0e 00010000 "rootfs"
mtd6: 00990000 00010000 "rootfs_data"
3、查看系統mtd的分區
root@OpenWrt:/# cat /proc/partitions
major minor #blocks name
31 0 16384 mtdblock0
31 1 192 mtdblock1
31 2 64 mtdblock2
31 3 64 mtdblock3
31 4 16064 mtdblock4
31 5 14827 mtdblock5
31 6 9792 mtdblock6
4、將非文件系統分區讀出來
hexdump -C /dev/mtd2 或者使用dd命令 dd if=/dev/mtd2 of=/tmp/mtd2
5、文件系統
下面開始深入的瞭解文件系統與上面分區 的關係,系統有rootfs_rom這個隱藏的只讀文件系統,也有rootfs_data這個可寫的文件分區,它們之間是什麼關係?這是Openwrt設計的一個有意思的地方。
①首先,引導程序啓動內核完成之後,由內核加載rootfs_rom只讀分區部分來完成系統的初步啓動。
②rootfs_rom只讀分區採用的是linux內核支持的squashFS文件系統(一種只讀文件系統),加載完畢後將其掛在到/rom目錄(同時也掛載爲/根目錄)
③系統將使用JFFS2文件系統格式化的rootfs_data可寫文件分區並且將這部分掛載到/overlay目錄。
④系統再將/overlay 透明掛載爲/根目錄
⑤最後將一部分內存掛載爲/tmp目錄
⑥掛載情況如下
root@OpenWrt:/# df
Filesystem 1K-blocks Used Available Use% Mounted on
rootfs 9792 408 9384 4% /
/dev/root 5120 5120 0 100% /rom
tmpfs 63108 92 63016 0% /tmp
/dev/mtdblock6 9792 408 9384 4% /overlay
overlayfs:/overlay 9792 408 9384 4% /
tmpfs 512 0 512 0% /dev
6、透明掛載根目錄
OpenWRT設計的一個特點是:系統先將rootfs_rom掛載爲/根目錄,這樣具備了一個完整的系統,然後再將rootfs_data以透明方式掛載在/根目錄上。Openwrt透明掛載處理流程如圖所示,這樣重疊之後的效果是:
①我們所看到的根文件系統是由rootfs_rom和rootfs_data兩個分區組合在一起的;
②當我們修改一個任何位置的文件的時候,所做的修改在rootfs_data裏會有記錄。
③當我們刪除一個文件的時候,所做的修改在rootfs_data裏會有記錄。
④當我們增加一個文件的時候,所做的修改在rootfs_data裏會有記錄。
⑤當我們讀取文件的時候,首先檢測rootfs_data裏的狀態,再檢測rootfs_rom裏的內容,一直到最後給你一個結果。
這樣做的好處和壞處爲:
①當對文件進行操作的時候,比如我們修改了一個名字爲abc的文件,那麼同時存在/rom裏面還有修改之前的abc,同時在/overlay裏面修改之後的abc,所佔的空間是倍增的。
②系統不論任何時候,只要通過簡單的刪除掉/overlay裏所有文件,就能達到復原的效果。
overlay文件系統解析
一個 overlay 文件系統包含兩個文件系統,一個 upper 文件系統和一個 lower 文件系統,是一種新型的聯合文件系統。overlay是“覆蓋…上面”的意思,overlay文件系統則表示一個文件系統覆蓋在另一個文件系統上面。
爲了更好的展示 overlay 文件系統的原理,現新構建一個overlay文件系統。文件樹結構如下:
1、在一個支持 overlay文件系統的 Linux (內核3.18以上)的操作系統上一個同級目錄內(如/root下)創建四個文件目錄 lower 、upper 、merged 、work其中 lower 和 upper 文件夾的內容如上圖所示,merged 和work 爲空,same文件名相同,內容不同。
2、在/root目錄下執行如下掛載命令,可以看到空的merged文件夾裏已經包含了 lower 及 upper 文件夾中的所有文件及目錄。
$mount -t overlay overlay -olowerdir=./lower,upperdir=./upper,workdir=./work ./merged
3、使用df –h 命令可以看到新構建的 overlay 文件系統已掛載。
Filesystem Size Used Avail Use% Mounted on
overlay 20G 13G 7.8G 62% /root /merged
那麼 lower 和 upper 目錄裏有相同的文件夾及相同的文件,合併到 merged 目錄裏時顯示的是哪個呢?規則如下:
1. 文件名及目錄不相同,則 lower 及 upper 目錄中的文件及目錄按原結構都融入到 merged 目錄中;
2. 文件名相同,只顯示 upper 層的文件。如上圖在 lower 和 upper 目錄下及下層目錄 dir_A 下都有 same.txt 文件,但在合併到 merged 目錄時,則只顯示 upper 的,而 lower 的隱藏 ;
3. 目錄名相同, 對目錄進行合併成一個目錄。如上圖在 lower 及 upper 目錄下都有 dir_A 目錄,將目錄及目錄下的所有文件合併到 merged 的 dir_A 目錄,目錄內如有文件名相同,則同樣只顯示 upper 的,如上圖中 dir_A 目錄下的same.txt文件。
overlay只支持兩層,upper文件系統通常是可寫的;lower文件系統則是隻讀,這就表示着,當我們對 overlay 文件系統做任何的變更,都只會修改 upper 文件系統中的文件。那下面看一下overlay文件系統的讀,寫,刪除操作。
讀
¬ 讀 upper 沒有而 lower 有的文件時,需從 lower 讀;
¬ 讀只在 upper 有的文件時,則直接從 upper 讀
¬ 讀 lower 和 upper 都有的文件時,則直接從 upper 讀。
寫
¬ 對只在 upper 有的文件時,則直接在 upper 寫
¬ 對在lower 和 upper 都有的文件時,則直接在 upper 寫。
¬ 對只在 lower 有的文件寫時,則會做一個copy_up 的操作,先從 lower將文件拷貝一份到upper,同時爲文件創建一個硬鏈接。此時可以看到 upper 目錄下生成了兩個新文件,寫的操作只對從lower 複製到 upper 的文件生效,而 lower 還是原文件。
刪
¬ 刪除 lower 和 upper 都有的文件時,upper 的會被刪除,在 upper 目錄下創建一個 ‘without' 文件,而 lower 的不會被刪除。
¬ 刪除 lower 有而 upper 沒有的文件時,會爲被刪除的文件在 upper 目錄下創建一個 ‘without' 文件,而 lower 的不會被刪除。
¬ 刪除 lower 和 upper 都有的目錄時,upper 的會被刪除,在 upper 目錄下創建一個類似‘without' 文件的 ‘opaque' 目錄,而 lower 的不會被刪除。
可以看到,因爲 lower 是隻讀,所以無論對 lower 上的文件和目錄做任何的操作都不會對 lower 做變更。所有的操作都是對在 upper 做, 。
copy_up只在第一次寫時對文件做copy_up操作,後面的操作都不再需要做copy_up,都只操作這個文件,特別適合大文件的場景。overlay的 copy_up操作要比AUFS相同的操作要快,因爲AUFS有很多層,在穿過很多層時可能會有延遲,而overlay 只有兩層。而且overlay在2014年併入linux kernel mailline ,但是aufs並沒有被併入linux kernel mailline ,所以overlay 可能會比AUFS快。
lower文件系統可以爲任何linux支持的文件系統,甚至可以爲另一個overlayfs。因爲雖然overlay文件系統的底層是由兩個文件系統構成,但它本身只是一個文件系統,就如前面用df命令看到的,所以也可以和其他文件系統組成新的overlay文件系統。而upper是可寫的,不支持NFS。多層 lower 可執行如下命令:
$mount -t overlay overlay -olowerdir=/lower1:/lower2:/lower3 ,upperdir=./upper,workdir=./work ./merged
上例中,lower 是由三個文件系統合併成一個文件系統,其中lower1在最上面,lower3在最底下。
Docker一直在用AUFS(高級多層次統一文件系統)作爲容器的文件系統。AUFS是一個能透明覆蓋一或多個現有文件系統的層狀文件系統。當一個進程需要修改一個文件時,AUFS創建該文件的一個副本。AUFS可以把多層合併成文件系統的單層表示。Docker 的image構採用的是AUFS,每個新版本都是一個與之前版本的簡單差異改動,有效地保持鏡像文件最小化。那docker 使用 overlay 之後有什麼區別呢?
首先鏡像在下載時每一層的鏡像都有一個自己的鏡像ID,每個鏡像都會有自己的目錄,保存在/var/lib/docker/overlay目錄下,但是這些層目錄的名字並不是下載鏡像時的ID名稱。我們都知道AUFS是多層,那如何體現爲兩層呢?啓動一個容器後,也在這個目錄下產生一個層目錄,進入到目錄可以看到有三個文件夾,分別是merged,upper,work,和一個文件lower-id,而在lower-id中保存的就是鏡像最上層的ID,所以對容器來說,還是一個兩層的文件系統。
這裏說明一下,docker pull image時顯示的鏡像ID名稱與/var/lib/docker/overlay目錄下的鏡像目錄名稱不一樣。鏡像目錄中保存的是這層獨有的文件和硬鏈接下層共享的文件。這樣可以更有效的利用磁盤資源。
從上面這個圖可以看到,overlay的兩層對應的就是docker的鏡像層(只讀)和容器層(可寫),只是把原來AUFS中的多層鏡像合併成了lower層,而upper層代表的是容器層。
我們看到雖然overlay和AUFS都是聯合文件系統,但結構比AUFS簡單,且併入了linux kernel mainline,可能會比AUFS快,但還是太年輕,要謹慎在生產使用。而AUFS做爲docker的第一個存儲驅動,已經有很長的歷史,比較的穩定,且在大量的生產中實踐過,有較強的社區支持。
轉載自:http://dockone.io/article/1511 ,https://blog.csdn.net/caofengtao1314/article/details/81182645?from=timeline