百篇博客系列篇.本篇为:

v66.xx 鸿蒙内核源码分析(根文件系统) | 先挂到/上的文件系统 | 51.c.h.o

文件系统相关篇为:

FHS | 文件系统层次结构标准

  • 挂载目录篇 中提到内核为了兼容文件系统的差异性,引出了目录树的概念,目录树是由各个文件系统像搭积木一样拼接起来的,任何文件系统只需要挂载到一个目录上就能对接进来,内核抽象出统一的挂载接口,各文件系统自己实现这些接口就行. 既然目录如此重要, 就需要规范管理, 类Unix都遵循 FHS 规范,鸿蒙同样遵循.

  • 文件系统层次结构标准(英语:Filesystem Hierarchy Standard,FHS)定义了Linux操作系统中的主要目录及目录内容。FHS由Linux基金会维护。 当前版本为3.0版,于2015年发布。基本目录如下:

    1. / 根目录
    2. /home 用户主文件夹
    3. /etc 系统主要的配置文件几乎都放置在这个目录内
    4. /root 系统管理员(root)的主文件夹
    5. /bin 可以被 root 与一般账号所使用
    6. /sbin 这些命令只有 root 才能够利用来“设置”系统
    7. /lib 放置的则是在开机时会用到的函数库
    8. /opt 用于安装第三方应用程序的
    9. /dev 任何设备与接口设备都是以文件的形式存在于这个目录当中
    10. /proc 一个虚拟的文件系统, 它放置的数据都是在内存当中
    11. /sys 也是一个虚拟的文件系统,主要也是记录与内核相关的信息
    12. /media 放置的就是可删除的设备
    13. /mnt 暂时挂载某些额外的设备
    14. /srv 一些网络服务启动之后,这些服务所需要取用的数据目录
    15. /tmp 正在执行的程序暂时放置文件的地方, 系统会不定期删除
    16. /usr UNIX 操作系统软件资源” 所放置的目录
    17.   /usr/bin/: 绝大部分的用户可使用命令都放在这里
    18.   /usr/include/:C/C++等程序语言的头文件 header 与包含文件include放置处
    19.   /usr/lib/: 包含各应用软件的函数库、目标文件以及一些不被一般用户惯用的执行文件或脚本
    20.   /usr/local/: 系统管理员在本机自行安装下载的软件建议安装到此目录
    21.   /usr/sbin/: 非系统正常运行所需的系统命令
    22.   /usr/share/: 放置共享文件的地方
    23.   /usr/src/: 一般源码建议放置到这里
    24. /var 该目录主要针对常态性可变动文件
    25. /var/cache/: 应用程序本身运行过程中会产生的一些暂存文件
    26.   /var/lib/: 程序本身执行的过程中,需要的数据文件放置的目录
    27.   /var/lock/: 目录下的文件资源一次只能被一个应用程序所使用
    28.   /var/log/: 放置登录文件的目录
    29.   /var/mail/: 放置个人电子邮件信箱的目录
    30.   /var/run/: 某些程序或服务启动后的PID目录
    31.   /var/spool/: 放置排队等待其他应用程程序使用的数据

什么是根文件系统

看网上有很多的文章,但基本全是一大抄,说是内核启动时所mount的第一个文件系统,这话固然是没错, 但想重新定义下这个概念, 所谓 根文件系统 就是先挂到根目录/上的文件系统. 核心是根目录 /. /目录并不必先属于哪个文件系统,否则就是先有蛋还是先有鸡的问题,所以别被蒙圈了,它跟其他文件系统没有任何区别,只是它先来,把坑/给占了,后续来的只能挂到它下面的目录上,最终形成整颗目录树.

理解了上面,就容易明白以下几个问题:

  • 一个系统可以存在多个不同的文件系统,谁做根文件系统只决于内核在启动阶段想让谁做.
  • 文件系统可存在于诸多介质上,例如:硬盘(mmc),闪存(flash),内存(RAM).每种介质上有其最合适配套的文件系统,mmc一般是(fat,ext),flash包括(jffs2),内存(proc,sys,tmpfs,ramfs)
  • 文件系统可简单,可复杂,只要能实现内核定义的三类接口就可以称之为文件系统,哪三类接口:
    • 挂载接口: MountOps ops
    • 操作 inode节点接口: VnodeOps *vop
    • 操作 file接口:file_operations_vfs *fop,这个接口底层实际操作的是 inode所指向的数据块.
  • 不管怎样,内核启动后必须得有一个文件系统用于挂载到/下. 鸿蒙根文件系统目录结构如下:
    1. .
    2. ├── app
    3. ├── bin
    4.    ├── init
    5.    ├── shell
    6.    └── tftp
    7. ├── data
    8.    └── system
    9.    └── param
    10. ├── etc
    11. ├── lib
    12.    ├── libc++.so
    13.    └── libc.so
    14. ├── system
    15.    ├── external
    16.    └── internal
    17. └── usr
    18. ├── bin
    19. └── lib

