在 Linux 中一切皆文件

这是我们经常能听到很多大佬说的一句话,那为什么说 Linux 中都是文件呢?这句话究竟代表着什么具体的含义呢?在操作系统中,文件系统又扮演着一个什么样的角色?作为一个普通的开发者,我们究竟对文件系统要有怎么样的认识?今天我们就来看看这个大哥 —— 文件系统

文件

在认识文件系统之前,首先来看看我们的文件是什么。当我们在 Linux 系统上创建的一个文件,究竟有哪些东西?是只有文件内容本身吗?

文件的两个数据结构

首先,来认识今天的第一个重点:

  • index node: 索引节点
  • directory entry: 目录项

索引节点

当我们创建一个文件的时候,其实不仅仅只是创建了文件本身的内容,还有很多相关的属性也被创建了,如:这个文件的访问权限,修改时间等等。我们的索引节点(index node) 就是我们常说的 inode,这个结构中就存放了文件的必要属性,也被称为文件的元数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
* Structure of an inode on the disk
*/
struct ext4_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size_lo; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Inode Change time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
__le32 i_blocks_lo; /* Blocks count */
__le32 i_flags; /* File flags */
....
....

上面就是 ext4_inode 的一些字段。

目录项

除了文件本身,我们也需要知道文件存放的位置,也就是目录。

目录项(directory entry),也就是我们常说的 dentry,用来记录文件名字、索引节点指针,目录项是有内核维护的数据结构,不存放在磁盘,而是缓存在内存。

所以,也就是说,当我们创建了一个文件,并非只是创建了文件内容本身,由于它需要存储在一个位置上并后续还需要对它进行操作,我们势必需要知道它的一些信息,这些信息可以帮助我们找到这个文件,修改的情况等,这对于文件系统的管理来说是非常有必要的。

虚拟文件系统

file-system-vfs.png
虚拟文件系统(Virtual File System)就是 VFS,因为文件系统种类很多,操作系统在中间做了一层封装,用户只要面向 VFS 提供的统一接口进行操作就可以了,无需关系底层的文件系统实现。

具体的文件系统分为:

  • 磁盘文件系统:ext4/xfs/btrfs/zfs
  • 内存文件系统:/proc/sys
  • 网络文件系统:NFSSMB

注意文件系统使用时需要挂载(mount)到某个目录才能使用

具体文件系统

首先,文件系统,顾名思义肯定是一个系统,它最大的目标就是帮助我们 “合理合法” 的管理文件,无论我们的文件是大是小,是多是少,它都应该尽可能的帮助我们有秩序的管理起来,方便我们的查找和使用。

首先我们来分类认识一些具体的文件系统 (如果你已经使用过一段时间 Linux 系统,其实应该会对这些文件系统的名字有点熟悉)

磁盘文件系统

磁盘文件系统是我们经常使用到的文件系统,比如:ext4/xfs/btrfs/zfs,其中 ext4 接触的更多。

我当时第二次接触到(第一次只是在课本上)这些文件系统是在攒 NAS 的时候,安装时让我选择文件系统,当时还不理解这些文件系统有什么区别,不知是不是有跟我一样的小伙伴

ext4

从 ext2 到 ext3 到 ext4,不断的进化,不断的成熟,它有这些特点:

  • 支持的最大文件和最大分区大小分别达到了 16TB 和 1EB
  • 支持 Extents
  • 支持日志(Journal)校验码
  • inode 数量固定,过多的小文件会爆掉

xfs

  • inode 动态分配,从而不受 inode 数量的限制
  • 更大的 xattr(extended attributes)空间
  • 不支持文件创建时间
  • 不支持无日志模式
  • 查询与分配存储空间非常快

btrfs

  • 支持 COW (导致碎片化问题比较严重)
  • inode 动态分配
  • 针对小文件和 SSD 做了优化
  • 能横跨多种硬盘

…..

当然,实际他们的区别很大,详细的不同点和特性你可以自行深入了解。总之,不同的文件系统所实现的功能都是帮助我们管理文件,不同点在于存储的方式结构以及访问速度、安全等方面。

内存文件系统

除了使用磁盘进行文件存储的文件系统之外,常见的就是我们的内存文件系统,最常见的就是我想说的 proc 文件系统。它之前经常出现在我们排查 Linux 问题的时候,它通常被挂载在 /proc 目录上。

proc 文件系统也被分类为 伪文件系统,不用于保存文件数据,而用于其他功能的文件系统

获取系统信息

比如我们可以通过 cat /proc/cpuinfo 命令来查看 cpu 的基本信息

1
2
3
4
5
6
7
8
9
10
root@VM-16-3-ubuntu:~# cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 94
model name : Intel(R) Xeon(R) Gold 6133 CPU @ 2.50GHz
stepping : 3
microcode : 0x1
cpu MHz : 2494.140
cache size : 28160 KB

