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