linux 基于debian/ubuntu AB系统适配(三)- overlayroot

Overlayroot

Overlayroot是一个实用工具,允许您创建一个只读的根文件系统和一个可写的覆盖文件系统。这对于创建一个更安全和稳定的系统很有用,因为对系统所做的任何更改都将存储在覆盖文件系统中,可以很容易地丢弃或重置。

在Debian下,分离的系统在/userdata/rootfs_overlay下,如:在根文件系统下创建一个111文件夹,实际创建在/userdata/rootfs_overlay下创建的。

这样在切换A/B系统的时候,更新了文件系统就不会影响到用户数据,因为用户数据是在单独的一个分区。但目前种模式只是在但系统上实现,A/B系统没有实现,我们需要进行修改。

uboot

uboot阶段会使用bootargs给内核传overlayroot参数,使内核开启overlayroot
在这里插入图片描述

但启动A/B系统之后会发现,overlayroot参数不见了,导致内核不能开启overlayroot。遂,查找原因。

通过不懈的查找发现,在bootargs中有root参数,该参数指向的就是所要使用的文件系统。如下:

但在启动A/B后,会去修改root这个环境变量,修改为A/B中其中一个文件的UUID,如下:
在这里插入图片描述

问题就出现在这里了,在arch\arm\mach-rockchip\board.c中如果定义了CONFIG_ANDROID_AB则在bootarge中寻找root=,然后删除。问题就出现在这个删除上,因为overlayroot字段里也有root就导致了overlayroot字段也被删除了
在这里插入图片描述

所以这里我们需要进行修改,把root=增加一些字段,使之具有唯一性。修改如下

diff --git a/arch/arm/mach-rockchip/board.c b/arch/arm/mach-rockchip/board.c
index 5c84f3dbfa..9d706b85fa 100644
--- a/arch/arm/mach-rockchip/board.c
+++ b/arch/arm/mach-rockchip/board.c
@@ -1181,7 +1181,7 @@ char *board_fdt_chosen_bootargs(void *fdt)
                 * to cmdline. The format is "roo=PARTUUID=xxxx...".
                 */
 #ifdef CONFIG_ANDROID_AB
-               env_update_filter("bootargs", bootargs, "root=");
+               env_update_filter("bootargs", bootargs, "root=PARTLABEL");
                ab_update_root_partition();
 #else
                env_update("bootargs", bootargs);

在这里插入图片描述

修改编译后发现overlayroot字段还是被删除了,思考后想到root字段删除了但后面还需要补上去的,所以在补上去的时候肯定把overlayroot字段被覆盖了,所以还得找。
在执行了env_update_filter之后又运行了ab_update_root_partition,在函数中又调用了ab_update_root_uuid,该函数就是用作设置root字段。

在该函数可以看到又在查找root=字段,所以这个地方也需要修改。

diff --git a/common/android_ab.c b/common/android_ab.c
index d344a024e9..5df6143fd1 100644
--- a/common/android_ab.c
+++ b/common/android_ab.c
@@ -433,7 +433,7 @@ static void ab_update_root_uuid(void)
        if (ab_is_support_dynamic_partition(dev_desc))
                return;
 
