7. 文件系统

Linux在访问外部存储器中的数据时,通常不会直接访问,而是通过"文件系统"来进行访问。

如果不存在文件系统,每一个访问外部存储器的程序都需要自己管理外部存储器中的所有数据的相关信息。

文件系统以文件为单位管理所有对用户有实际意义的数据块,并为这些数据块加上名称、位置和大小等辅助信息。它还规范了数据结构,以确定什么文件应该保存到什么位置,内核中的文件系统将依据该规范处理数据。
进程只需要通过读取文件的系统调用,指定文件名、文件的偏移量以及文件大小,负责操作文件系统的处理即可找到相关数据并转交给用户。

Linux文件系统

为了分门别类地整理文件,Linux的文件系统提供了一种可以收纳其他文件的特殊文件,这种文件称为 目录

Linux能使用的文件系统不止一种,ext4, xf5, btrfs等不同的文件系统可以共存于Linux上。这些文件系统在外部存储器中的数据结构以及用于处理数据的程序各不相同。各种文件系统所支持的文件大小、文件系统本身的大小以及各种文件操作(创建、删除与读写文件等)的速度也不相同。

面向进程的访问接口为:

  • 创建与删除文件:create(), unlink()
  • 打开与关闭文件:open(), close()
  • 从已打开的文件中读取数据:read()
  • 往已打开的文件中写入数据:write()
  • 将已打开的文件移动到指定位置:lseek()
  • 除了以上这些操作以外的依赖于文件系统的特殊处理: ioctl()

在请求这些系统调用时,将按照下列流程读取文件中的数据:

  1. 执行内核中的全部文件系统通用的处理,并判断作为操作对象的文件保存在哪个文件系统上
  2. 调用文件系统专有的处理,并执行与请求的系统调用对应的处理
  3. 在读写数据时,调用设备驱动程序执行操作
  4. 由设备驱动程序执行数据的读写操作

数据与元数据

  • 数据:用户创建的文档、图片、视频和程序等数据内容
  • 元数据:文件的名称、文件在外部存储器中的位置和文件大小等辅助信息
    • 种类:用于判断文件是保存数据的普通文件,还是目录或其他类型的文件的信息
    • 时间信息: 包括文件的创建时间,最后一次访问的时间,以及最后一次修改的时间
    • 权限信息:表明该文件运行哪些用户访问

通过df命令得到的文件系统所用的存储空间,不但包括大家在文件系统上创建的所有文件占用的空间,还包括所有元数据所占用的空间。

容量限制

当系统管理相关的处理所需的容量不足时,系统将无法正常运行。

为了避免这样的情况出现,可以通过磁盘配额功能来限制各种用途的文件系统的容量。

磁盘配额的类型:

  • 用户配额:限制作为文件所有者的用户的可用容量
  • 目录配额:限制特定目录的可用容量
  • 子卷配额:限制文件系统内名为子卷的单元的可用容量

文件系统不一致


这一连串的操作是不可分割的,称为"原子操作"。
如果在这一系列操作中发生了中断,就会导致文件系统不一致状态。

只要发生过这种不一致的状况,迟早会被文件系统检查出来。如果在挂载时检测到了不一致,就会导致文件系统无法被挂载;如果在访问过程中检测到不一致,则可能会以只读模式重新挂载该文件系统,在最坏的情况下甚至可能导致系统出错。

防止文件系统不一致的技术有很多,常用的是日志journaling写时复制

日志

日志功能在文件系统中提供了一个名为日志区域的特殊区域。日志区域是用户无法识别的元数据。文件系统的更新按照以下步骤进行。

  1. 把更新所需的原子操作的概要暂时写入日志区域,这里的"概要"就称为日志
  2. 基于日志区域中的内容,进行文件系统的更新

如果在更新日志记录的过程中被中断,就只需丢弃日志区域的数据即可,数据本身依旧是开始处理前的状态。