相类似的还有 cat /proc/meminfo 查看内存信息

获取进程信息

毕竟是 proc 文件系统(process) 所以对于进程的相关信息有时能帮助我们查找出很多问题。

比如我们可以通过 cat /proc/31143/status 命令来查看进程状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
root@VM-16-3-ubuntu:~# cat /proc/31143/status
Name: webhook
Umask: 0022
State: S (sleeping)
Tgid: 31143
Ngid: 0
Pid: 31143
PPid: 1
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256
Groups: 0
NStgid: 31143
NSpid: 31143
NSpgid: 31142
NSsid: 3759
VmPeak: 1155576 kB
VmSize: 1155576 kB
VmLck: 32 kB
VmPin: 0 kB
VmHWM: 12520 kB
VmRSS: 12520 kB

总之 proc 文件系统掌握着整个系统运行的各种信息,各种运行情况,它可以帮助我们快速了解当前系统的运行状态或者是进程的运行状态。

网络文件系统

网络文件系统(Network File System) 也就是 NFS ,顾名思义就是通过网络将需要使用的文件系统挂载到一个本地的目录上,这样就可以像访问本地文件一样,访问网络中的文件。

我们最常见的就是我们家里的 NAS,使用 smb 协议,我们可以挂载到我们本地目录,这样访问非常方便,通过内网就可以访问 NAS 中的相关资源。其他具体这里就不多介绍了。

文件系统结构

逻辑块

首先,磁盘读写的最小单位是扇区,一个扇区是 512B 如果每次读写这样小的单位效率太低,故文件系统将多个扇区抽象为一个块,Linux 中一块为 4KB

格式化

针对磁盘进行格式化的时候,会将它分成不同的区域:

  1. 超级块:记录了整个文件系统的全局元数据,如文件系统类型和存储布局。
  2. 块分配信息与 inode 分配信息:记录块的使用情况和每个 inode 的使用情况
  3. inode 列表:保存整个文件系统中所有的 inode 结构
  4. 数据块:具体的文件数据

file-system-structure.png

位图法

当我们有数据需要存储的时候,我们不可能每次去扫描一遍磁盘,看哪里放得下就随便一放,找也是很花时间的。于是就需要对磁盘的空闲空间做管理。

上面提到格式化的时候,会有一个块分配信息,这里就保存着我们块的使用情况,位图法,就是将使用具体的使用情况以比特位的形式记录下来,0 表示空闲;1 表示使用。
类似 011010101001.....

目录存储

linux 一切皆文件,所以目录也是个文件,也有 inode。目录的文件里面存放的是该目录里面一项项的文件信息。

你是否曾经误打误撞见过目录的存储呢?我曾经就不小心使用 vim . 发现目录本身也是可以被查看的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
" ============================================================================
" Netrw Directory Listing (netrw v165)
" /usr
" Sorted by name
" Sort sequence: [\/]$,\<core\%(\.\d\+\)\=\>,\.h$,\.c$,\.cpp$,\~\=\*$,*,\.o$,\.obj$,\.info$,\.swp$,\.bak$,\~$
" Quick Help: <F1>:help -:go up dir D:delete R:rename s:sort-by x:special
" ==============================================================================
../
./
bin/
games/
include/
lib/
lib32/
lib64/
libexec/
libx32/
local/
sbin/
share/
src/

链接

最后来看一个小知识点:硬链接 和 软链接。

其实链接很好理解,我个人第一次使用和遇见链接就觉得,它就是 windows 系统下的快捷方式。我们可以通过创建一个文件的 “快捷方式” 来放到桌面,从而在桌面上就可以访问这个文件,而不需要一个个目录的去寻找。

软链接

命令为:

1
2
ln -s 源文件 目标文件
ln -s /bin/hello.sh /usr/local/bin/hello

这个就和快捷方式非常类似,其实就是新建了一个文件,这个文件指向了另一个文件,删除链接不会影响原来的文件,原文件删除,链接访问会报错。

软链接是可以跨文件系统的。

硬链接

命令为:

1
2
ln 源文件 目标文件
ln /bin/hello.sh /usr/local/bin/hello

硬链接只能引用同一文件系统中的文件,它引用的是 inode(硬链接是不会建立 inode 的),其实际是为文件建立了一个别名,链接文件和原文件是同一个文件。

只有删除文件的所有硬链接和文件本身,这个文件才会被删除。

总结

  1. 文件除了内容本身还有 inode 和 dentry
  2. VFS 虚拟文件系统封装了各种文件系统,提供的统一接口进行操作。
  3. 各种文件系统有不同的功能,其本质都是帮助我们更好的管理文件,更快的查询到文件。
  4. 文件系统本身格式化之后也会有”索引”来帮助寻找空闲块和查找文件
  5. 在 Linux 中真的都是文件:普通的各种文件,目录也是文件,链接也是文件,socket 也是文件,管道也是文件…

参考链接