Linux文件系统管理

(整理自《鸟哥的Linux私房菜》书籍)

1.文件系统特性

我们都知道磁盘分区完毕后还需要进行格式化(format),之后操作系统才能够使用这个文件系统。 为什么需要进行『格式化』呢?这是因为每种操作系统所设定的文件属性/权限并不相同, 为了存放这些文件所需的数据,因此就需要将分区槽进行格式化,以成为操作系统能够利用的文件系统格式(filesystem)。

一个可被挂载的数据为一个文件系统而不是一个分区槽。

文件系统是如何运作的?

这与操作系统的文件数据有关。较新的操作系统的文件数据除了文件实际内容外, 通常含有非常多的属性,例如 Linux 操作系统的文件权限(rwx)与文件属性(拥有者、群组、时间参数等)。 文件系统通常会将这两部份的数据分别存放在不同的区块,权限与属性放置到 inode 中,至于实际数据则放置到 data block 区块中。还有一个超级区块 (superblock) 会记录整个文件系统的整体信息,包括 inode 与 block 的总量、使用量、剩余量等。

每个 inode 与 block 都有编号,至于这三个数据的意义可以简略说明如下:

•        superblock:记录此 filesystem 的整体信息,包括 inode/block 的总量、使用量、剩余量, 以及文件系统的格式与相关信息等;

•        inode:记录文件的属性,一个文件占用一个 inode,同时记录此文件的数据所在的 block 号码;

•        block:实际记录文件的内容,若文件太大时,会占用多个 block 。

由于每个 inode 与 block 都有编号,而每个文件都会占用一个 inode ,inode 内则有文件数据放置的 block 号码。 因此,如果能够找到文件的 inode 的话,那么自然就会知道这个文件所放置数据的 block 号码, 当然也就能够读出该文件的实际数据了。我们将 inode 与 block 区块用图解来说明一下:

Linux文件系统管理

这种数据存取的方法我们称为索引式文件系统(indexed allocation)。

那有没有其他的惯用文件系统?

有的,那就是我们惯用的U盘,它使用的文件系统一般为 FAT 格式。

FAT 这种格式的文件系统并没有 inode 存在,所以 FAT 没有办法将这个文件的所有 block 在一开始就读取出来。每个 block 号码都记录在前一个 block 当中, 他的读取方式有点像底下这样:

 Linux文件系统管理

 我们假设文件的数据依序写入 1->7->4->15 号这四个 block 号码中, 但这个文件系统没有办法一口气就知道四个 block 的号码,他得要一个一个的将 block 读出后,才会知道下一个 block 在何处。 如果同一个文件数据写入的 block 分散的太过厉害时,则我们的磁盘读取头将无法在磁盘转一圈就读到所有的数据, 因此磁盘就会多转好几圈才能完整的读取到这个文件的内容!

什么是碎片整理,为什么需要?

需要碎片整理的原因就是文件写入的 block 太过于离散了,此时文件读取的效能将会变的很差所致。 这个时候可以透过碎片整理将同一个文件所属的 blocks 汇整在一起,这样数据的读取会比较容易。

一般来说对于U盘(FAT文件系统)来说需要碎片整理。

由于 Ext2 是索引式文件系统,基本上不太需要常常进行碎片整理的。但是如果文件系统使用太久,常常删除/编辑/新增文件时,那么还是可能会造成文件数据太过于离散的问题,此时或许会需要进行重整一下的。

2.Linux 的 EXT2 文件系统(inode)

文件系统一开始就将 inode 与 block 规划好了,除非重新格式化(或者利用resize2fs 等指令变更文件系统大小),否则 inode 与 block 固定后就不再变动。如果我的文件系统高达数百 GB 时, 那么将所有的 inode 与 block 通通放置在一起将是很不明智的决定,因为 inode 与 block 的数量太庞大,不容易管理。为此之故,因此 Ext2 文件系统在格式化的时候基本上是区分为多个区块群组 (block group) 的,每个区块群组都有独立的inode/block/superblock 系统。

 Linux文件系统管理

在整体的规划当中,文件系统最前面有一个启动扇区(boot sector),这个启动扇区可以安装开机管理程序, 这是个非常重要的设计,因为如此一来我们就能够将不同的开机管理程序安装到个别的文件系统最前端,而不用覆盖整颗磁盘唯一的 MBR, 这样也才能够制作出多重引导的环境!至于每一个区块群组(block group)的六个主要内容说明如下:

§      data block (数据区块)

data block 是用来放置文件内容数据地方,在 Ext2 文件系统中所支持的 block 大小有 1K, 2K 及4K 三种而已。在格式化时 block 的大小就固定了,且每个 block 都有编号,以方便 inode 的记录。 不过要注意的是,由于 block 大小的差异,会导致该文件系统能够支持的最大磁盘容量与最大单一文件容量并不相同。 因为 block 大小而产生的 Ext2 文件系统限制如下:

Block 大小

1KB

2KB

4KB

最大单一文件限制

16GB

256GB

2TB

最大文件系统总容量

2TB

8TB

16TB

需要注意的是,虽然 Ext2 已经能够支持大于 2GB 以上的单一文件容量,不过某些应用程序依然使用旧的限制, 也就是说,某些程序只能够捉到小于 2GB 以下的文件而已,这就跟文件系统无关了!除此之外 Ext2 文件系统的 block 还有什么限制呢?

•        原则上,block 的大小与数量在格式化完就不能够再改变了(除非重新格式化);

•        每个 block 内最多只能够放置一个文件的数据;

•        承上,如果文件大于 block 的大小,则一个文件会占用多个 block 数量;

•        承上,若文件小于 block ,则该 block 的剩余容量就不能够再被使用了(磁盘空间会浪费)。

如上第四点所说,由于每个 block 仅能容纳一个文件的数据而已,因此如果你的文件都非常小,但是你的 block 在格式化时却选用最大的 4K 时,可能会产生一些容量的浪费。

既然大的 block 可能会产生较严重的磁盘容量浪费,那么我们是否就将 block 大小订为 1K 即可? 这也不妥,因为如果 block 较小的话,那么大型文件将会占用数量更多的 block ,而 inode 也要记录更多的 block 号码,此时将可能导致文件系统不良的读写效能。

§     inode table (inode )

基本上,inode 记录的文件数据至少有底下这些:

•        该文件的存取模式(read/write/excute);

•        该文件的拥有者与群组(owner/group);

•        该文件的容量;

•        该文件建立或状态改变的时间(ctime);

•        最近一次的读取时间(atime);

•        最近修改的时间(mtime);

•        定义文件特性的旗标(flag),如 SetUID...;

•        该文件真正内容的指向 (pointer);

inode 的数量与大小也是在格式化时就已经固定了,除此之外 inode 还有些什么特色呢?

•        每个 inode 大小均固定为 128 bytes (新的 ext4 与 xfs 可设定到 256 bytes);

•        每个文件都仅会占用一个 inode 而已;

•        承上,因此文件系统能够建立的文件数量与 inode 的数量有关;

•        系统读取文件时需要先找到 inode,并分析 inode 所记录的权限与用户是否符合,若符合才能够开始实际读取 block 的内容。

假设我一个文件有400MB 且每个 block 为 4K 时, 那么至少也要十万个block 号码的记录。inode 哪有这么多可记录的信息?为此我们的系统很聪明的将 inode 记录 block 号码的区域定义为 12 个直接,一个间接, 一个双间接与一个三间接记录区。

 Linux文件系统管理

 上图最左边为 inode 本身 (128 bytes),里面有 12 个直接指向 block 号码的对照,这 12 个记录就能够直接取得 block 号码! 至于所谓的间接就是再拿一个 block 来当作记录 block 号码的记录

区,如果文件太大时, 就会使用间接的 block 来记录编号。 同理,如果文件持续长大,那么就会利用所谓的双间接,第一个 block 仅再指出下一个记录编号的 block 在哪里, 实际记录的在第二个 block 当中。依此类推,三间接就是利用第三层 block 来记录编号!

这样子 inode 能够指定多少个 block 呢?我们以较小的 1K block 来说明,可以指定的情况如下:

•        12 个直接指向: 12*1K=12K

由于是直接指向,所以总共可记录 12 笔记录,因此总额大小为如上所示;

•        间接: 256*1K=256K 每个 block 号码的记录会花去 4bytes,因此 1K 的大小能够记录 256 笔记录,因此一个间接可以记录的文件大小如上; 

•        双间接: 256*256*1K=2562K

第一层 block 会指定 256 个第二层,每个第二层可以指定 256 个号码,因此总额大小如上;

•        三间接: 256*256*256*1K=2563K