如果在实际执行数据更新的过程中被中断,那么只需按照日志记录从头开始执行一遍操作,即可完成文件系统的处理。

写时复制

在ext4和XFS等传统的文件系统上,文件一旦被创建,其位置原则上就不会再改变了。即便在更新文件内容时,也只会在外部存储器的同一位置写入心得数据。

与此相对,在Btrfs等利用写时复制得文件系统上,创建文件后得每一次更新处理都会把数据写入不同得位置。

写时复制的操作过程

在执行中发生中断,只要在重启后删除未处理完的数据,也就不会导致不一致的情况出现。

文件系统不一致的对策

外一文件系统上出现了不一致的情况,要怎样应对呢?

  • 定期备份文件系统,当发生文件系统不一致时,可以直接还原到最近备份的状态。推荐使用
  • 利用各文件系统提供的恢复命令,这些命令可能将文件系统还原到一致的状态
    • ext4上为 fsck.ext4
    • xfs上为 xfs_repair
    • btrfs上为 btrfscheck
    • fsck命令为通用的命令,但是不推荐使用
      • 该命令遍历整个文件系统,以检查文件系统的一致性,并修复不一致的地方。
      • 运行时间长,且经常以失败告终
      • 即便修复成功,也不一定能恢复到期待的状态

文件的种类

  • 普通文件:用于保存用户数据
  • 目录文件:用于保存其他文件
  • 设备文件:Linux会将自身所处的硬件系统上几乎所有的设备呈现为文件形式
    • 在Linux上,设备如同文件一般,可以通过open(), read(), write()等系统调用进行访问
    • 在执行设备特有的复杂操作时,就使用ioctl()系统调用

虽然设备也存在很多种类,但Linux将以文件形式存在的设备分为两种类型,分别为字符设备块设备。所有设备文件都保存在/dev目录下。通过设备文件的元数据中保存的以下信息,我们可以识别各个设备。

  • 文件的种类(字符设备或块设备),首字母c表示字符设备,b表示块设备
  • 设备的主设备号,第5字段的显示值
  • 设备的次设备号,第6字段的显示值

字符设备

字符设备虽然能执行读写操作,但是无法自行确定读取数据的位置。

  • 终端
  • 键盘
  • 鼠标

ps ax命令的第2个字段,可得知各个进程关联的设备文件名。

块设备

块设备除了能执行普通的读写操作以外,还能进行随机访问,比较具有代表性的块设备是HDD与SSD等外部存储器。只需像读写文件一样读写块设备的数据,即可访问外部存储器中指定的数据。

通常不会直接访问块设备,而是在设备上创建一个文件系统并将其挂载,然后通过文件系统进行访问,但在以下几种情况下,需要直接操作块设备。

  • 更新分区表(利用parted命令等)
  • 块设备级别的数据备份与还原(利用dd命令等)
  • 创建文件系统(利用各文件系统的mkfs命令等)
  • 挂载文件系统(利用mount命令等)
  • fsck

各种各样的文件系统

基于内存的文件系统

tmpfs是一种创建于内存(而非外部存储器)上的文件系统。虽然这个文件系统中保存的数据会在切断电源后消失,但由于访问该文件系统时不再需要访问外部存储器,所以能提高访问速度。

tmpfs通常被用于"/tmp"与"/var/run"这种"文件内容无须保存到下一次启动时"的文件上。

tmpfs创建于挂载的时候。在挂载时,通过size选项指定最大容量。不过,并不是说一开就直接占用指定的内存量,而是在初次访问文件系统中的区域时,以页为单位申请相应大小的内存。通过查看free命令的输出结果中shared字段的值,可以得知tmpfs实际占用的内存量。

网络文件系统

网络文件系统可以通过网络访问远程主机上的文件。

在访问Windows主机上的文件时,使用名为cifs的文件系统;而在访问搭载Linux等类UNIX系统的主机上的文件时,则使用名为nfs的文件系统。

虚拟文件系统

