Linux文件系统之根文件系统rootfs

张开发
2026/4/7 4:54:49 15 分钟阅读

分享文章

Linux文件系统之根文件系统rootfs
文章目录1preface1、资料快车2、概述1根文件系统rootfs特点2过渡根文件系统的设计思想2基本概念1、文件系统在EMMC/RAM中的布局2、Linux过渡文件系统-ram filesystem1早期的initrd(ramdisk)2主流轻量级的initramfs3initrd与initramfs比较3Android中的ramdisk(initramfs)1、Android启动加载过程2、Android中的ramdisk制作3、Android的rootfs配置4、ramfs注册与启动1rootfs初始化2ramfs的注册与挂接3ramfs的init进程4小结5、ramfs源码分析1preface1、资料快车1Android ramdisk配置、解压、创建rootfs、启动简单分析https://www.cnblogs.com/arnoldlu/p/10986583.html2initrd和initramfs实操https://www.cnblogs.com/xiaomanblog/articles/182482272、概述1根文件系统rootfs特点1.rootfs是需要Linux系统启动初期能够识别的因此最好的方案是使用ram filesystem2.包含基本的目录结构和启动程序3.Linux设备的rootfs一般作为过渡使用Android不仅用作启动还作为文件系统的顶层框架4.Linux和Android上的rootfs一般为initrd和initramfs (有ramfs和tmpfs)它们都是ram filesystem5.ramdisk依赖VFS所有文件系统都需依赖VFS2过渡根文件系统的设计思想内核和文件系统镜像都在EMMC为什么还需要initrd/initramfs过渡- 分层思想1.kernel、ramdisk都是bootloader 加载到内存运行的kernel未加载emmc.ko、ext4.ko之前是没有能力访问emmc和文件系统2.rootfs则打包了启动脚本、init、emmc.ko、ext4.ko、工具等文件 (ext4则放一些非必要、可以后期加载的模块和文件)3.rootfs当下不也是打包到kernel镜像违背了裁剪kernel的初衷1ramdisk虽然也打包到kernel镜像但ramdisk也是一个独立的模块做的也仅仅是镜像拼接简化烧录流程2而精简kernel是指kernel保留基础功能 (不要把这些功能捆绑在kernel的编译里)定制功能交给ramdisk(不同厂家只需要定制ramdiskkernel则可以保持最大的兼容性)4.试想一下如果将各种纷繁复杂的存储设备打包到kernel那么kernel将变得不灵活厂商还得调试好内核中的文件系统才能正常启动如果将这部分抽离没有真正的文件系统设备也能正常启动 - 只是缺乏用户功能2基本概念1、文件系统在EMMC/RAM中的布局1从发展历程来看 先有initrd(2.6内核之后被弃用)再由initramfs(2.6内核默认使用)但在切换过程中存在术语混用2内核中配置选项和代码都还保留 ”initrd“ 关键字但实际早已经被淘汰3ramdisk是指在ram模拟块设备用于加载initrd这类基于FLASH的文件系统但现代系统也一直保留ramdisk的称呼ramdisk 已经泛指 initramfs不再是基于块设备而是基于 cpio 归档只有明确提到“块设备 ramdisk”或“/dev/ram0”时是指initrd2、Linux过渡文件系统-ram filesystem1早期的initrd(ramdisk)1、initrd全称为initial ram disk但它实际不是纯粹的ram fs类型可能使用ext2文件系统格式(即块设备)使用ram模拟块设备运行2、ramdisk指的是在RAM分配 用于装载initrd镜像的区域大小固定在编译时静态分配采用initrd时ramdiskinitrd3、initrd是早期的过渡文件系统现在基本使用更加轻量的initramfs2主流轻量级的initramfs1initramfs : initial ram file system具体实现可以是ramfs 或 tmpfs2tmpfs是ramfs的升级版相对ramfstmpfs有容量的限制并且允许将数据写入交换分区3如果内核中 initramfs 和外部的 initramfs 都存在则外部的会覆盖内核中的4initramfs的构建与配置1、根文件系统与其它文件系统构建流程没有差异(打包格式化)可以使用busybox制作initramfs2、在开发初期可以单独制作根文件系统动态替换生效在产品发布则使用脚本打包到完整镜像中5initramfs文件布局案例6拆解真实的initramfs3initrd与initramfs比较3Android中的ramdisk(initramfs)1、资料快车1rootfs文件_clang编译android内核https://cloud.tencent.cn/developer/article/21559382Ramdisk分区介绍https://source.android.google.cn/docs/core/architecture/partitions/ramdisk-partitions1、现代Android系统中的ramdisk指的是initramfs2、initrd 这个老名字来指代本质上已经是 initramfs 的 ramdisk.img3、ramdisk所承担的工作大体一致但不同系统分工不同采用的形式也有所不同注意区分1、Android启动加载过程123从Android启动过程可以看到Android系统与Linux有所不同仍然采用ramdisk机制但不是作为过渡文件系统而是作为根文件系统也就是作为一个独立分区不会消亡后续的分区镜像依次挂载根目录下的不同目录常驻与内存能运行Android的系统RAM资源也不会缺无需考虑占用RAM资源2、Android中的ramdisk制作1.Android系统如何制作initramfs 集成在编译脚本任何大型系统都不会单独制作 initramfs打包相关脚本 /android/build/target/product/generic_ramdisk.mk /android/common/common14-5.15/build/kernel/build.sh /android/common/common14-5.15/build/kernel/build_utils.sh /android/common/common14-5.15/common/usr/Makefile /android/common/common14-5.15/common/usr/* /android/common/common14-5.15/common/usr/gen_initramfs.sh 2.Android ramdisk,boot,system.img 解包和打包 https://blog.csdn.net/tsb151/article/details/1080467973、Android的rootfs配置1.ramfs源码 /android/common/common14-5.15/common/init/initramfs.c 2.mk /android/common/common14-5.15/common/init/Makefile obj-y : main.o version.o mounts.o obj-$(CONFIG_BLK_DEV_INITRD) initramfs.o mounts-y : do_mounts.o mounts-$(CONFIG_BLK_DEV_RAM) do_mounts_rd.o mounts-$(CONFIG_BLK_DEV_INITRD) do_mounts_initrd.o 3.config /android/common/common14-5.15/out/android14-5.15/common/.config CONFIG_BLK_DEV_INITRDy --Linux配置项名为 CONFIG_BLK_DEV_INITRD它同时支持initrd和initramfs CONFIG_BLK_DEV_RAMy 4.打包逻辑 /android/common/common14-5.15/common/usr/* /android/build/target/product/generic_ramdisk.mk 5.cmdline /android/bootloader/uboot-repo/bl33/v2019/customer/board/configs/txhd2_be30ae.h 1) fs_typerootfstyperamfs 2) init/init 6.指定rootfs类型 不同方案使用不同环境变量但都是通过环境变量 1) rootfstype __setup(rootflags, root_data_setup); __setup(rootfstype, fs_names_setup); __setup(rootdelay, root_delay_setup); static int __init fs_names_setup(char *str) { root_fs_names str; return 1; } 2) root? /android/common/common14-5.15/common/init/do_mounts.c static int __init root_dev_setup(char *line) --__setup(root, root_dev_setup); 7.rdinit/bin/sh-有些Linux系统ramfs运行的init是shell用来执行脚本文件Android则使用CPP实现的init(system/core/init) 1 /android/common/common14-5.15/common/init/main.c int __init rdinit_setup(char *str) --__setup(rdinit, rdinit_setup); 2init/bin/sh 等价于 rdinit/bin/sh /android/common/common14-5.15/common/Documentation/filesystems/ramfs-rootfs-initramfs.rst4、ramfs注册与启动1rootfs初始化1init_rootfs /android/common/common14-5.15/common/init/do_mounts.c void __init init_rootfs(void) { if (IS_ENABLED(CONFIG_TMPFS) !saved_root_name[0] (!root_fs_names || strstr(root_fs_names, tmpfs))) is_tmpfs true; } 2) init_ramfs_fs /android/common/common14-5.15/common/fs/ramfs/inode.c static int __init init_ramfs_fs(void) { return register_filesystem(ramfs_fs_type); } fs_initcall(init_ramfs_fs);2ramfs的注册与挂接一、ramfs的注册与挂接(与常规文件系统类似挂接到VFS) 1start_kernel /android/common/common14-5.15/common/init/main.c start_kernel() --vfs_caches_init(); /android/common/common14-5.15/common/fs/namespace.c ----mnt_init() /android/common/common14-5.15/common/mm/shmem.c ------init_rootfs() /android/common/common14-5.15/common/fs/ramfs/inode.c --------init_ramfs_fs(void) ----------register_filesystem(ramfs_fs_type); //1.注册文件系统 ------init_mount_tree() //2.挂接文件系统,最终调用ram_fill_super /android/common/common14-5.15/common/fs/namespace.c --------vfs_kern_mount(rootfs_fs_type, 0, rootfs, NULL); ----------fc fs_context_for_mount(type, flags); ----------fc_mount(fc); ------------vfs_create_mount(fc); --------------rootfs_fs_type-mount() 1.ramfs_fs_type /android/common/common14-5.15/common/fs/ramfs/inode.c static struct file_system_type ramfs_fs_type { .name ramfs, .init_fs_context ramfs_init_fs_context, .parameters ramfs_fs_parameters, .kill_sb ramfs_kill_sb, .fs_flags FS_USERNS_MOUNT, }; ramfs_init_fs_context() --fs_context-ops ramfs_context_ops; ----ramfs_get_tree() ------get_tree_nodev(fc, ramfs_fill_super); 2.ramfs_fill_super /android/common/common14-5.15/common/fs/ramfs/inode.c static int ramfs_fill_super(struct super_block *sb, struct fs_context *fc) { struct ramfs_fs_info *fsi sb-s_fs_info; struct inode *inode; sb-s_maxbytes MAX_LFS_FILESIZE; sb-s_blocksize PAGE_SIZE; sb-s_blocksize_bits PAGE_SHIFT; sb-s_op ramfs_ops; //挂接ramfs operations操作集 inode ramfs_get_inode(sb, NULL, S_IFDIR | fsi-mount_opts.mode, 0); sb-s_root d_make_root(inode); //创建根节点/ } 二、ramfs解压缩 1.start_kernel /android/common/common14-5.15/common/init/main.c start_kernel() --vfs_caches_init(); //完成ramfs的注册和挂接 --arch_call_rest_init(); ----rest_init() ------kernel_thread(kernel_init, NULL, CLONE_FS); --------kernel_init() ----------kernel_init_freeable() ------------do_basic_setup(); //执行完do_basic_setup()即完成各种initcall之后判断ramdisk_execute_command --------------do_initcalls(); ----------------do_initcall_level(level, command_line); //最终会调用到populate_rootfs ----------run_init_process(ramdisk_execute_command)//执行ramdisk_execute_command命令替代当前进程。 2.do_initcalls 内核启动执行 start_kernel() → 初始化内存管理、调度器、VFS 等 → 调用 do_initcalls() 按优先级顺序执行所有 initcall。 rootfs_initcall 的优先级为 4在 arch_initcall 和 subsys_initcall 之后在 device_initcall 之前此时 VFS 和具体文件系统如 tmpfs、rootfs已经注册并挂载了初始的 rootfs通常是 ramfs 或 tmpfs。 1populate_rootfs /android/common/common14-5.15/common/init/initramfs.c populate_rootfs()//解压__initramfs_start包含的ramdisk到rootfs中。 --do_populate_rootfs() ----unpack_to_rootfs(__initramfs_start, __initramfs_size); //存放的地址在vmlinux.lds.h指定 ------decompress() //采用压缩格式对应的解压方法默认使用cpio格式 static int __init populate_rootfs(void) { initramfs_cookie async_schedule_domain(do_populate_rootfs, NULL, initramfs_domain); usermodehelper_enable(); if (!initramfs_async) wait_for_initramfs(); return 0; } rootfs_initcall(populate_rootfs); 2 __initramfs_start/__initramfs_size会在链接脚本指定 /android/common/common14-5.15/common/include/asm-generic/vmlinux.lds.h3ramfs的init进程不同根文件系统的“init”有的使用init进程有些使用rc脚本-linuxrc Android10 init启动流程初识 https://blog.csdn.net/Harrison509/article/details/108659469 1、ramfs启动工作 /android/common/common14-5.15/common/init/main.c run_init_process(ramdisk_execute_command) //static char *ramdisk_execute_command /init; --kernel_execve(init_filename, argv_init, envp_init); //执行第一个程序init, /system/core/init /android/system/core/init/main.cpp --main() ----FirstStageMain(argc, argv) ------CHECKCALL(mount(tmpfs, /dev, tmpfs, MS_NOSUID, mode0755)); //挂载创建各种分区 ------CHECKCALL(mount(sysfs, /sys, sysfs, 0, NULL)); ------CHECKCALL(mkdir(/mnt/vendor, 0755)); ------StartConsole(cmdline); //启动控制台 ------SwitchRoot(/first_stage_ramdisk); //切换真正的文件系统根目录(system分区) ------DoFirstStageMount(!created_devices); ------FreeRamdisk(old_root_dir.get(), old_root_info.st_dev); ------execv(system/bin/init) //执行真正的init程序4小结5、ramfs源码分析1.ramfs目录结构(只有两个文件) /android/common/common14-5.15/common/fs/ramfs/file-mmu.c /android/common/common14-5.15/common/fs/ramfs/inode.c 2.4大对象实现使用libfs简单文件系统库实现 1) file_operations /android/common/common14-5.15/common/fs/ramfs/file-mmu.c struct file_operations ramfs_file_operations { .read_iter generic_file_read_iter, //VFS通用接口 .write_iter generic_file_write_iter, .mmap generic_file_mmap, ... }; 2文件inode_operations /android/common/common14-5.15/common/fs/ramfs/file-mmu.c struct inode_operations ramfs_file_inode_operations { .setattr simple_setattr, //libfs接口 .getattr simple_getattr, }; 3目录inode_operations struct inode_operations ramfs_dir_inode_operations { .create ramfs_create, .lookup simple_lookup, .link simple_link, .unlink simple_unlink, .symlink ramfs_symlink, .mkdir ramfs_mkdir, .rmdir simple_rmdir, .mknod ramfs_mknod, .rename simple_rename, .tmpfile ramfs_tmpfile, }; 4ramfs_ops struct super_operations ramfs_ops { .statfs simple_statfs, .drop_inode generic_delete_inode, .show_options ramfs_show_options, };

更多文章