开源鸿蒙内核源码分析系列 | 文件概念 | 为什么说一切皆是文件(转载)

开源鸿蒙内核源码分析系列 | 文件概念 | 为什么说一切皆是文件(转载)

本篇开始说文件系统,它是内核五大模块之一,甚至有Linux的设计哲学是”一切皆文件”的说法。所以其重要性不言而喻。搞不清楚文件系统,内核肯定是没整明白。文件系统相关概念巨多,后续将结合内核源码详细阐述,本篇先说清楚源头概念:文件。

什么是文件

不说清楚什么是文件就说不清楚文件系统,更说不清楚内核是如何管理和为什么要这么来管理文件的。

现代操作系统为解决信息能独立于进程之外被长期存储引入了文件,将文件抽象成一个宽泛的概念,把文档、目录(文件夹)、键盘、监视器、硬盘、可移动媒体设备、打印机、调制解调器、虚拟终端,还有进程间通信(IPC)和网络通信等输入/输出资源都看成文件来统一操作。

因为它们都具有共同的读和写共性,一旦具有普适性,可以抽象出理想的模型,通过这个模型,设计工作就会变得简单而有序,API的设计可以化繁为简。用户可以使用通用的方式去访问任何资源,使他们被处理时均可统一使用字节流方式,而差异部分则由相应的中间件做好对底层的适配。

不准确但是形象的例子 Linux 系统把硬件设备映射成文件,例如将摄像头映射为 /dev/video,然后就可以使用基本的函数操作它。用 open() 函数连接设备,再用 read() 函数读取图像,最后用 write() 函数保存图像。而在声卡设备中,read() 函数会变为录音功能,write() 函数变为播放功能。

文件类型

从内核视角将文件分成七种类型:

普通文件 (- regular file)

大家普遍理解的文件属于此类,(如:图片,视频,mp3,ppt,zip == ),这类文件也叫正则文件,当然是无处不在。


turing@ubuntu:/home/tools$ ls -hil
total 12M
1083954 -rwxrwxr-x 1 turing turing 2.3M Feb 18 18:55 gn
1083803 -rw-r--r-- 1 root   root   9.4M Nov 25  2020 hapsigntoolv2.jar
1083802 -rw-r--r-- 1 root   root    58K Nov 25  2020 hmos_app_packing_tool.jar

目录文件(d,directory file)

就是目录或者说文件夹,能用cd命令进入的。它同样无处不在。


turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ ls -lhi
total 68K
1202976 drwxr-xr-x  3 turing turing 4.0K Jun 21 02:38 applications
1173738 drwxr-xr-x 10 turing turing 4.0K Jun 21 02:38 base
1106153 drwxr-xr-x  3 turing turing 4.0K Jun 21 02:38 build

块设备文件(b,block device)

就是存储数据以供系统存取的接口设备,简单而言就是硬盘。例如一号硬盘的代码是 /dev/hda1等文件。属性为 [b] : block device,通常在 /dev目录下能看到它。


turing@ubuntu:/dev$ ls -lhi
total 0
210 brwxr-xr-x  2 root   root         420 Jul 23 18:59 block
337 brwxr-xr-x  2 root   root          80 Jul 23 18:05 bsg

字符设备(c,char device)

字符设备文件:即串行端口的接口设备,例如键盘、鼠标等等。通常在 /dev目录下能看到它。


turing@ubuntu:/dev$ ls -lhi
total 0
124 crw-------  1 root   root     10, 175 Jul 23 18:05 agpgart
373 crw-r--r--  1 root   root     10, 235 Jul 23 18:05 autofs

套接字文件(s,socket)

这类文件通常用在网络数据连接。可以启动一个程序来监听客户端的要求,客户端就可以通过套接字来进行数据通信,最常在 /var/run目录中看到这种文件类型。


turing@ubuntu:/var/run$ ls -lhi
690 srw-rw-rw-  1 root              root     0 Jul 23 18:05 snapd-snap.socket
689 srw-rw-rw-  1 root              root     0 Jul 23 18:05 snapd.socket

管道文件(p,pipe)

