有些项目需要做根文件系统只读,也需要保证系统本身是可写的。这里通过使用联合文件系统overlayfs来处理这种需求。
同样的,客户还需要做U盘更新,备份,还原等操作。为了方便处理,这些操作均通过ramdisk里的overlayfs脚本来实现。这里简单讲一下实现步骤
功能主要为两个地方,一个是支持ramdisk/initrd,一个是支持overlayfs
其次需要开启的为各类挂载系统的功能支持,如ext4,ntfs,exfat,squashfs,以及U盘的识别
如下所示:
CONFIG_BLK_DEV_INITRD CONFIG_OVERLAY_FS CONFIG_EXT4_FS CONFIG_NTFS_FS CONFIG_FAT_FS CONFIG_VFAT_FS CONFIG_SQUASHFS CONFIG_USB_STORAGE CONFIG_SCSI CONFIG_BLK_DEV_SD
我们知道,系统开机由内核的cmdline来体现,为了使能overlayfs,可以显示的将overlayfs的配置体现在cmdline。如下
root=PARTLABEL=rootfs rootfstype=squashfs rw overlayroot=device:dev=PARTLABEL=userdata,fstype=ext4,mkfs=1
可以知道如下信息:
a.root分区默认挂载在PARTLABEL=rootfs,类型为squashfs b.overlayroot分区默认一个设备,为PARTLABEL=userdata,类型为ext4
ramdisk脚本可以通过如下获取
https://gitlab2.kylin.com/shanghai-team/ramdisk/-/blob/ramdisk-reduce/ramdisk/scripts/init-bottom/kylinoverlay
脚本在init-bottom下运行,需要在ORDER下追加
/scripts/init-bottom/kylinoverlay "$@"
这样在系统加载ramdisk/initrd时,kylinoverlay运行会通过mount命令,将原始的root挂载修改为overlay挂载
如直接克隆ramdisk参考,上述步骤无需关心
root@kylin:~# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT mmcblk0 179:0 0 29.1G 0 disk ├─mmcblk0p3 179:3 0 10.5G 0 part /media/root-ro └─mmcblk0p6 179:6 0 13G 0 part /media/root-rw
其中 /media/root-ro 和 /media/root-rw 是对应的root和userdata分区
root@kylin:~# blkid /dev/mmcblk0p3: TYPE="squashfs" PARTLABEL="rootfs" PARTUUID="614e0000-0000-4b53-8000-1d28000054a9" /dev/mmcblk0p6: PARTLABEL="userdata" UUID="62af73c5-bd8c-4cc0-af0a-10abc9574f21" TYPE="ext4" PARTLABEL="userdata" PARTUUID="2d1d0000-0000-4e74-8000-770200003b4e" overlay的挂载情况 root@kylin:~# mount /dev/mmcblk0p3 on /media/root-ro type squashfs (ro,relatime) /dev/mmcblk0p6 on /media/root-rw type ext4 (rw,relatime) overlayroot on / type overlay (rw,relatime,lowerdir=/media/root-rw/commit:/media/root-ro,upperdir=/media/root-rw/rootfs_overlay,workdir=/media/root-rw/rootfs_overlay-workdir/_)
这里把commit和root-ro作为lower,root-ro是最底层,rootfs_overlay作为upper,rootfs_overlay-workdir作为work
这里需要说明的是:
overlayfs是将多个分区/目录进行联合挂载,对挂载点进行分层,作为lower层的只读,upper层的可写,从而合并成overlayroot目录作为根文件系统,在根文件系统上的读写实际上是通过读写upper层的内容。
rm -rf "${root_rw}/${dir_prefix}/*"
开机自动清理即直接删除upper层的所有文件内容
cp -rpf ${root_rw}/${dir_prefix}/* ${root_rw}/commit/ rm -rf ${root_rw}/${dir_prefix}/*
提交改动即将overlay_root目录的内容,原封不动拷贝到commit下。
值得注意的是,overlay会标记已删除的文件和目录为字符文件,需要针对其做如下处理
先遍历dir_prefix的字符文件,然后跑到commit下删掉 再遍历commit的字符文件,然后跑到dir_prefix下删掉
func_restore(){ rm -rf ${root_rw}/* mkdir -p ${root_rw}/${dir_prefix} mkdir -p $workdir mkdir -p ${root_rw}/commit }
系统还原即删除所有root-rw目录的内容,并重新创建upper层,work层,和lower层的commit 目录
umount ${root_ro} umount ${root_rw} rootfs=`blkid -s PARTLABEL | grep PARTLABEL=\"rootfs\" | awk -F: '{print $1}'` userdata=`blkid -s PARTLABEL | grep PARTLABEL=\"userdata\" | awk -F: '{print $1}'` dd if=/update/filesystem.squashfs of=${rootfs} dd if=/update/ghost.squashfs of=${rootfs} dd if=/update/overlay.ext4 of=${userdata} mount ${rootfs} ${root_ro} mount ${userdata} ${root_rw}
U盘更新即找到U盘后,卸载root-rw和root-ro,将分区进行dd到系统上,然后再重新mount起来
因为直接使用的dd,所以dd时不能断电和拔出U盘,否则系统会变砖,后续可以考虑,系统变砖后,自动恢复rootfs的功能
mksquashfs ${root_ro}/ /ghost/ghost.squashfs commit_size=`/usr/bin/du --block-size=1M -s ${root_rw}/commit/ | awk '{print $1}'` commit_size=$(($commit_size+100)) dd if=/dev/zero of=/ghost/overlay.ext4 bs=512 count=2048 mkfs.ext4 -F /ghost/overlay.ext4 resize2fs /ghost/overlay.ext4 ${commit_size}M inode=`expr ${commit_size} \* 1024 / 16` mkfs.ext4 -F -L userdata -N ${inode} /ghost/overlay.ext4 cp -rpf ${root_rw}/commit/ /tmp umount /tmp sync -f /ghost/overlay.ext4 e2fsck -f /ghost/overlay.ext4 resize2fs /ghost/overlay.ext4 -M
备份系统即打包root分区和打包overlay分区下的commit目录。生成ghost.squashfs和overlay.ext4
使用通过overlaymanager.sh脚本,通过内置到操作系统下即可使用,具体操作情况如下
usage(){ info "Usage: " info " $0 -commit/-c #提交" info " $0 -ghost/-g #一键ghost" info " $0 -restore/-r #系统还原" info " $0 -update/-u #更新系统" info " $0 -y #打开自动清理" info " $0 -n #关闭自动清理" info " $0 -boot/-b #升级内核" }