系统上存在着各种各样的文件系统,用于获取内核中的各种信息,以及更改内核的行为。

  • procfs
    用于获取系统上所有进程的信息。它通常被挂载在/proc目录下。通过访问/proc/{pid}/目录下的文件,即可获取各个进程的信息。
    • /proc/{pid}/maps:进程的内存映射

    • /proc/{pid}/cmdline:进程的命令行参数

    • /proc/{pid}/stat:进程的状态,比如CPU时间、优先级和内存使用量等信息

    • /proc/cpuinfo: 搭载于系统上的CPU的相关信息

    • /proc/diskstat: 搭载于系统上的外部存储器的相关信息

    • /proc/meminfo: 搭载于系统上的内存的相关信息

    • /proc/sys目录下的文件: 内核的各种调优参数,与sysctl命令和/etc/sysctl.conf中的调优参数一一对应。

ps, sar, topfree等用于显示OS提供的各种信息的命令,都是从procfs中采集信息的。

  • sysfs
    sysfs的文件系统,用来存放那些与进程无关的信息。通常被挂载在/sys目录下

    • /sys/devices:搭载于系统上的设备的相关信息
    • /sys/fs:系统上的各种文件系统的相关信息
  • cgroupfs
    用于限制单个进程或者由多个进程组成的群组的资源使用量,它需要通过文件系统cgroupfs来操作。

只有root用户可以操作cgroup。cgroupfs通常被挂载在/sys/fs/cgroup目录下。
通过cgroup添加限制的资源有很多种:

  • CPU: 设置能够使用的比例,比如令某群组只能够使用CPU资源总量的50%等/sys/fs/cgroup/cpu
  • 内存:限制群组的物理内存使用量,比如令群组最多只能够使用1GB内存等。/sys/fs/cgroup/memory

cgroup通常被用于通过docker之类的容器管理软件,或virt-manager等虚拟机管理软件来限制各个容器或虚拟机的资源使用量。

Btrfs

  • 多物理卷

在ext4与XFS上需要为每个分区创建文件系统,但在Btrfs中不需要这样。Btrfs可以创建一个包含多个外部存储器或分区的存储池,然后在存储池上创建可被挂载的区域,该区域称为子卷。存储池相当于LVM中的卷组,而子卷则类似于LVM中的逻辑卷与文件系统的融合。

在Btrfs中,甚至还可以向现存的文件系统添加、删除以及替换外部存储器。即便这些操作导致容量发生变化,也无须调整文件系统大小。

  • 快照
    Btrfs可以以子卷为单位创建快照。创建快照并不需要复杂所有的数据,只需根据数据创建其元数据,并回写快照内的脏页即可,因此创建快照与平常的复杂操作起来要快得多。而且,由于快照与子卷共享数据,所以创建快照的存储空间成本也很低。
    复制操作的示意图

    快照的示意图

  • RAID
    Btrfs可以在文件系统级别上配置RAID,支持的RAID级别有0,1,10,5,6以及dup。另外,在配置RAID时,不是以子卷为单位,而是以整个Btrfs文件系统为单位。

  • 数据损坏的检测与恢复
    当外部存储器中的部分数据损坏时,Btrfs能够检测出来,如果配置了某些级别的RAID,还能修复这些损坏的数据。而在那些没有这类功能的文件系统中,即便在写入时外部存储器中的数据因比特差错等而损坏了,也无法检测出这些损坏的数据,而是在数据损坏的状态下继续运行。

    Btrfs拥有一种被称为校验和checksum的机制,用于检测数据与元数据的完整性。通过这种机制,可以检测出数据损坏。

在检测到损坏时,如果配置的RAID级别是RAID1, RAID10, RAID5,RAID6或dup之一,Btrfs就能基于校验和正确的另一份数据副本修复破损的数据。在RAID5和RAID6中,还能通过奇偶校验实现同样的功能。

posted @ 2024-07-15 13:05  Python习者  阅读(29)  评论(0)    收藏  举报