管道文件主要用于进程间通讯。比如使用mkfifo命令可以创建一个FIFO文件,启用一个进程A从FIFO文件里读数据,启动进程B往FIFO里写数据,先进先出,随写随读。


turing@ubuntu:/var/run$ ls -lhi
269 prw-------  1 root              root     0 Jul 23 18:05 initctl

符号链接文件(l,symbolic link)

这里说的链接指的是软链接,类似Windows下面的快捷方式。,这类文件非常多,尤其 /bin,/usr/bin目录下最多。


turing@ubuntu:/bin$ ls -lhi
143828 lrwxrwxrwx 1 root root       29 Jul 14 21:51  rmiregistry -> /etc/alternatives/rmiregistry
132128 lrwxrwxrwx 1 root root        4 Jul 14 19:10  rnano -> nano
132131 lrwxrwxrwx 1 root root       29 Jul 14 19:10  rrsync -> ../share/rsync/scripts/rrsync
132132 lrwxrwxrwx 1 root root       21 Jul 14 19:10  rsh -> /etc/alternatives/rsh

文件属性

文件属性,简单的说,有这么几种

  • 权限
  • 所属者
  • 所属组

1173738     drwxr-xr--   10      turing   turing    4.0K        Jun 21 02:38    base
[  0  ]     [  1  ]    [  2 ]   [   3  ]  [  4  ] [   5   ]   [      6      ]  [  7  ]
[vnode编号]  [权限  ]   [硬链接]  [ 拥有者 ] [ 群组 ] [文件容量]   [    修改日期   ]  [文件名]

[vnode编号] 

vnode是文件系统非常重要的一个概念,后续有专门的篇幅结合源码详细说明,每个文件都有唯一的一个编号,跟身份证号一样,全国有100万人叫李伟,大家沟通都是叫李伟,不会喊身份证,并不影响沟通,但到了公安局就只认身份证,只要敢犯罪保准一逮一个准。所以视角不同,关注的点是不一样的。文件管理的机制是一模一样的,普通用户只需记住高清大片放在C:\xx\xx\xx\xx\xxx\xxx\xx.avi下就可以了,不管埋的多深都能翻出来。根本不需要知道vnode.id是多少。但到了内核层面,它操作的都是vnode.id。

[权限] 

对于多用户多群组的系统,就必须有权限来加持文件操作,该栏可以分成以下4个小组。


d, rwx, r-x, r-x
  • 第一个字符d单独成组,这个表示文件类型,这里表示是个目录文件(d,directory file)。
  • 剩下的三个主要由[rwx]组成,r-read, w-write, x-execute, [-]表示占位符,即没权限。
    • 第二组为『文件拥有者的权限』,rwx表示文件拥有者可读可写可执行。
    • 第三组为『同群组的权限』;r-x文件所属组可读可执行但不可写。
    • 第四组为『其他非本群组的权限』,r–其他人可读。
  • 权限除了字母表示外还可以用数字表示。

 r=100=4, w=010=2, x=001=1, -=0 
 rwxr-xr-- 可表示为 
 111101100 = 754

chmod [-R] xxx 文件或目录 :改变文件拥有者 有两种方法可改变文件的权限。

  • 数字法 : chmod -R 777 ohos_config.json。

turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ ls -hli
1103292 -rw-r--r--  1 turing root    350 Jul 21 00:17 ohos_config.json
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ chmod -R 777 ohos_config.json
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ ls -hli
1103292 -rwxrwxrwx  2 turing root    350 Jul 21 00:17 ohos_config.json

777 = (111)(111)(111) = (rwx)(rwx)(rwx)

  • 字母法 :

        u   +(加入)     r   
chmod   g   -(除去)     w   文件或目录
        o   =(设定)     x
        a  
(u)user (g)group (o)others (a)all    

chmod  u=rwx,go=rx   ohos_config.json 结果: rwxr-xr-x
chmod  a+w ohos_config.json           结果: rwxrwxrwx
chmod  u-r+wx ohos_config.json        结果: -wxrwxrwx

[链接] 