这些数据是怎么来的呢 ? 比如:libc.so这种C库函数,启动后就马上需要使用的, 这需要先外部制作好,烧录到flash的指定位置. 同时注意鸿蒙制作的根文件系统并没有 /dev目录,这个在 设备文件篇 中详细说明.

根文件系统制作过程

liteos_a内核为例,其提供了制作根文件系统的方法:

  1. turing@ubuntu:/home/openharmony/code-v1.1.1-LTS/kernel/liteos_a$ make help
  2. -------------------------------------------------------
  3. 1.====make help: get help infomation of make
  4. 2.====make: make a debug version based the .config
  5. 3.====make debug: make a debug version based the .config
  6. 4.====make release: make a release version for all platform
  7. 5.====make release PLATFORM=xxx: make a release version only for platform xxx
  8. 6.====make rootfsdir: make a original rootfs dir
  9. 7.====make rootfs FSTYPE=***: make a original rootfs img
  10. 8.====make test: make the testsuits_app and put it into the rootfs dir
  11. 9.====make test_apps FSTYPE=***: make a rootfs img with the testsuits_app in it
  12. xxx should be one of (hi3516cv300 hi3516ev200 hi3556av100/cortex-a53_aarch32 hi3559av100/cortex-a53_aarch64)
  13. *** should be one of (jffs2)

其中第七项 make rootfs, FSTYPE支持 jffs2,vfat文件格式系统

本篇跟踪敲下 make rootfs FSTYPE=jffs2后发生了什么

查看 kernel/liteos_a/Makefile

  1. #执行 make rootfs FSTYPE=jffs2 一切从这里开始
  2. $(ROOTFS): $(ROOTFSDIR) #依赖于 ROOTFSDIR
  3. $(HIDE)$(LITEOSTOPDIR)/tools/scripts/make_rootfs/rootfsimg.sh $(ROOTFS_DIR) $(FSTYPE) #制作镜像文件
  4. $(HIDE)cd $(ROOTFS_DIR)/.. && zip -r $(ROOTFS_ZIP) $(ROOTFS) #打rootfs.zip包

