本篇关键词:、、、

下载 >> 离线文档.鸿蒙内核源码分析(百篇博客分析.挖透鸿蒙内核).pdf

文件系统相关篇为:

关于文件系统的介绍已经写了三篇,但才刚刚开始,其中的 [文件系统篇] 一定要阅读,用生活中的场景去解释计算机各模块设计的原理和运行机制是整个系列篇最大的特点,计算机文件系统相关概念是非常的多的,若不还原其本质,不跳出这些概念去看问题是很难理解它为什么要弄这么些东东出来让你头大。 反之,如果搞明白了这些概念背后的真相你想忘记它们都很难,问题是经不起追问的, 多追问几个为什么就会离本源越来越近。

前几篇中追问了以下几个问题:

  • 对内核来说inode真的是唯一的吗? 答案是否定的,使用电脑的经验告诉我们,当把电脑硬盘拆下来挂到其他电脑上时,里面的数据一样能访问,并没有让你一切重来,而inode是存放硬盘上的,你没有办法让已编好序号的inode按你的逻辑重排,这不合理更不科学。 所以结论是inode的全局唯一性不是不想做,而是压根臣妾做不到啊。inode唯一性仅限于某个文件系统的内部。
  • 经验还告诉我们硬盘可以有多个分区,每个分区可以被格式化成不同的文件系统。(例如:C盘:NTF,D盘FAT32,E盘ext),数据可以相互拷贝,毫无障碍。不同的文件系统是如何实现文件迁移到呢 ? 具体实现细节是怎样的 ?

如果想明白了这些问题, 就能逆向倒推为什么要有目录,为什么需要挂载使用, 为什么需要根文件系统。一切将是水到渠成 。 先说目录,从内核视角看目录可不能像普通老百姓从用户视角去看,目录是为了屏蔽文件系统之间的差异而设计出来的概念,也就说必须在inode的局部唯一性之上存在一个全局唯一性才能解决统一性问题。目录从更大尺度上去兼容并蓄各文件系统。

那它是如何解决的呢?

  • 首先各个文件系统记录了自己内部目录层级关系的,这个在 文件系统篇 | 目录项 中已经说过了。 这种关系是绝对的但也是相对的,绝对是对内,相对是对外。 例如: A文件系统内部如下:

    ├─古龙系列 inode id : 789
    │  ├─小李飞刀 inode id : 56
    │  ├─楚留香 inode id : 342
    │  └─陆小凤 inode id : 432
    └─金庸系列 inode id : 5567
        ├─倚天屠龙记 inode id : 89
        ├─射雕英雄传 inode id : 1212
        └─笑傲江湖 inode id : 567843
    
    1
    2
    3
    4
    5
    6
    7
    8

    B文件系统内部如下:

    ├─席绢系列  : inode id : 87 
    │  ├─上错花轿嫁对郎 : inode id : 89 
    │  ├─吻上你的心 : inode id : 789 
    │  └─红袖招 : inode id : 56 
    └─琼瑶系列 : inode id : 321 
        ├─在水一方 : inode id : 234 
        ├─梅花三弄 : inode id : 5678 
        ├─烟雨濛濛 : inode id : 987 
        └─还珠格格 : inode id : 23 
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    其中78989两个文件系统中都用到了,但它们在内部是唯一的。在A文件系统中通过 789 就能找到 56342432,并且能得到相对路径: 古龙系列/小李飞刀,古龙系列/楚留香 。也就是说拿着inode只要进入了本文件系统地盘,那都不叫事,事都能给你办的妥妥的。 那如何才能进入而且不会搞错呢?

挂载目录

答案就是: 挂载目录,也叫挂载点,集体统一指挥的前提是需要先回归集体。如果已经有一颗目录树,将你们的目录树挂上来形成一颗更大的树不就统一了吗? 例如已有:

├─小说系列 inode id : 2
│  ├─武侠小说 inode id : 13
│  ├─言情小说 inode id : 14
1
2
3

其实它也是个文件系统,叫根文件系统, 它的 inode也是独立的, 并且能得到相对路径 小说系列/武侠小说小说系列/武侠小说 通过两个 mount动作, 将它变成如下所示

├─小说系列 (根文件系统)
    ├─武侠小说 (根文件系统)
    │  ├─古龙系列 (A文件系统)
    │  │  ├─小李飞刀
    │  │  ├─楚留香
    │  │  └─陆小凤
    │  └─金庸系列 (A文件系统)
    │      ├─倚天屠龙记
    │      ├─射雕英雄传
    │      └─笑傲江湖
    └─言情小说 (根文件系统)
        ├─席绢系列 (B文件系统)
        │  ├─上错花轿嫁对郎
        │  ├─吻上你的心
        │  └─红袖招
        └─琼瑶系列 (B文件系统)
            ├─在水一方
            ├─梅花三弄
            ├─烟雨濛濛
            └─还珠格格
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

哦,原来整颗目录树是由这三个文件系统像搭积木一样拼接起来。而两个文件系统的衔接点,必然会产生一个新的概念出来, 这个概念就是 挂载点,也叫 挂载目录

Mount

可以猜测到的是挂载点的描述结构体中必有两个文件系统接驳点inode的信息,挂钩和脱钩的操作也只属于它专有。具体如下:

//挂载操作
struct MountOps {
    int (*Mount)(struct Mount *mount, struct Vnode *vnode, const void *data);//挂载
    int (*Unmount)(struct Mount *mount, struct Vnode **blkdriver);//卸载
    int (*Statfs)(struct Mount *mount, struct statfs *sbp);//统计文件系统的信息,如该文件系统类型、总大小、可用大小等信息
};
struct Mount {
    LIST_ENTRY mountList;              /* mount list */			 //通过本节点将Mount挂到全局Mount链表上
    const struct MountOps *ops;        /* operations of mount */ //挂载操作函数	
    struct Vnode *vnodeBeCovered;      /* vnode we mounted on */ //要被挂载的节点 即 /bin1/vs/sd 对应的 vnode节点
    struct Vnode *vnodeCovered;        /* syncer vnode */		 //要挂载的节点	即/dev/mmcblk0p0 对应的 vnode节点
    LIST_HEAD vnodeList;               /* list of vnodes */		//链表表头
    int vnodeSize;                     /* size of vnode list */	//节点数量
    LIST_HEAD activeVnodeList;         /* list of active vnodes */	//激活的节点链表
    int activeVnodeSize;               /* szie of active vnodes list *///激活的节点数量
    void *data;                        /* private data */	//私有数据,可使用这个成员作为一个指向它们自己内部数据的指针
    uint32_t hashseed;                 /* Random seed for vfs hash */ //vfs 哈希随机种子
    unsigned long mountFlags;          /* Flags for mount */	//挂载标签
    char pathName[PATH_MAX];           /* path name of mount point */	//挂载点路径名称  /bin1/vs/sd
    char devName[PATH_MAX];            /* path name of dev point */		//设备名称 /dev/mmcblk0p0
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

解读

  • mountList : 挂载点由双向链表全局统一管理

  • vnodeBeCovered:,记录挂到根文件系统的哪个节点上。

  • vnodeCovered: 设备也是一种文件,也被统一管理,统一在/dev目录下,内核会给设备的每个分区分配一个vnode节点,一个分区对应一个文件系统,设备文件后续有专门的介绍,此处不展开。

  • vnodeList: 指的是A/B文件系统的节点链表,由挂载点结构体记录。

  • activeVnodeList: A 文件系统节点的使用情况,统一由双向链表管理。

  • activeVnodeSize: A 文件系统已被使用的节点数

  • data 这是文件系统的私有数据,跟 索引节点篇 | Vnode -> data 一样理解。