链接一栏代表的是硬链接的数量,有硬链接就会有软链接,有什么区别呢。先说清楚为什么会有链接 ?原因是因为同一个文件往往需要被同一个用户或多个用户同时使用,好东西要懂得分享,好人一生平安,大片怎能独享。做个小实验看下二者的区别。


#对ohos_config.json 创建硬链接和软链接
#创建硬链接命令 ln ohos_config.json hard_link
#创建软链接命令 ln -s ohos_config.json hard_link
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ ls -hli
1103292 -rw-r--r--  1 turing root    350 Jul 21 00:17 ohos_config.json
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ ln ohos_config.json hard_link
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ ln -s ohos_config.json soft_link
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ ls -hli
1103292 -rw-r--r--  2 turing root    350 Jul 21 00:17 hard_link
1103292 -rw-r--r--  2 turing root    350 Jul 21 00:17 ohos_config.json
1086100 lrwxrwxrwx  1 turing root     16 Jul 29 01:06 soft_link -> ohos_config.json
  • 硬链接: 记录大片被分享的次数,hard_link和ohos_config.json的 vnode_id都是1103292,二者内容一模一样。但是和没创建之前的区别是[链接]数,也叫引用数,由1变成了2 。而新增加的这次引用数就是 hard_link导致的
  • 软链接: 是单独创建了另一个文件,有独立的vnode_id,只是这个文件的内容指向了ohos_config.json而已,这样做有什么好处呢?举个例子就明白了。

某酒店301房住着一位美女,想进房间就需要有钥匙,只要去敲门就给你一把钥匙,离开了钥匙归还,硬链接就是301房间发出去的钥匙数量。那软链接是什么呢?是旁边的302房间, 进入302房间里面只有一张纸条上面写着”去301房间敲门,你懂的”。明白了吗?虽然绕了个湾,但换来的是非常灵活的操作,公安来了怎么办?只需把纸条内容改成 “去404房间敲门。404房间在开民主生活会,啥问题也没有。

在应用层是大量的软链接在被使用,比如 版本切换,升级软链接就非常的方便。

[拥有者]

chown :改变文件拥有者 chown [-R] 账号名称 文件或目录 chown [-R] 账号名称:用户组名称 文件或目录。


turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ll
-rw-r--r--  2 root   root    350 Jul 21 00:17 ohos_config.json
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$sudo chown -R turing:turing ohos_config.json
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ll
-rw-r--r--  2 turing   turing    350 Jul 21 00:17 ohos_config.json

[群组]

chgrp [-R] 用户组名称 文件或目录。


turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ll
-rw-r--r--  2 root   root    350 Jul 21 00:17 ohos_config.json
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$sudo chgrp -R turing ohos_config.json
turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ll
-rw-r--r--  2 root   turing    350 Jul 21 00:17 ohos_config.json

[修改日期]

用stat命令可以查看一个文件的信息。


turing@ubuntu:/home/openharmony/code-v1.1.1-LTS$ stat ohos_config.json 
File: ohos_config.json
Size: 350         Blocks: 8          IO Block: 4096   regular file
Device: 805h/2053d  Inode: 1103292     Links: 2
Access:(0644/-rw-r--r--)  Uid:( 1000/  turing)   Gid:(    0/    root)
Access: 2021-07-24 02:07:21.683190622 -0700
Modify: 2021-07-21 00:17:34.733766830 -0700
Change: 2021-07-29 01:20:14.314343117 -0700
Birth: -

mtime(modify time):修改时间是文件内容最后一次被修改的时间。比如:vim操作后保存文件。ls -l列出的就是这个时间

atime(access time):访问时间是读一次文件的内容,这个时间就会更新。比如more、cat等命令。ls、stat命令不会修改atime

ctime(change time):状态改动时间,是该文件的vnode节点最后一次被修改的时间,通过chmod、chown命令修改一次文件属性,这个时间就会更新

了解了文件后,再看文件系统。

初始化

Monastic Library painted by Richard Linderum