第一层 block 会指定 256 个第二层,每个第二层可以指定 256 个第三层,每个第三层可以指定 256 个号码,因此总额大小如上;

•        总额:将直接、间接、双间接、三间接加总,得到 12 + 256 + 256*256 + 256*256*256 (K) = 16GB

所以当文件系统将 block 格式化为 1K 大小时,能够容纳的最大文件为 16GB,比较一下文件系统限制表的结果可发现是一致的!但这个方法不能用在 2K 及 4K block 大小的计算中, 因为大于 2K 的 block 将会受到 Ext2 文件系统本身的限制,所以计算的结果会不太符合之故。

 §  Superblock (超级区块)

Superblock 是记录整个 filesystem 相关信息的地方, 没有 Superblock ,就没有这个 filesystem 了。

他记录的信息主要有:

•        block 与 inode 的总量;

•        未使用与已使用的 inode / block 数量;

•        block 与 inode 的大小 (block 为 1, 2, 4K,inode 为 128bytes 或 256bytes);

•        filesystem 的挂载时间、最近一次写入数据的时间、最近一次检验磁盘 (fsck) 的时间等文件系统的相关信息;

•        一个 valid bit 数值,若此文件系统已被挂载,则 valid bit 为 0 ,若未被挂载,则 valid bit 为 1 。

如果 superblock 死掉了, 你的文件系统可能就需要花费很多时间去挽救。一般来说, superblock 的大小为 1024bytes。相关的 superblock 讯息在Ext2/3/4中可以使用 dumpe2fs 指令来观察!

此外,每个 block group 都可能含有 superblock !但是我们也说一个文件系统应该仅有一个 superblock 而已,因为除了第一个 block group 内会含有 superblock 之外,后续的 block group 不一定含有 superblock , 而若含有 superblock 则该 superblock 主要是做为第一个 block group 内 superblock 的备份

 §  Filesystem Description (文件系统描述说明)

这个区段可以描述每个 block group 的开始与结束的 block 号码,以及说明每个区段 (superblock,

bitmap, inodemap, data block) 分别介于哪一个 block 号码之间。这部份也能够用 dumpe2fs 来观察的。

 §  block bitmap (区块对照表)

如果你想要新增文件时总会用到 block 。从 block bitmap 当中可以知道哪些 block 是空的。同样的,如果你删除某些文件时,那么那些文件原本占用的 block 号码就得要释放出来, 此时在block bitmap 当中相对应到该 block 号码的标志就得要修改成为【未使用中】。

 §  inode bitmap (inode 对照表)

这个其实与 block bitmap 是类似的功能,只是 block bitmap 记录的是使用与未使用的 block 号码,至于 inode bitmap 则是记录使用与未使用的 inode 号码。

 §  dumpe2fs查询 Ext 家族 superblock 信息的指令

我们的 CentOS 7 现在是以 xfs 为预设文件系统, 所以目前你的系统应该无法使用 dumpe2fs 去查询任何文件系统的。对于Ext2/3/4则可以使用这个命令来观察,观察的内容如下:

 Linux文件系统管理

3. 与目录树的关系

目录与文件在文件系统当中是如何记录数据的呢?基本上可以这样说:

§目录

当我们在 Linux 下的文件系统建立一个目录时,文件系统会分配一个 inode 与至少一块 block 给该目录。其中,inode 记录该目录的相关权限与属性,并可记录分配到的那块 block 号码; 而 block 则是记录在这个目录下的文件名与该文件名占用的 inode 号码数据。也就是说目录所占用的 block 内容在记录如下的信息:

Linux文件系统管理 

§  文件:

当我们在 Linux 下的 ext2 建立一个一般文件时, ext2 会分配一个 inode 与相对于该文件大小的 block 数量给该文件。例如:假设我的一个 block 为 4 Kbytes ,而我要建立一个 100 KBytes 的文

件,那么 linux 将分配一个 inode 与 25 个 block 来储存该文件! 但同时请注意,由于 inode 仅有 12 个直接指向,因此还要多一个 block 来作为区块号码的记录。

 §  目录树读取:

因为文件名是记录在目录的 block 当中, 因此当我们要读取某个文件时,就务必会经过目录的 inode 与 block ,然后才能够找到那个待读取文件的 inode 号码,最终才会读到正确的文件的 block 内的数据。由于目录树是由根目录开始读起,因此系统透过挂载的信息可以找到挂载点的 inode 号码,此时就能够得到根目录的 inode 内容,并依据该 inode 读取根目录的 block 内的文件名数据,再一层一层的往下读到正确的档名。

