forked from 0voice/kernel_awsome_feature
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f5377ee
commit 4719879
Showing
1 changed file
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
|
||
|
||
> **原文链接:** https://www.qiyacloud.cn/2021/05/2021-05-24/ | ||
## 前情提要 | ||
|
||
来一个硬核系列,得益于 Linux 一切皆文件的哲学,把文件系统玩转的飞起。文件系统所有人都听过,都用过,但是就很少有人深究。 | ||
|
||
对于文件系统,大家的态度可能是两个极端,要么就是觉得好深奥,好牛,你竟然懂这玩意!要么就是,文件系统是什么鬼?不就是那个。。。我在 Linux 用过无数次的。这玩意还用得着讲? 这两种态度可能都不合适,文件系统作为一个深入我们生活的事物,我们不应去忽略它,也不要去抬高或者贬低。我们应该要去了解它,打破对它的恐惧,因为恐惧是对未知事物产生的一种情绪。平视它,了解清楚脉络,从而掌握它。 小孩在为什么总是学习东西很快?因为他们都是从形到意,先直观的摸到,看到,嗅到,吃到,先感受到“形”,然后我们教导他这些东西是的含义。他们很快就接受了。 我们这个自制文件系统,就是想从形意结合,让读者朋友能够跟随着笔者一起经历一次文件系统由 0 到 1 的过程,构建好知识框架,后续的深造将会得心应手。 好,话不多说,我们先从什么是文件系统讲起,简单介绍一些探索文件系统的基础知识。 | ||
|
||
## 探索文件系统 | ||
|
||
### 查看现有文件系统实例 | ||
|
||
Linux 文件系统相比大家都使用过。大家在自己的 Linux 上机器上执行 `mount` 命令就能看到当前系统上挂载的所有文件系统: | ||
|
||
```sh | ||
mount | ||
``` | ||
|
||
示例如下: | ||
|
||
```sh | ||
root@localhost:~# mount | ||
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel) | ||
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) | ||
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel) | ||
/dev/mapper/cl-root on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota) | ||
.... | ||
``` | ||
|
||
比如通过这一行信息我们能看出来: | ||
|
||
```sh | ||
sysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime) | ||
``` | ||
|
||
信息拆解分析: | ||
|
||
- `sysfs`:文件系统**名称**; | ||
- `/sys` :文件系统目录**挂载点**; | ||
- `sysfs`:文件系统**类型** | ||
- `(ro,nosuid,nodev,noexec,relatime)`:挂载参数 | ||
|
||
这里蕴含的重要信息: | ||
|
||
- 同一个文件系统类型是可以创建多个实例的,挂载在不同的挂载点,就跟面向对象里的类和实例的关系; | ||
- **基础知识点:挂载点必须是目录**; | ||
|
||
其实,`mount` 这个命令很强大,不仅能 list 所有的文件系统,还能挂载文件系统。如下: | ||
|
||
**挂载文件系统**: | ||
|
||
```sh | ||
# 把已经格式化好的 /dev/sdb1 盘挂到 /mnt 目录上 | ||
mount -t ext4 /dev/sdb1 /mnt/ | ||
``` | ||
|
||
**对应卸载文件系统命令**: | ||
|
||
```sh | ||
# 卸载 /mnt 的挂载点 | ||
umount /mnt | ||
``` | ||
|
||
### 查看目录挂载的文件系统用量 | ||
|
||
`mount` 命令能看到所有的挂载列表,但是如果你想要看到所有文件系统的使用情况,则需要另一个命令:`df`。`df` 命令用来查看当前操作系统挂载的文件系统和**使用情况**: | ||
|
||
```sh | ||
df -Tha | ||
``` | ||
|
||
- -T 参数能够让你看到所有的文件系统实例的类型; | ||
- -h 参数能够以更符合人类的友好的形式展示数据; | ||
- -a 参数展示所有的文件系统,包括 0 Blocks 的文件系统(默认是会过滤掉的); | ||
|
||
示例如下: | ||
|
||
```sh | ||
root@localhost:~# df -ahT | ||
Filesystem Type Size Used Avail Use% Mounted on | ||
sysfs sysfs 0 0 0 - /sys | ||
proc proc 0 0 0 - /proc | ||
/dev/mapper/cl-root xfs 17G 11G 7.0G 60% / | ||
... | ||
``` | ||
|
||
注意,如果 `df` 没有加 `-a` 参数,类似于上面 sysfs,proc 这种用量 0 的会被过滤掉。这也是 `mount` 和 `df` 两个命令默认显式信息的区别。 | ||
|
||
### 查看文件系统挂载配置 | ||
|
||
文件系统挂载可以通过 `mount` 命令直接挂载,但是 `mount` 命令挂载并没有持久化,关机重启就没了。所以想要关机重启之后,还能自动挂载到指定目录,那么就要把挂载规则写到 `/etc/fstab` 文件中,`fstab` 就是 fs table 的缩写,很容易理解。 | ||
|
||
操作系统在启动的时候,就会解析这个文件,并按照这个文件里的配置,自动挂载文件系统了。 | ||
|
||
如下: | ||
|
||
```sh | ||
root@localhost:~# cat /etc/fstab | ||
|
||
/dev/mapper/cl-root / xfs defaults 0 0 | ||
UUID=600e3771-af4a-48ca-a557-02204c9a48a5 /boot ext4 defaults 1 2 | ||
/dev/mapper/cl-swap swap swap defaults 0 0 | ||
``` | ||
|
||
fstab 的文件格式: | ||
|
||
```sh | ||
<设备标识> <挂载目录> <文件系统类型> <挂载参数> <dump选项> <fsck选项> | ||
``` | ||
|
||
从左到右参数拆解: | ||
|
||
- 设备标识:能够标识到唯一的文件系统所在的设备,这里可以是设备路径,也可以是 LABEL,或者 UUID; | ||
- 挂载目录:文件系统挂载的目录点; | ||
- 文件系统类型:比如 ext4,ext2,xfs 之类的; | ||
- 挂载参数:可以填 defaults,也可以精细化配置,比如只读还是可写(rw/ro),同步刷盘还是异步(async/sync),等等; | ||
- dump选项:让你能控制文件系统备份的频率,0 表示不备份; | ||
- fsck选项:让你控制是否开机用 fsck 自检,0 表示不要; | ||
|
||
### 查看内核支持的文件系统 | ||
|
||
这个直接去看内核模块即可: | ||
|
||
```sh | ||
ls /lib/modules/${kernel_version}/kernel/fs/ | ||
``` | ||
|
||
不同的 Linux 发行版略有不同,比如,centos 一般为: | ||
|
||
```sh | ||
ls -l /lib/modules/4.18.0-80.el8.x86_64/kernel/fs/ | ||
``` | ||
|
||
ubuntu 一般为: | ||
|
||
```sh | ||
ls -l /lib/modules/4.4.0-142-generic/kernel/fs/ | ||
``` | ||
|
||
在对应的目录找到对应的 .ko 模块,比如 `ext4.ko` ,如果想看内核已经加载的内核模块,可以调用 `lsmod` 看到。 | ||
|
||
**简单普及一下 .ko 模块的知识:** | ||
|
||
**ko** 其实是 **kernel object** 的缩写,这类文件存在的意义其实和用户态的 .so 库类似,都是为了模块化的编程实践。内核把核心主干框架之外的功能拆解成模块,需要的时候就加载 ko 模块,不需要的时候卸载即可。这样带来的好处就是方便开发和使用,保持内核的核心代码极度精炼。 | ||
|
||
类似于文件系统,硬件驱动等等,都是以这种形式来加载使用的。 | ||
|
||
## 开发文件系统为什么难? | ||
|
||
为什么文件系统的开发大家会觉得非常难?原因其实不在于实现,而在于调试和排障,因为早期文件系统的开发只能在内核之中,这个带来了非常高的门槛。 | ||
|
||
### 内核文件系统 | ||
|
||
因为在此之前我们看到了文件系统是位于内核之中, vfs 之下,块存储模块之上的一个位置。对外呈现文件存储实现,对下管理裸块设备。划重点,文件系统是位于内核的一个模块,那就可以理解了,内核模块的开发之所以艰难就是难在调试和排障,用户态的程序你可以随意 debug,出问题最多也就是 panic,coredump,内核态的程序出了文件就是宕机,所有现场都丢失,你只能通过日志,kdump 等手段来排查。并且内核态程序的编写是要注意非常多的规范的,比如内存分配,比用户态的要谨慎的多。 | ||
|
||
![image](https://user-images.githubusercontent.com/87457873/154071883-b9c41e8b-16ce-4a80-a8d3-33792987a7c1.png) | ||
|
||
那怎么办?我们本次的目标是要自制实现一个极简的文件系统,但总不能带大家趟一次内核开发的坑吧!那可是要吓退 99% 的小伙伴。 | ||
|
||
有办法的,内核开发者考虑到了这个问题,又考虑到文件系统的需求是千变万化的,所以提供了一种手段,把 IO 路径导向用户态,由用户态程序捕获到 IO ,从而实现文件的存储,这个机制就叫 FUSE 机制。 | ||
|
||
### FUSE 文件系统 | ||
|
||
作为系列第一篇,我们不讲 FUSE 的实现,而是通过一个动画来演示 IO 的旅途: | ||
|
||
![image](https://user-images.githubusercontent.com/87457873/154071911-de196f5e-2a0c-41d8-ab3d-6f4b07412d5f.png) | ||
|
||
这里的路径做了一些简化,简化了用户态之上的逻辑处理,以后详细解释。 | ||
|
||
## 总结 | ||
|
||
本篇文章是为后续铺垫一些基础知识,从**形**的方面,系统介绍了一些命令,告诉你文件系统怎么配置,怎么挂载,怎么查看,怎么获取到使用详情。这些基础知识在后面自制文件系统的时候,都要用上。这些 Linux 命令**都是帮助我们从文件系统的外围去用,去摸,去嗅,从而再去深入理解**。 | ||
|
||
我们目标不止如此,我们是要亲手做一个文件系统,动手做过一遍的东西,你对它理解也将会突飞猛进,更加深刻。 | ||
|
||
下面总结一下上面的基础以上的知识: | ||
|
||
1. `mount` 用来列举查看当前所有文件系统实例,也能支持挂载命令(但 `mount` 挂载不会持久化,重启就没了),`umount` 用来卸载; | ||
2. `/etc/fstab` 是用来配置文件系统挂载规则的,是持久化的配置,重启不丢; | ||
3. `df -aTh` 用来查看每个文件系统挂载目录的详情,包括空间使用量,总量,挂载点等信息; | ||
4. 内核模块的功能以 `ko` 文件的形式体现,在 `/lib/modules/${kernel_version}/kernel/fs/` 目录可以看到支持的内核文件系统模块,`lsmod` 命令可以看到已经加载的内核模块; | ||
5. 文件系统开发之所以难?是因为之前在内核中开发,内核开发最难的在于调试和排障手段不方便。那文件系统还有出路吗?有,奇伢带你**自制一个极简的文件系统**,基于 Linux 系统使用纯 Go 语言来做哦,敬请期待后续,自己动手,理解更深; | ||
|