什么是文件系统? 看看维基百科的解释:

  • 计算机的文件系统是一种存储和组织计算机数据的方法,它使得对其访问和查找变得容易,文件系统使用文件和树形目录的抽象逻辑概念代替了硬盘和光盘等物理设备使用数据块的概念,用户使用文件系统来保存数据不必关心数据实际保存在硬盘(或者光盘)的地址为多少的数据块上,只需要记住这个文件的所属目录和文件名。在写入新数据之前,用户不必关心硬盘上的那个块地址没有被使用,硬盘上的存储空间管理(分配和释放)功能由文件系统自动完成,用户只需要记住数据被写入到了哪个文件中。
  • 文件系统通常使用硬盘和光盘这样的存储设备,并维护文件在设备中的物理位置。但是,实际上文件系统也可能仅仅是一种访问资料的界面而已,实际的数据是通过网络协议(如NFS、SMB、9P等)提供的或者内存上,甚至可能根本没有对应的文件(如proc文件系统)。
  • 严格地说,文件系统是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型。

简单地说,文件系统是操作系统中负责管理持久数据的子系统,基本数据单位是文件,它的目的是对磁盘上的文件进行组织管理,组织的方式不同,就会形成不同的文件系统。

计算机文件系统很像我们大学的智能图书管理系统,你去图书馆借书,只需在屏幕上选中要借的书本列表提交后会自动把书提取出来放到你的面前,你并不需要知道书本是如何被检测出来,它真实的摆放在几号馆的几号书架的第几排。每个大学都有一套独立的图书管理方式,有的按分类,有的按科目,有的按地域,有的按时间。 即便都按分类来的,分类的方法也会不一样,而且管理1万册很高效的方法却不一定对1000万册也同样高效,但衡量方法的好坏无非是看以下几个要素:

  • 增删改查的速度要快,
  • 存储空间要小,空间回收算法要好,
  • 安全机制,什么人有什么权限对这本书执行什么操作。
  • 各种操作记录,书的入库时间,最后的借阅时间,修改时间等等都要记录在案。

计算机的文件系统因为技术的更新,因为各个公司的利益保护等等诸多原因,肯定也是百花齐放的,跟计算机语言一样,绝大多数语言的发明只是为了解决某个实验室或者某个公司当下遇到的问题,很多压根没想那么远,标准和规范那都是后话,取决于你的市场规模和背后的金主。统一标准是好,但真的很难。世界语出现很多年了,但又有几个人去学。联合国存在也很多年了,就不听你,不交会费,你能有啥办法。经济基础决定上层建筑,这句话初中政治就反复讲,当初不理解,现在是彻底明白了,终究是要靠实力说话的。

所以不要去奇怪为什么会有这么多语言要学,这么多前端,后台框架要搞,互联网技术版图还处于群雄争霸时代,巨头林立,身处其中的码农都是绞肉机里的肉。而且这种分裂的趋势会愈演愈烈, PC时代 Windows 一统天下, 手机时代 苹果,Android 楚汉相争,万物互联时代 鸿蒙,苹果,Fuchsia 很可能是三分天下。新生代不断崛起,老贵族不下牌桌。

