在使用嵌入式?Linux?系统的时,会出现由于设备意外断电引起文件系统损坏而最终使该设备无法启动的现象。为了应对这种情况,通常会从硬件设计如采用备用电源,无论是锂电池还是超级电容等,或者从系统软件设上加以规避。本文接下来将介绍如何使用?squashfs?只读文件系统制作?Linux?系统文件,并采用?overlayfs?为用户目录增加可写权限。演示采用?Colibri iMX6?计算机模块,该方法同样也适用于?Toradex?其他产品,如?iMX8?计算机模块。
Squashfs?是一种只读压缩文件系统,通常被用于数据备份或者系统资源受限的计算机系统上使用,如?Linux?发行版的?LiveCD,OpenWRT?系统也采用?squashfs。OverlayFS?一个结合其他文件系统的联合挂载,将多个挂载点叠加为一个目录。常见的应用是在一个只读的分区上叠加可读写的另一个分区。嵌入式?Linux?设备通常的功能都是被设计好的,极少需要在后期安装其他软件或更改?Linux?系统软件,更多的是更新设备应用程序和相关数据。因此基于?squashfs?的只读文件系统,结合?overlayfs?为用户应用和数据提供读写操作,能够提高嵌入式?Linux?文件系统可靠性。
在?Colibri iMX6?的?eMMC?上我们将使用以下分区规划。BootFS?为?FAT32?格式,该分区上包含?Linux?内核文件,device tree?等启动文件,如果是?iMX8,则还包含一些其他固件文件。该分区通常只在文件系统烧写阶段被写入。RootFS?分区是?Linux?运行的文件系统,usr, bin, lib, etc, home?等目录都在上面。一般该分区是EXT3,EXT4?格式,支持文件的写入和删除。而文件系统的损坏也常发生于此,最终导致设备启动失败。因此我们这里会采用只读格式的?squashfs?。UserData?是能够读写的?EXT4?分区。该分区通过?overlayfs?会被挂载到原本位于只读?squashfs??中的?/home/root?目录。用户应用可以毫无察觉得使用该目录,在上面写入和删除文件,但不破坏只读?squashfs?文件系统,所有的操作都会被转移到?UserData?分区上。用户的应用也会存在?UserData?分区上,启动的时候从这里加载应用程序。该分区是可写的,所有这上面的文件是可以被更新。
下面我们会具体说明如何在?Yocto?环境生成符合上面规划的?BSP?,并通过?Toradex Easy Installer?工具实现这些分区和写入文件。
首先需要在?Yocto?环境中生成?squashfs?格式的系统文件?rootfs。修改?build/conf/local.conf?,结尾添加以下内容。
------------------------------------
IMAGE_FSTYPES_append = " squashfs"
------------------------------------
默认?Linux?内核配置下?squahfs?是通过加载内核驱动模块实现对其支持,而模块驱动文件位于?rootfs?中,为了保证?Linux?内核在启动时能够正确处理该格式,需要将?squahfs?内核驱动模块配置为静态驱动,直接编译进内核中。为内核配置的文件系统支持添加?squahfs?和?overlay?格式。
------------------------------------
$ MACHINE=colibri-imx6 bitbake -c menuconfig virtual/kernel
→?File systems
<*> Overlay filesystem support
→?File systems?→?Miscellaneous filesystems
<*>?? SquashFS 4.0 - Squashed file system support?
------------------------------------
EXT4?格式的?UserData?分区会通过?overlay?机制挂载到只读的?rootfs?上的?/home/root,但这之前需要通过?fstab?将该分区挂载到系统中,/dev/mmcblk0p3 -> /media/data-> /home/root。在?Yocto?中,layers/meta-toradex-demos/recipes-core/base-files/base-files/fstab?会被编译到?Colibri IMX6 BSP?中,在该文件中添加:
------------------------------------
/dev/mmcblk0p3?????? /media/data???????? auto?????? defaults,sync,noauto? 0? 0
------------------------------------
然后再添加一个开机自启动脚本,将??/media/data?使用?overlay挂载到?/home/root。?在?layers/meta-toradex-bsp-common/recipes-core目录中添加?mount-overlayfs?文件夹,里面包含编译需要的?bb?文件和?systemd service。mount-overlayfs.bb?中?install -d ${D}/media/data?会在?/media?目录中创建?data?文件夹,FILES_${PN} = "/media/data"?将该空文件夹添加到?BSP?中。?mount-overlayfs.service?通过?RequiresMountsFor?保证?/media/data?目录通过?fstab?挂载后才运行。Overlay?的目录结构如下,lowerdir?为/home/root upperdir?为?/media/data/home/root/upper,workdir?为?/media/data/home/root/work。这样应用可以在?/home/root?下直接读写文件,overlayfs?对应用和用户都是透明的。
------------------------------------
[Service]
Type=simple
ExecStart=/bin/sh -c 'mount -t overlay -o lowerdir=/home/root,upperdir=/media/data/home/root/upper,workdir=/media/data/home/root/work overlay /home/root'
------------------------------------
在?build/conf/local.conf?中将?mount-overlayfs?添加到?BSP?中。
------------------------------------
IMAGE_INSTALL_append = " mount-overlayfs"
------------------------------------
由于?rootfs?是只读格式,无法像之前一样直接在开发板上运行?systemctl?命令添加开机自启动脚本。我们需要像上面一样,在?Yocto?中增加一个?test-app?来开机自动运行位于?UserData?分区(该分区通过?overlay?会被最终挂载到?/home/root?目录)上的测试程序?test。在?layers/meta-toradex-bsp-common/recipes-core目录中添加?test-app?文件夹,里面包含编译需要的?bb?文件和?systemd service。
在?build/conf/local.conf?中将?test-app?添加到?BSP?中。
------------------------------------
IMAGE_INSTALL_append = " mount-overlayfs test-app"
------------------------------------
至此我们已经通过修改?Yocto?能够生成所需结构的BSP,执行下面命令完成编译任务。
------------------------------------
$ MACHINE=colibri-imx6 bitbake tdx-reference-minimal-image
------------------------------------
在?build/deploy/images/colibri-imx6?有相关文件生成,我们需要下面两个文件,文件名字中的时间戳对应具体编译的日期。
Colibri-iMX6_Reference-Minimal-Image-Tezi_5.1.0-devel-20201112022057+build.0.tar
Colibri-iMX6_Reference-Minimal-Image.rootfs.squashfs
解压?Colibri-iMX6_Reference-Minimal-Image-Tezi_5.1.0-devel-20201112022057+build.0.tar。因为rootfs?是?squahfs?格式,需要使用定制的?boot.src?来启动。
------------------------------------
$ cd ~/
$ tar vxf Colibri-iMX6_Reference-Minimal-Image-Tezi_5.1.0-devel-20201112022057+build.0.tar
$ cd Colibri-iMX6_Reference-Minimal-Image-Tezi_5.1.0-devel-20201112022057+build.0
$ tar vxf Reference-Minimal-Image-colibri-imx6.bootfs.tar.xz
------------------------------------
修改其中的?emmcargs_set?参数。
------------------------------------
env set emmcargs_set 'env set rootfsargs root=/dev/mmcblk0p2 rootfstype=squashfs ro rootwait'
------------------------------------
可以使用该?boot.cmd?直接生成对应的?boot.src,?替换解压目录中同名文件,?重新打包?Reference-Minimal-Image-colibri-imx6.bootfs.tar.xz
------------------------------------
$ cd Reference-Minimal-Image-colibri-imx6.bootfs
$ rm boot.src
$ mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "Distro boot script" -d boot.cmd boot.scr
$ cd ..
$ tar cJf Reference-Minimal-Image-colibri-imx6.bootfs.tar.xz -C Reference-Minimal-Image-colibri-imx6.bootfs .
------------------------------------
将?squashfs?的?rootfs?文件系统复制到?Colibri-iMX6_Reference-Minimal-Image-Tezi_5.1.0-devel-20201112022057+build.0?目录中。
------------------------------------
$ cp Colibri-iMX6_Reference-Minimal-Image.rootfs.squashfs Colibri-iMX6_Reference-Minimal-Image-Tezi_5.1.0-devel-20201112022057+build.0
------------------------------------
接下来创建需要复制到?UserData?分区中的文件。如上面提到的?overlay?挂载需要有对应目录结构,依次创建以下目录,并将测试程序?test?复制到?upper?目录中。这里的测试程序?test?是一个非常简单的?C?应用,它会输出“Hello Toradex!”到系统日志中。
------------------------------------
$ cd ~/Colibri-iMX6_Reference-Minimal-Image-Tezi_5.1.0-devel-20201112022057+build.0
$ mkdir rootfs
$ cd rootfs
$ mkdir -p home/root/upper
$ mkdir -p home/root/work
$ cp ~/test home/root/upper
$ tree
------------------------------------
打包为?rootfs.tar.xz。
------------------------------------
$ cd ..
$ sudo tar cJf rootfs.tar.xz -C rootfs .
------------------------------------
修改?image.json?文件,在blockdevs?中增加?RAW?格式分区用于直接写入?squashfs?系统文件,以及?EXT4?格式的DATA分区用于写入上面生成的?rootfs.tar.xz。
Colibri-iMX6_Reference-Minimal-Image-Tezi_5.1.0-devel-20201112022057+build.0?目录下最终包含以下文件。
将上面的?BSP?通过?Toradex Easy Installer?重新安装到?Colibri iMX6?上,安装的时候注意需要点击?Erase?擦除?eMMC?上的内容。
烧写后重启模块。可以通过?mount?命令查看挂载分区的情况。
------------------------------------
root@colibri-imx6:~# mount
/dev/mmcblk0p2 on / type squashfs (ro,noatime)
……
/dev/mmcblk0p3 on /media/data type ext4 (rw,relatime,sync)
overlay on /home/root type overlay (rw,relatime,lowerdir=/home/root,upperdir=/media/data/home/root/upper,workdir=/media/data/home/root/work)
------------------------------------
mmcblk0p2?为写入?squashfs?只读文件系统的分区,例如在?/etc?目录无法创建文件。
------------------------------------
root@colibri-imx6:/etc# mkdir test-folder
mkdir: can't create directory 'test-folder': Read-only file system
------------------------------------
EXT4?格式的?/dev/mmcblk0p3?分区上是用户文件,被挂载到?/media/data。而?/home/root?会通过?overlay?具有可读写权限。
------------------------------------
root@colibri-imx6:~# cd ~/
root@colibri-imx6:~# pwd
/home/root
root@colibri-imx6:~# mkdir test-folder
root@colibri-imx6:~# ls
test???????? test-folder
root@colibri-imx6:~# ls -lh
-rwxrwxr-x??? 1 1000???? 1000?????? 11.3K Nov 11? 2020 test
drwxr-xr-x??? 2 root???? root??????? 4.0K Feb? 7 16:25 test-folder
------------------------------------
位于?UserData?上的测试程序?test??也在开机的时候自动运行。
------------------------------------
root@colibri-imx6:~# journalctl -u test-app
-- Logs begin at Fri 2020-02-07 15:50:53 UTC, end at Fri 2020-02-07 16:11:49 UTC. --
Feb 07 15:50:57 colibri-imx6 systemd[1]: Started start a demo on overlay mount folder.
Feb 07 15:50:57 colibri-imx6 test[456]: Hello Toradex!
Feb 07 15:50:57 colibri-imx6 systemd[1]: test-app.service: Succeeded.
------------------------------------
总结
上面我们演示结合使用?squashfs?和?overlay,将系统文件放在一个只读分区,把读写操作在单独的分区上进行。降低系统文件因意外断电受损从而导致无法启动的风险。在使用只读?squashfs?只读文件系统时需要保证?rootfs?尽量精简,建议在?Reference-Minimal-Image?基础上构建用户自己的?BSP,甚至对其进行裁剪。
审核编辑:黄飞
评论