解读

  • 编译整个内核的目标文件

    1. $(LITEOS_TARGET): $(__LIBS) sysroot
    2. $(HIDE)touch $(LOSCFG_ENTRY_SRC)
    3. #逐个编译子目录中的 makefile
    4. $(HIDE)for dir in $(LITEOS_SUBDIRS); \
    5. do $(MAKE) -C $$dir all || exit 1; \
    6. done
    7. # 生成 liteos.map
    8. $(LD) $(LITEOS_LDFLAGS) $(LITEOS_TABLES_LDFLAGS) $(LITEOS_DYNLDFLAGS) -Map=$(OUT)/$@.map -o $(OUT)/$@ --start-group $(LITEOS_LIBDEP) --end-group
    9. # $(SIZE) -t --common $(OUT)/lib/*.a >$(OUT)/$@.objsize
    10. $(OBJCOPY) -O binary $(OUT)/$@ $(LITEOS_TARGET_DIR)/$@.bin #生成 liteos.bin 文件
    11. $(OBJDUMP) -t $(OUT)/$@ |sort >$(OUT)/$@.sym.sorted #生成 liteos.sym.sorted 文件
    12. $(OBJDUMP) -d $(OUT)/$@ >$(OUT)/$@.asm # 生成 liteos.asm文件
  • 使用 $(APPS) 编译 kernel/liteos_a/apps 目录下的各个APP 如( init,shell,tftp),这些APP也称为内置到内核的APP,

    1. # 编译多个应用程序
    2. $(APPS): $(LITEOS_TARGET) sysroot #依赖于 LITEOS_TARGET , sysroot
    3. $(HIDE)$(MAKE) -C apps all #执行apps目录下Makefile 的all目标, -C代表进入apps目录,
  • 使用 tools/scripts/make_rootfs/rootfsdir.sh 创建根系统下的各个目录( /bin, /app, /lib).

    1. #创建根文件系统的各个目录
    2. mkdir -p ${ROOTFS_DIR}/bin ${ROOTFS_DIR}/lib ${ROOTFS_DIR}/usr/bin ${ROOTFS_DIR}/usr/lib ${ROOTFS_DIR}/etc \
    3. ${ROOTFS_DIR}/app ${ROOTFS_DIR}/data ${ROOTFS_DIR}/proc ${ROOTFS_DIR}/dev ${ROOTFS_DIR}/data/system ${ROOTFS_DIR}/data/system/param \
    4. ${ROOTFS_DIR}/system ${ROOTFS_DIR}/system/internal ${ROOTFS_DIR}/system/external ${OUT_DIR}/bin ${OUT_DIR}/libs
    5. if [ -d "${BIN_DIR}" ] && [ "$(ls -A "${BIN_DIR}")" != "" ]; then
    6. cp -f ${BIN_DIR}/* ${ROOTFS_DIR}/bin
    7. if [ -e ${BIN_DIR}/shell ] && [ "${BIN_DIR}/shell" != "${OUT_DIR}/bin/shell" ]; then
    8. cp -f ${BIN_DIR}/shell ${OUT_DIR}/bin/shell #拷贝 shell 到根文件系统的 /bin下
    9. fi
    10. if [ -e ${BIN_DIR}/tftp ] && [ "${BIN_DIR}/tftp" != "${OUT_DIR}/bin/tftp" ]; then
    11. cp -f ${BIN_DIR}/tftp ${OUT_DIR}/bin/tftp #拷贝 tftp 到根文件系统的 /bin下
    12. fi
    13. fi
    14. cp -f ${LIB_DIR}/* ${ROOTFS_DIR}/lib #将c/c++ .so 库拷贝到根文件系统的 /lib
    15. cp -f ${LIB_DIR}/* ${OUT_DIR}/libs
  • 使用 prepare 创建musl目录,并将 c/c++ 库拷贝到该目录下

    1. prepare: #准备工作,创建 musl 目录,用于拷贝 c/c++ .so库
    2. $(HIDE)mkdir -p $(OUT)/musl
    3. ifeq ($(LOSCFG_COMPILER_CLANG_LLVM), y) #使用clang-9 ,鸿蒙默认用这个编译
    4. $(HIDE)cp -f $$($(CC) --target=$(LLVM_TARGET) --sysroot=$(SYSROOT_PATH) $(LITEOS_CFLAGS) -print-file-name=libc.so) $(OUT)/musl #将C库复制到musl目录下
    5. $(HIDE)cp -f $$($(GPP) --target=$(LLVM_TARGET) --sysroot=$(SYSROOT_PATH) $(LITEOS_CXXFLAGS) -print-file-name=libc++.so) $(OUT)/musl #将C++库复制到musl目录下
    6. else
    7. $(HIDE)cp -f $(LITEOS_COMPILER_PATH)/target/usr/lib/libc.so $(OUT)/musl
    8. $(HIDE)cp -f $(LITEOS_COMPILER_PATH)/arm-linux-musleabi/lib/libstdc++.so.6 $(OUT)/musl
    9. $(HIDE)cp -f $(LITEOS_COMPILER_PATH)/arm-linux-musleabi/lib/libgcc_s.so.1 $(OUT)/musl
    10. $(STRIP) $(OUT)/musl/*
    11. endif
  • tools/scripts/make_rootfs/rootfsimg.sh 生成镜像文件 rootfs_jffs2.img , 调用 mkfs.jffs2来制作 jffs2文件格式的镜像.

    1. ROOTFS_IMG=${ROOTFS_DIR}"_"${FSTYPE}".img"
    2. JFFS2_TOOL=mkfs.jffs2 #linux 下 制作 jffs2镜像文件的工具
    3. WIN_JFFS2_TOOL=mkfs.jffs2.exe #windows 下 制作 jffs2镜像文件的工具
    4. chmod -R 755 ${ROOTFS_DIR}
    5. if [ -f "${ROOTFS_DIR}/bin/init" ]; then
    6. chmod 700 ${ROOTFS_DIR}/bin/init 2> /dev/null
    7. fi
    8. if [ -f "${ROOTFS_DIR}/bin/shell" ]; then
    9. chmod 700 ${ROOTFS_DIR}/bin/shell 2> /dev/null
    10. fi
    11. if [ "${FSTYPE}" = "jffs2" ]; then
    12. if [ "${system}" != "Linux" ] ; then
    13. tool_check ${WIN_JFFS2_TOOL}
    14. ${WIN_JFFS2_TOOL} -q -o ${ROOTFS_IMG} -d ${ROOTFS_DIR} --pagesize=4096
    15. else
    16. tool_check ${JFFS2_TOOL}
    17. ${JFFS2_TOOL} -q -o ${ROOTFS_IMG} -d ${ROOTFS_DIR} --pagesize=4096
    18. fi
    19. elif [ "${FSTYPE}" = "yaffs2" ]; then
    20. # to do
    21. fi
  • 最后用 zip 命令将 rootfs打包成 rootfs.zip,至此完成了鸿蒙根系统的制作过程.

    将增加了一个 out 目录,内容如下:

    1. turing@ubuntu:/home/openharmony/code-v1.1.1-LTS/kernel/liteos_a/out/hi3518ev300$ ls
    2. bin lib liteos liteos.asm liteos.bin liteos.map liteos.sym.sorted musl obj rootfs rootfs_jffs2.img rootfs.zip
    • rootfs便为制作的鸿蒙根文件系统
    • rootfs_jffs2.img为镜像文件,可以烧到flash中.

启动过程

这里列出启动根文件系统的相关代码

  1. STATIC UINT32 OsSystemInitTaskCreate(VOID)
  2. {
  3. UINT32 taskID;
  4. TSK_INIT_PARAM_S sysTask;
  5. (VOID)memset_s(&sysTask, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
  6. sysTask.pfnTaskEntry = (TSK_ENTRY_FUNC)SystemInit;
  7. sysTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
  8. sysTask.pcName = "SystemInit";
  9. sysTask.usTaskPrio = LOSCFG_BASE_CORE_TSK_DEFAULT_PRIO;
  10. sysTask.uwResved = LOS_TASK_STATUS_DETACHED;
  11. #if (LOSCFG_KERNEL_SMP == YES)
  12. sysTask.usCpuAffiMask = CPUID_TO_AFFI_MASK(ArchCurrCpuid());
  13. #endif
  14. return LOS_TaskCreate(&taskID, &sysTask);
  15. }

解读

  • 首先内核开了一个叫SystemInit任务来处理系统初始化代码,任务入口函数为SystemInit
  • SystemInit层层调用到MountPartitions,挂载分区.
    1. SystemInit(void)
    2. ...
    3. OsMountRootfs()
    4. AddPartitions //注册分区驱动程序
    5. MountPartitions()
    6. #define ROOT_DEV_NAME "/dev/spinorblk0"
    7. #define ROOT_DIR_NAME "/"
    8. ret = mount(ROOT_DEV_NAME, ROOT_DIR_NAME, fsType, mountFlags, NULL);//

    设备文件篇 中将详细说明 /dev/spinorblk0 的来源,简单的说就根文件系统烧录在nor flash介质设备的第一个分区上,分区名称/dev/spinorblk0只是表示一个“虚”的设备文件名而已,其背后是个实实在在的文件系统.现将它挂到 /上,结果是nor flash的第一个分区成了根文件系统.

鸿蒙内核源码分析.总目录

v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析 | 51.c.h .o

百万汉字注解.百篇博客分析

百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee| github| csdn| coding >

百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< 51cto| csdn| harmony| osc >

关注不迷路.代码即人生

QQ群:790015635 | 入群密码: 666

原创不易,欢迎转载,但请注明出处.

鸿蒙内核源码分析(根文件系统) | 先挂到`/`上的文件系统 | 百篇博客分析OpenHarmony源码 | v66.01的更多相关文章

  1. v76.01 鸿蒙内核源码分析(共享内存) | 进程间最快通讯方式 | 百篇博客分析OpenHarmony源码

    百篇博客分析|本篇为:(共享内存篇) | 进程间最快通讯方式 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁) | 同样 ...

  2. 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么 | 百篇博客分析OpenHarmony源码 | v16.02

    百篇博客系列篇.本篇为: v16.xx 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么 | 51.c.h .o 内存管理相关篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪 ...

  3. 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基础 | 百篇博客分析OpenHarmony源码 | v68.01

    子曰:"质胜文则野,文胜质则史.文质彬彬,然后君子." <论语>:雍也篇 百篇博客系列篇.本篇为: v68.xx 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基 ...

  4. 鸿蒙内核源码分析(挂载目录篇) | 为何文件系统需要挂载 | 百篇博客分析OpenHarmony源码 | v65.01

    百篇博客系列篇.本篇为: v65.xx 鸿蒙内核源码分析(挂载目录篇) | 为何文件系统需要挂载 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

  5. 鸿蒙内核源码分析(索引节点篇) | 谁是文件系统最重要的概念 | 百篇博客分析OpenHarmony源码 | v64.01

    百篇博客系列篇.本篇为: v64.xx 鸿蒙内核源码分析(索引节点篇) | 谁是文件系统最重要的概念 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么 ...

  6. 鸿蒙内核源码分析(文件系统篇) | 用图书管理说文件系统 | 百篇博客分析OpenHarmony源码 | v63.01

    百篇博客系列篇.本篇为: v63.xx 鸿蒙内核源码分析(文件系统篇) | 用图书管理说文件系统 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

  7. 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 百篇博客分析OpenHarmony源码 | v70.01

    百篇博客系列篇.本篇为: v70.xx 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

  8. 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 百篇博客分析OpenHarmony源码 | v69.01

    百篇博客系列篇.本篇为: v69.xx 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说 ...

  9. 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 百篇博客分析OpenHarmony源码 | v67.01

    百篇博客系列篇.本篇为: v67.xx 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

随机推荐

  1. 题解 P4111 [HEOI2015]小 Z 的房间

    题解 题目大意:给定一个无向图,求它的生成树个数. 一道裸的矩阵树定理,外加一些建图的技巧. 矩阵树定理 对于一个 \(Laplace\) 矩阵,其去掉任意一行后的行列式即为答案. 行列式不会的看这里 ...

  2. 0x800b010a 证书

    无论是装微软的什么应用,只要报这个错误,下载这个证书: http://download.microsoft.com/download/2/4/8/248D8A62-FCCD-475C-85E7-6ED ...

  3. 从元素抽取属性,文本和HTML

    问题 在解析获得一个Document实例对象,并查找到一些元素之后,你希望取得在这些元素中的数据. 方法 要取得一个属性的值,可以使用Node.attr(String key) 方法 对于一个元素中的 ...

  4. Javascript - Vue - 组件

    创建组件 组件是可以重复使用的html容器,可以把它注册到全局的Vue或实例的vue对象上,使它成为全局组件或vue对象的子组件,然后可以将它的html标签插入html文档中.组件的html只能有一个 ...

  5. 【C语言】第1章 程序设计与C语言

    第1章 程序设计与C语言 程序:一组计算机能识别和执行的 指令. 计算机语言:人和计算机交流信息的.计算机和人都能识别的语言 C语言允许用两种注释方式: //:单行注释 可单独占一行 可出现在一行中其 ...

  6. T-SQL - query03_去重查询|模糊查询|排序|分组|使用函数

    时间:2017-09-29 整理:byzqy 本篇仍以"梁山好汉"数据表为例,介绍几个常用的 T-SQL 查询语句: 去重查询,关键字:distinct 使用通配符模糊查询,关键字 ...

  7. Learning ROS: Using a C++ class in Python

    http://wiki.ros.org/ROS/Tutorials/Using%20a%20C%2B%2B%20class%20in%20Python This tutorial illustrate ...

  8. MySQL-表迁移工具的选型-xtrabackup的使用

    1.1. 场景 有的时候test人员可能需要在测试库上比较新的数据,这时候只能是从生产库上面去那了.如果是小表还好实用mysqldump/mysqlpump就可以轻松的解决.但是,如果遇到了大表这将是 ...

  9. Java中Scanner用法总结

    最近在做OJ类问题的时候,经常由于Scanner的使用造成一些细节问题导致程序不通过(最惨的就是网易笔试,由于sc死循环了也没发现,导致AC代码也不能通过...),因此对Scanner进行了一些总结整 ...

  10. (1)RabbitMQ在Docker上安装

    1.简介 在来学习RabbitMQ时候,我觉得很有必要先把它的环境先搭建起来,这样后面的示例才能进行.因为之前自己手动在Linux服务器上搭建过Elasticsearch,当时踩过太多坑了,浪费太多时 ...