文件系统按类型可分成以下四种:

  • 磁盘文件系统 : 是一种设计用来利用数据存储设备来保存计算机文件的文件系统,最常用的数据存储设备是磁盘驱动器,可以直接或者间接地连接到计算机上。例如:FAT、exFAT、NTFS、HFS、HFS+、ext2、ext3、ext4、ODS-5、btrfs、XFS、UFS、ZFS。有些文件系统是行程文件系统(也有译作日志文件系统)或者追踪文件系统。
  • 闪存文件系统 : 闪存文件系统是一种设计用来在闪存上储存文件的文件系统。随着移动设备的普及和闪存容量的增加,这类文件系统越来越流行。尽管磁盘文件系统也能在闪存上使用,但闪存文件系统是闪存设备的首选,理由如下:
    • 擦除区块:闪存的区块在重新写入前必须先进行擦除。擦除区块会占用相当可观的时间。因此,在设备空闲的时候擦除未使用的区块有助于提高速度,而写入数据时也可以优先使用已经擦除的区块。
    • 随机访问:由于在磁盘上寻址有很大的延迟,磁盘文件系统有针对寻址的优化,以尽量避免寻址。但闪存没有寻址延迟。
    • 写入平衡(Wear levelling):闪存中经常写入的区块往往容易损坏。闪存文件系统的设计可以使数据均匀地写到整个设备。 日志文件系统具有闪存文件系统需要的特性,这类文件系统包括JFFS2和YAFFS。也有为了避免日志频繁写入而导致闪存寿命衰减的非日志文件系统,如exFAT。
  • 伪文件系统 : 启动时动态生成的文件系统,包含有关当前正在运行的内核的许多信息、配置和日志,由于它们放置在易失性存储器中,因此它们仅在运行时可用,而在关闭时消失。这些伪文件常挂载到以下目录: sysfs (/sys), procfs (/proc), debugfs (/sys/kernel/debug), configfs (/sys/kernel/config), tracefs (/sys/kernel/tracing), tmppfs (/dev/shm, /run, /sys/fs/cgroup, /tmp/, /var/volatile, /run/user/), devtmpfs (/dev)
    • procfs 是 进程文件系统 (file system) 的缩写,用于通过内核访问进程信息。这个文件系统通常被挂载到 /proc 目录。由于 /proc 不是一个真正的文件系统,它也就不占用存储空间,只是占用有限的内存。
    • tmpfs(temporary file system) 是类Unix系统上暂存档存储空间的常见名称,通常以挂载文件系统方式实现,并将资料存储在易失性存储器而非永久存储设备中。所有在tmpfs上存储的资料在理论上都是暂时借放的,那也表示说,文件不会创建在硬盘上面。一旦重启,所有在tmpfs里面的资料都会消失不见。
    • Sysfs 是Linux 2。6所提供的一种虚拟文件系统。这个文件系统不仅可以把设备(devices)和驱动程序(drivers)的信息从内核输出到用户空间,也可以用来对设备和驱动程序做设置。sysfs的目的是把一些原本在procfs中的,关于设备的部分,独立出来,以‘设备层次结构架构’(device tree)的形式呈现。
    • devtmpfs 是在 Linux核心启动早期建立一个初步的 /dev,令一般启动程序不用等待 udev,缩短GNU/Linux的开机时间。将设备也看成为文件,突出了Linux文件系统的特点:一切皆文件或目录。
  • 网络文件系统: NFS,(Network File System)是一种将远程主机上的分区(目录)经网络挂载到本地系统的一种机制,是一种分布式文件系统,力求客户端主机可以访问服务器端文件,并且其过程与访问本地存储时一样,它由Sun公司开发,于1984年发布。它的特点是将网络也看出了文件,再次体现一切皆文件的说法。

对于开源鸿蒙内核,JFFS2,YAFFS,tmpfs,procfs,FAT,NTFS,ZFS将是后续章节的重点。

百文说内核 | 抓住主脉络

子曰:“诗三百,一言以蔽之,曰‘思无邪’。”——《论语》:为政篇。百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在开源鸿蒙内核源码加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了。
百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。

与代码有bug需不断debug一样,文章和注解内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx 代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。百篇博客系列思维导图结构如下:

根据上图的思维导图,我们未来将要和大家一一分享以上大部分关键技术点的博客文章。

百万汉字注解.精读内核源码

如果大家觉得看文章不过瘾,想直接撸代码的话,可以去下面四大码仓围观同步注释内核源码:

gitee仓

https://gitee.com/weharmony/kernel_liteos_a_note

github仓 :

https://github.com/kuangyufei/kernel_liteos_a_note

codechina仓

https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note

coding仓

https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files

写在最后

我们最近正带着大家玩嗨OpenHarmony。如果你有用OpenHarmony开发的好玩的东东,或者有对OpenHarmony的深度技术剖析,想通过我们平台让更多的小伙伴知道和分享的,欢迎投稿,让我们一起嗨起来!有点子,有想法,有Demo,立刻联系我们:

合作邮箱:zzliang@atomsource.org