  • pathName :这个很重要,记录了小说系列/武侠小说,因为文件的绝对路径是拼接起来的,以小说系列/武侠小说/古龙系列/小李飞刀这个完整的路径来说,它是由 小说系列/武侠小说(根文件系统提供) + 古龙系列/小李飞刀(A文件系统提供) 这两部分拼成的。

  • devName :一般名称类似于mmcblk0p0 = mmc + block0 + Partition0

    • mmc: MultiMediaCard 可理解为硬盘
    • block0: 0号块设备
    • Partition:0号分区,一个分区上安装一个文件系统。
  • MountOps ops: 每个文件系统挂载方式是不用的,都需要实现这几个接口(挂载,卸载,统计)。

    // 文件系统 proc 对 MountOps 接口实现
    const struct MountOps procfs_operations = {
        .Mount = VfsProcfsMount,//装载
        .Unmount = NULL,
        .Statfs = VfsProcfsStatfs,//统计信息
    };
    //文件系统 fat 对MountOps 接口实现
    struct MountOps fatfs_mops = {
        .Mount = fatfs_mount,
        .Unmount = fatfs_umount,
        .Statfs = fatfs_statfs,
    };
    //文件系统 jffs 对MountOps 接口实现
    const struct MountOps jffs_operations = {
      .Mount = VfsJffs2Bind,
      .Unmount = VfsJffs2Unbind,
      .Statfs = VfsJffs2Statfs,
    };
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

问题

上面提到 挂载就需要一个已经存在的文件系统提供目录,也就是根文件系统,但根文件系统又是怎么来的呢?

百文说内核 | 抓住主脉络

  • 百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切。
  • 与代码需不断debug一样,文章内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx 代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。
  • 百文在 < 鸿蒙研究站 | 开源中国 | 博客园 | 51cto | csdn | 知乎 | 掘金 > 站点发布,百篇博客系列目录如下。

按功能模块:

基础知识 进程管理 任务管理 内存管理
双向链表
内核概念
源码结构
地址空间
计时单位
优雅的宏
钩子框架
位图管理
POSIX
main函数
调度故事
进程控制块
进程空间
线性区
红黑树
进程管理
Fork进程
进程回收
Shell编辑
Shell解析
任务控制块
并发并行
就绪队列
调度机制
任务管理
用栈方式
软件定时器
控制台
远程登录
协议栈
内存规则
物理内存
内存概念
虚实映射
页表管理
静态分配
TLFS算法
内存池管理
原子操作
圆整对齐
通讯机制 文件系统 硬件架构 内核汇编
通讯总览
自旋锁
互斥锁
快锁使用
快锁实现
读写锁
信号量
事件机制
信号生产
信号消费
消息队列
消息封装
消息映射
共享内存
文件概念
文件故事
索引节点
VFS
文件句柄
根文件系统
挂载机制
管道文件
文件映射
写时拷贝
芯片模式
ARM架构
指令集
协处理器
工作模式
寄存器
多核管理
中断概念
中断管理
编码方式
汇编基础
汇编传参
链接脚本
内核启动
进程切换
任务切换
中断切换
异常接管
缺页中断
编译运行 调测工具
编译过程
编译构建
GN语法
忍者无敌
ELF格式
ELF解析
静态链接
重定位
动态链接
进程映像
应用启动
系统调用
VDSO
模块监控
日志跟踪
系统安全
测试用例

百万注源码 | 处处扣细节

  • 百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。

  • < gitee | github | coding | gitcode > 四大码仓推送 | 同步官方源码。

关注不迷路 | 代码即人生

期间不断得到小伙伴的支持,有学生,有职场新人,也有老江湖,在此一并感谢,大家的支持是前进的动力。尤其每次收到学生的赞助很感慨,后生可敬。 >> 查看捐助名单

据说喜欢 点赞 + 分享 的,后来都成了大神。😃