-       if (!strstr(boot_args, "root=")) {
+       if (!strstr(boot_args, "root=PARTUUID")) {
                get_partition_unique_uuid(ANDROID_PARTITION_SYSTEM,
                                          guid_buf, UUID_SIZE);
                strcat(root_partuuid, guid_buf);

在这里插入图片描述

编译后,参数终于正确了
在这里插入图片描述

kernel

修改uboot启动系统后,overlayroot能够顺利建立了,但新的问题又来了,建立的overlayroot文件名称不对,是以分区名称为前缀建立的,如下
在这里插入图片描述

这样会导致切换系统后,用户数据丢失,需要修改,使用mount命令可以看到,,overlayroot挂载在/userdata下,并带有参数:
在这里插入图片描述

lowerdir=/root-ro,  //原始文件所在的位置,lower层的文件只读
upperdir=/userdata/system_b_overlay, //任何修改都将反映在Upper层 ,故upper层可读可写
workdir=/userdata/system_b_overlay-workdir/_ //指定文件系统的工作基础目录,挂载后内容会被清空,且在使用过程中其内容用户不可见

可以看出该参数很重要,所以先修改挂载目录,通过搜索查找到了他们赋值的位置,在Y:\android\rk3588_debian\kernel\fs\overlayfs\super.c,中
在这里插入图片描述

有尝试过直接修改他们的值,但是会导致整个系统崩溃。所以需要找到原始赋值的地方。
数据是通过opt传入进来的,该值是通过file_system_type的系统调用来传输的,通过mount接口使用ovl_mount函数指针传入进来,在往上就是应用层面了,所以只能在ovl_mount中进行修改,修改方式如下:

diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 4a2ce2eeee88..dcbdc08bd87d 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -2074,6 +2074,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags,
                                const char *dev_name, void *raw_data)
 {
+    /*****************cc add*******************************/
+    char *data = "lowerdir=/root-ro,upperdir=/userdata/rootfs_overlay,workdir=/userdata/rootfs_overlay-workdir/_\0";
+    if(strstr(raw_data, "system_a_overlay") || strstr(raw_data, "system_b_overlay")) {
+        memcpy(raw_data, data, strlen(data)+1);
+    }
+    /*****************cc add*******************************/
+
        return mount_nodev(fs_type, flags, raw_data, ovl_fill_super);
 }

在这里插入图片描述

这里修改的逻辑是不管是A系统还是B系统都使用一个文件夹rootfs_overlay,修改过这里之后还不行,因为没有创建rootfs_overlay文件夹。

通过报错的log可以知道,创建/userdata文件夹的是通过调用mkdir创建的,我们无法修改已编译好的应用,所以需要在底层做修改。

创建文件在内核中的位置是fs/namei.c中的filename_create,任何的文件创建都会通过该接口。
在这里插入图片描述

但不可直接在该函数下创建文件,原因是内核和用户都会调用该接口去创建文件夹,overlayroot使用的是用户接口去创建的,所以我们秉着影响最小的原则来修改,选择在user_path_create中修改。
在这里插入图片描述

修改方式是在这里通过字符串比较,如果创建system_a_overlaysystem_b_overlay则就认为是要创建双系统挂载目录。我们拦截修改即可,如下
在这里插入图片描述

如果仅仅修改此地方还不能解决问题,因为在下一次开机的时候查找不到需要的目录还会再次的去创建,但我们又无法阻值它去创建,所以我们只能在它再次创建的时候去返回一个成功,但实际我们并没有创建,即可解决该问题。

创建文件的入口在do_mkdirat然后调用user_path_create函数,再去调用filename_create去创建文件。
在这里插入图片描述

所以我们可以在这之前就直接返回即可,修改如下:
在这里插入图片描述

全部修改如下:

diff --git a/fs/namei.c b/fs/namei.c
index 342bc7d4cbc7..b48dbbd0f4c6 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3597,7 +3597,23 @@ EXPORT_SYMBOL(done_path_create);
 inline struct dentry *user_path_create(int dfd, const char __user *pathname,
                                struct path *path, unsigned int lookup_flags)
 {
-       return filename_create(dfd, getname(pathname), path, lookup_flags);
+    /***************************cc add*******************************************************/
+    struct filename *name = getname(pathname);
+
+    char *dir_name =(char *) name->name;
+    if(strstr(name->name, "system_a_overlay") || strstr(name->name, "system_b_overlay")) {
+        if(strstr(dir_name, "_overlay-workdir")) {
+            if(strstr(dir_name, "_overlay-workdir/_")) {
+                memcpy(dir_name, "/userdata/rootfs_overlay-workdir/_\0", strlen("/userdata/rootfs_overlay-workdir/_\0")+1);
+            } else {
+                memcpy(dir_name, "/userdata/rootfs_overlay-workdir\0", strlen("/userdata/rootfs_overlay-workdir\0")+1);
+            }
+        } else {
+            memcpy(dir_name, "/userdata//rootfs_overlay\0", strlen("/userdata//rootfs_overlay\0")+1);
+        }
+    }
+    /*****************************************************************************************/
+       return filename_create(dfd, name, path, lookup_flags);
 }
 EXPORT_SYMBOL(user_path_create);
 
@@ -3736,6 +3752,17 @@ static long do_mkdirat(int dfd, const char __user *pathname, umode_t mode)
        int error;
        unsigned int lookup_flags = LOOKUP_DIRECTORY;
 
+/*****************cc add*******************************/
+    struct filename *name = getname(pathname);
+    struct path path_overlay;
+    if(strstr(name->name, "system_a_overlay") || strstr(name->name, "system_b_overlay")) {
+        if (!kern_path("/userdata/rootfs_overlay\0", LOOKUP_FOLLOW, &path_overlay) &&
+            !kern_path("/userdata/rootfs_overlay-workdir/_\0", LOOKUP_FOLLOW, &path_overlay)) {
+            return 0;
+        }
+    }
+/******************************************************/
+
 retry:
        dentry = user_path_create(dfd, pathname, &path, lookup_flags);
        if (IS_ERR(dentry))

编译测试,系统正常运行。

总结

通过三章把基于linux Debian下的A/B系统移植大致描述了一下,主要修改的地方是uboot、kernel、roofs,A/B系统的原理很简单,主要是镜像的分离打包和开机后的一些处理。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
CentOS的文件系统中,Overlay是一种联合文件系统(Union File System),它允许将多个文件系统以层叠的方式合并在一起。Overlay文件系统通常用于创建轻量级容器,其中一个只读的基础文件系统(Base File System)与一个可写的上层文件系统(Upper File System)进行合并。 在CentOS中,Overlay文件系统可以使用OverlayFS来实现。它通过将两个文件系统以层叠的方式合并,将只读的基础文件系统与可写的上层文件系统进行组合。这样,对于上层文件系统的读操作,会首先在上层文件系统中查找,如果找不到则会在基础文件系统中查找。对于写操作,则会直接在上层文件系统中进行。 要使用Overlay文件系统,首先需要确保内核支持OverlayFS。在CentOS 7及以上版本中,默认情况下已经支持OverlayFS。然后,你可以在需要的地方挂载Overlay文件系统,将只读的基础文件系统与可写的上层文件系统进行合并。 例如,可以使用以下命令来挂载Overlay文件系统: ``` mount -t overlay overlay -o lowerdir=/path/to/base,upperdir=/path/to/upper,workdir=/path/to/work /path/to/mount ``` 其中,`lowerdir`指定基础文件系统的路径,`upperdir`指定上层文件系统的路径,`workdir`指定工作目录的路径,`/path/to/mount`指定挂载点的路径。 请注意,Overlay文件系统需要Linux内核的支持,并且在某些情况下可能会有性能方面的考虑。因此,在使用Overlay文件系统之前,建议你仔细评估你的需求和系统资源,并确保了解其工作原理和限制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘭噗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值