§  filesystem 大小与磁盘读取效能:

当你的一个文件系统规划的很大时,例如 100GB 这么大时, 由于磁盘上面的数据总是来来去去的,所以,整个文件系统上面的文件通常无法连续写在一起(block 号码不会连续的意思), 而是填入式的将数据填入没有被使用的 block 当中。如果文件写入的 block 真的分的很散, 此时就会有所谓的文件数据离散的问题发生了。

如前所述,虽然我们的 ext2 在 inode 处已经将该文件所记录的 block 号码都记上了, 所以资料可以一次性读取,但是如果文件真的太过离散,确实还是会发生读取效率下降的问题。 因为磁盘读取头还是得要在整个文件系统中来来去去的频繁读取! 果真如此,那么可以将整个 filesystme 内的数据全部复制出来,将该 filesystem 重新格式化, 再将数据给他复制回去即可解决这个问题。

此外,如果 filesystem 太大,那么当一个文件分别记录在这个文件系统的最前面与最后面的 block 号码中, 此时会造成磁盘的机械手臂移动幅度过大,也会造成数据读取效能的下降。而且读取头在搜寻整个 filesystem 时, 也会花费比较多的时间去搜寻。因此, partition 的规划并不是越大越好, 而是要针对您的主机用途来进行规划。

4.日志式文件系统

假设我们想要新增一个文件,此时文件系统的行为是:

1.     先确定用户对于欲新增文件的目录是否具有 w 与 x 的权限,若有的话才能新增;

2.     根据 inode bitmap 找到没有使用的 inode 号码,并将新文件的权限/属性写入;

3.     根据 block bitmap 找到没有使用中的 block 号码,并将实际的数据写入 block 中,且更新 inode 的 block 指向数据;

4.     将刚刚写入的 inode 与 block 数据同步更新 inode bitmap 与 block bitmap,并更新 superblock 的内容。

一般来说,我们将 inode table 与 data block 称为数据存放区域,至于其他例如 superblock、 block bitmap 与 inode bitmap 等区段就被称为 metadata (元数据),因为 superblock, inode bitmap 及 block bitmap 的数据是经常变动的,每次新增、移除、编辑时都可能会影响到这三个部分的数据,因此才被称为元数据。

 §数据的不一致 (Inconsistent) 状态

在一般正常的情况下,上述的新增动作当然可以顺利的完成。但是如果有个万一怎么办? 例如你的文件在写入文件系统时,因为不知名原因导致系统中断(例如突然的停电、 系统核心发生错误等等的怪事发生时),所以写入的数据仅有 inode table 及 data block 而已, 最后一个同步更新中介数据的步骤并没有做完,此时就会发生 metadata 的内容与实际数据存放区产生不一致(Inconsistent) 的情况了。

在早期的 Ext2 文件系统中,如果发生这个问题, 那么系统在重新启动的时候,就会藉由 超级区块当中记录的 valid bit (是否有挂载) 与 filesystem state (clean 与否) 等状态来判断是否强制进行数据一致性的检查。但这个往往是对于整个文件系统的检查,效率很低,所以就有了日志式文件系统。。

 §日志式文件系统

为了避免上述提到的文件系统不一致的情况发生, 如果在我们的 filesystem 当中规划出一个区块,该区块专门在记录写入或修订文件时的步骤, 那就可以简化一致性检查的步骤了。也就是说:

1.     预备:当系统要写入一个文件时,会先在日志记录区块中纪录某个文件准备要写入的信息;

2.     实际写入:开始写入文件的权限与数据;开始更新 metadata 的数据;

3.     结束:完成数据与 metadata 的更新后,在日志记录区块当中完成该文件的纪录。

在这样的程序当中,万一数据的纪录过程当中发生了问题,那么我们的系统只要去检查日志记录区块,就可以知道哪个文件发生了问题,针对该问题来做一致性的检查即可,而不必针对整块 filesystem 去检查, 这样就可以达到快速修复 filesystem 的能力。

5.VFS

常见的支持文件系统有:

•        传统文件系统:ext2 / minix / MS-DOS / FAT (用 vfat 模块) / iso9660 (光盘)等等;

