热度 1
2018-3-15 10:58
1455 次阅读|
0 个评论
ByToradex 胡珊逢 1. 简介 文件系统对于嵌入式系统,正如记忆对于大脑,嵌入式系统失去了文件系统,这往往是严重的问题,轻则导致应用无法启动,数据丢失,严重的情况可能是整个系统启动失败。 Windows 电脑的蓝屏、手机变砖,这其中很大比例是由于重要系统文件丢失、损坏所致。如何保护嵌入式文件系统的安全,这是系统开发人员打造一款稳定、可靠产品时应该考虑的事情。 损坏文件系统,除了外部因素如高压、高温、强磁场干扰存储器外,写文件系统那时的突然掉电往往会造成文件系统结构本身的损坏,例如分区信息。在 Linux 嵌入式系统常见的挂载 VFS 失败就是由于 rootfs 受损所致 , 而这之前的 U-Boot 和 Linuxkernel 往往任可以正常工作。文件针对此类情况 , 将介绍如何在 iMX6 平台上 , 如何使用只读文件系统 , 并将用户应用和数据保存在独立的分区 , 以及利用 ToradexEasyInstaller 完成分区和系统安装操作。 2. 生成只读文件系统 Yocto/OpenEmbedded 构建框架的一个特点是,系统软件会根据所构建的目标镜像的要求自动调整编译软件的功能。例如在 IMAGE_FEATURES 中添加 read-only-rootfs , 那么 BSP 中包含的软件将不会往 Flash 上写入文件 , 包括系统日志。 在 local.conf 配置 ------------------------------------ EXTRA_IMAGE_FEATURES="debug-tweakspackage-managementread-only-rootfs" DISTRO_EXTRA_RDEPENDS_remove="angstrom-libc-fixup-hack" ------------------------------------ 3. 设置分区挂载 修改用户分区挂载目录 ------------------------------------ layers/meta-toradex-demos/recipes-core/base-files/base-files/fstab /dev/root/auto ro,noatime 11 proc/procprocdefaults00 devpts/dev/ptsdevptsmode=0620,gid=500 usbdevfs/proc/bus/usbusbdevfsnoauto00 tmpfs/runtmpfsmode=0755,nodev,nosuid,strictatime00 tmpfs/var/volatiletmpfsdefaults00 #uncommentthisifyourdevicehasaSD/MMC/Transflashslot #/dev/mmcblk0p1/media/cardautodefaults,sync,noauto00 /dev/mmcblk0p3/mntext4defaults,sync,noauto00 ------------------------------------ 将系统根目录设置为只读状态,并将独立的用户分区挂载到 /mnt 目录,该目录任具有读写权限。用户应用可以在该分区下保存用户配置文件、应用日志,甚至升级用户应用本身。 4. 设置应用自启动脚本 由于文件系统需要配置为只读属性,我们需要在 Yocto/OpenEmbedded 构建时直接包含应用开机启动脚本。目前 Toradex 的 LinuxBSP 已经采用 systemd 启动管理,用户需要添加对应的 systemdservice 文件。为了方便演示 , 我们直接在 layers/meta-toradex-bsp-common/recipes-core/ 目录下创建用户自己的 recipe 文件 , 如 user-demo , 当然你也可以在 Yocto/OpenEmbedded 根目录中添加自己的 layer , 将所需的 recipe 都包含进来 , 具体方法请参考 这里 。 ------------------------------------ tdx_cn_ben@LinuxDevSH1:~/Toradex/OE/v2.7/layers/meta-toradex-bsp-common/recipes-core/user-demo$tree-L2 . ├──files │└──user-demo.service └──user-demo.bb ------------------------------------ user-demo.bb ------------------------------------ SUMMARY="Adduserdemo" DESCRIPTION="createfolderwithinhomeandinstallauto-runservicescript" LICENSE="CLOSED" PR="r3" SRC_URI="\ file://user-demo.service\ " do_install(){ install-m0644${WORKDIR}/user-demo.service${D}${systemd_unitdir}/system } NATIVE_SYSTEMD_SUPPORT="1" SYSTEMD_PACKAGES="${PN}" SYSTEMD_SERVICE_${PN}="user-demo.service" inheritallarchsystemd ------------------------------------ user-demo.service ------------------------------------ Description=launchuser'sdemoondedicatedpartition ConditionFileIsExecutable=/mnt/helloworld StartLimitIntervalSec=200 StartLimitBurst=5 After=multi-user.target Type=simple ExecStart=/mnt/helloworld Restart=on-failure RestartSec=10 WantedBy=multi-user.target ------------------------------------ 启动脚本中使用 ConditionFileIsExecutable 来判断用户分区是否成功挂载并存在可执行文件,等待分区文件准备完成后才启动,同时设置 Restart ,当启动失败后会再次尝试。 最后执行命令,生成用于 ToradexEasyInstaller 的安装文件 ------------------------------------ bitbakeconsole-tdx-image ------------------------------------ 将下面文件复制到 SD 或者 U 盘中 ------------------------------------ ├──Colibri-iMX6_Console-Image.bootfs.tar.xz ├──Colibri-iMX6_Console-Image.rootfs.tar.xz ├──image.json ├──prepare.sh ├──slides_vga ├──SPL ├──toradexlinux.png ├──u-boot.imx ├──userapp.tar.xz └──wrapup.sh ------------------------------------ 5. 修改 image.json 配置文件 ToradexEasyInstaller 中的 image.json 文件可用于配置 iMX6 模块上 Flash 的分区情况,并将文件写入对应的分区中。我们需要在 Flash 创建分区,存放用户文件 userapp.tar.xz ,并去掉 rootfs 分区 want_maximised 属性。 ------------------------------------ { "want_maximised":false, "content":{ "mkfs_options":"-Enodiscard", "filesystem_type":"ext4", "uncompressed_size":140.03515625, "filename":"Colibri-iMX6_Console-Image.rootfs.tar.xz", "label":"RFS" }, "partition_size_nominal":512 }, { "want_maximised":true, "content":{ "mkfs_options":"-Enodiscard", "filesystem_type":"ext4", "uncompressed_size":7.01, "filename":"userapp.tar.xz", "label":"UserData" }, "partition_size_nominal":512 } ------------------------------------ userapp.tar.xz 压缩包中包含了用户文件,如 helloworld 和 taq.mp4 ,直接将其压缩成 xz 格式即可。 6. 用户应用 由于用户应用存放在独立的分区上,因此并不需要将其集成到 Yocto/OpenEmbedded ,借助 ToradexEasyInstaller 可以直接将程序、数据等写入分区。以下面应用为例,应用将打印 “Helloworld!” ,并在用户分区上写如数据文件。该应用由上面的 user-demo.service 脚本在开机时启动。 ------------------------------------ intmain(intargc,char*argv ={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; file_hd=open("/mnt/log-file",O_CREAT|O_WRONLY|O_TRUNC); if(file_hd==-1) { printf("filecreatefailed"); return-1; } write(file_hd,(unsignedchar*)data,16); close(file_hd); printf("Helloworld!\n"); return0; } ------------------------------------ 7. 测试文件系统 查看挂载情况 ------------------------------------ root@colibri-imx6:/etc/udev/rules.d#mount-l /dev/mmcblk0p2on/typeext4(ro,noatime,data=ordered) …… /dev/mmcblk0p3on/media/mmcblk0p3typeext4(rw,relatime,data=ordered) ------------------------------------ 在只读文件系统上无法创建目录 ------------------------------------ root@colibri-imx6:~#pwd /home/root root@colibri-imx6:~#mkdirtestfolder mkdir:can'tcreatedirectory'testfolder':Read-onlyfilesystem ------------------------------------ UserData 分区下的用户文件 ------------------------------------ root@colibri-imx6:/media/mmcblk0p3#ls helloworldlost+foundtaq.mp4 ------------------------------------ 应用启动情况 ------------------------------------ root@colibri-imx6:~#journalctl-uuser-demo.service --LogsbeginatWed2018-03-0704:48:18UTC,endatMon2018-03-1208:30:56UTC.-- Mar1208:30:51colibri-imx6systemd :Startedlaunchuser'sdemoondedicatedpartition. Mar1208:30:51colibri-imx6helloworld :Helloworld! root@colibri-imx6:~#hexdump-b/mnt/log-file 0000000000001002003004005006007010011012013014015016017 0000010 ------------------------------------ 8. 总结 通过将 rootfs 设置为只读模式,用户的写操作只缩小到一个单独分区,可以降低由于 rootfs 损坏导致系统启动失败的发生。只读模式的 rootfs 也会带来其他影响,有些文件是在系统运行时必须创建或者更新的,如密码、 randomseed 、 SSHKeys 、网络配置参数等。这些文件的缺失使得系统无法保存之前的配置,每次使用时都需重新建立。以上只是一个简单的说明,如何使用只读文件系统提高系统稳定性。用户也可以将应用直接集成到 BSP 中,当用户分区上的文件损坏或者丢失时,可以将其用作备份恢复。甚至采用额外的存储介质,实现系统恢复、 A/B 分区、 OTA 等其他功能。