•        日志式文件系统: ext3 /ext4 / ReiserFS / Windows‘ NTFS / IBM‘s JFS / SGI‘s XFS / ZFS

•        网络文件系统: NFS / SMBFS

整个 Linux 的系统都是透过一个名为 Virtual Filesystem Switch 的核心功能去读取 filesystem 的。 也就是说,整个 Linux 认识的 filesystem 其实都是 VFS 在进行管理,我们使用者并不需要知道每个 partition 上的 filesystem 是什么, VFS 会主动的帮我们做好读取的动作。

Linux文件系统管理

6.XFS文件系统

 xfs 就是一个日志式文件系统,而 CentOS 7.x 拿它当预设的文件系统,自然就是因为最早之前,这个 xfs 就是被开发来用于高容量磁盘以及高性能文件系统之用, 因此,相当适合现在的系统环境。此外,几乎所有 Ext4 文件系统有的功能, xfs 都可以具备!

xfs 文件系统在数据的分布上,主要规划为三个部份,一个数据区 (data section)、一个文件系统活动登录区 (log section)以及一个实时运行区 (realtime section)。 这三个区域的数据内容如下:

o  数据区 (data section)

基本上,数据区就跟我们之前谈到的 ext 家族一样,包括 inode/data block/superblock 等数据,都放置在这个区块。 这个数据区与 ext 家族的 block group 类似,也是分为多个储存区群组来分别放置文件系统所需要的数据。 每个储存区群组都包含了 (1)整个文件系统的 superblock、 (2)剩余空间的管理机制、 (3)inode 的分配与追踪。此外,inode 与 block 都是系统需要用到时, 这才动态配置产生,所以格式化动作超级快。

另外,与 ext 家族不同的是, xfs 的 block 与 inode 有多种不同的容量可供设定,block 容量可由 512bytes ~ 64K 调配,不过,Linux 的环境下, 由于内存控制的关系 (页面文件 pagesize 的容量之故),因此最高可以使用的 block 大小为 4K 而已。至于 inode 容量可由 256bytes 到 2M 这么大,不过,大概还是保留 256bytes 的默认值就很够用了。

o   文件系统活动登录区 (log section)

在登录区这个区域主要被用来纪录文件系统的变化,其实有点像是日志区。在这个区域中, 你可以指定外部的磁盘来作为 xfs 文件系统的日志区块。例如,妳可以将 SSD 磁盘作为 xfs 的登录区,这样当系统需要进行任何活动时, 就可以更快速的进行工作。!

o   实时运作区 (realtime section)

当有文件要被建立时,xfs 会在这个区段里面找一个到数个的 extent 区块,将文件放置在这个区块内,等到分配完毕后,再写入到 data section 的 inode 与 block 去。 这个 extent 区块的大小得要在格式化的时候就先指定,最小值是 4K 最大可到 1G。一般非磁盘阵列的磁盘默认为 64K 容量,而具有类似磁盘阵列的 stripe 情况下,则建议 extent 设定为与 stripe 一样大较佳。这个 extent 最好不要乱动,因为可能会影响到实体磁盘的效能。

 §      XFS 文件系统的描述数据观察

 Linux文件系统管理

 上面的输出讯息可以这样解释:

•        第 1 行里面的 isize 指的是 inode 的容量,每个有 256bytes 这么大。至于 agcount 则是前面谈到的储存区群组 (allocation group) 的个数,共有 4 个, agsize 则是指每个储存区群组具有 65536 个 block 。配合第 4 行的 block 设定为 4K,因此整个文件系统的容量应该就是 4*65536*4K 这么大。

•        第 2 行里面 sectsz 指的是逻辑扇区 (sector) 的容量设定为 512bytes 这么大的意思。

•        第 4 行里面的 bsize 指的是 block 的容量,每个 block 为 4K 的意思,共有 262144 个 block 在这个文件系统内。

•        第 5 行里面的 sunit 与 swidth 与磁盘阵列的 stripe 相关性较高

•        第 7 行里面的 internal 指的是这个登录区的位置在文件系统内,而不是外部设备的意思。且占用了 4K *2560 个 block,总共约 10M 的容量。

•        第 9 行里面的 realtime 区域,里面的 extent 容量为 4K。不过目前没有使用。

由于我们并没有使用磁盘阵列,因此上头这个装置里头的 sunit 与 extent 就没有额外的指定特别的值。

相关推荐