Linux最传统的磁盘文件系统就是EXT2了(当然现在已经升级成为EXT4),这一章主要介绍Linux的磁盘文件系统,而这篇文章主要聚焦的是Linux的EXT2文件系统。
我们都知道磁盘分区完成之后要进行格式化,之所以要格式化就是因为每种操作系统所使用的文件系统格式是不一样的。在Linux中,主要就是EXT2这种文件系统格式了,默认情况下Windows操作系统是无法识别Linux的EXT2文件系统。通常情况下,一个分区就是一个文件系统,但是由于新技术的利用,我们可以将多个分区合成一个文件系统,因此现在我们称呼一个可被挂载的数据为一个文件系统。
Linux的Ext2文件系统是一种以inode为基础的文件系统。在Ext2文件系统中,inode用来记录文件的属性和权限,block块则记录文件的实际内容,此外文件系统还有一个超级块(superblock)会记录文件系统的整体信息,包括inode与block的总量,使用量,剩余量等信息。文件系统一开始就将inode与block规划好了,所以除非重新格式化(或者用resize2fs重新改变文件系统的大小),否则inode与block就固定不变了。而且Linux的Ext2文件系统是以块组(block group)的方式来管理inode与block的,每个块组都有独立的inode/block/superblock系统,这样就不会因为整个文件系统的inode与block数量过多而造成难以管理了。 Ext2文件系统结构可以用下图来表示:
正如以前文章提到的,每个文件系统的第一个扇区为启动扇区,启动扇区可以安装引导加载程序。尽管每个开机设备只有一个主引导记录(MBR),但是因为每个文件系统的启动扇区也可以安装引导加载程序,所以我们才有机会进行多重引导。
接下来是superblock(超级块),尽管每个块组都可能含有一个超级块,但是整个文件系统应该仅有一个超级块。什么意思呢?事实上,除了第一个块组里拥有超级块,其他块组一般是没有超级块的,即使拥有,它们也只是第一个块组内超级块的备份,是用来做超级块救援的。
文件系统描述用来描述每个block group开始和结束的block号码以及每个区段位于哪一个block号码之间。相当于文件系统描述的是每个block group的信息。
indoe bitmap (indoe对照表): 用来记录当前文件系统的indoe哪些是已经使用的,哪些又是未使用的。
block bitmap (块对照表): 用来记录当前文件系统哪些block已经使用,哪些又是未使用的。
inode table (inode 表格):inode是用来记录文件的属性以及该文件实际数据所在的block的号码。每一个文件都占用一个inode,每个inode的大小都固定为128bytes。因此我们可以发现每个文件系统所能创建的文件数量与inode的数量有关,而且因为每个inode的大小是固定的,而inode里需要记录文件实际数据所在的block的号码。因此每个文件的大小也与inode/block有关。inode记录block号码的区域定义为12个直接,1个间接,1个双间接,1个三间接。
什么意思呢?12个直接指的的inode指向的这12个block直接用来记录文件数据,1个间接指的是inode指向的block不是直接存放文件数据的,相反这个block里存放的其他block号码,而这些block号码对应的block里才存放真实的文件数据。那如果是双间接的话,这些block里也是用来记录存放真实数据的block编号。依次类推,三间接就是指第三层block还是用来记录标号。
当我们假设每个block的大小是1k时,每个文件的最大大小可以这样计算: 12个直接: 12*1k=12k; 1个间接:假设用四个字节来记录block号码,因此一个block可以记录256(1024/4)个block号码,因此能存放 256* 1k=256k的容量;而双间接即为: 256* 256k ,三间接即为 256*256*256k。因此所能存放的最大文件大小为 12k + 256k +256*256k + 256*256*256k=16G。
block table ( data block) 即为数据块,就是block 的集合,Ext2文件系统支持的block大小有1k,2k,4k。在格式化的时候,block的大小和数量就已经固定下来。而且每个block最多存一个文件的数据,因此当文件大小大于一个block的大小,该文件数据就需要占据多个block号码,当该文件数据小于一个block的大小时,该block剩余的空间也不会被使用了,其他文件的数据是不能放进来的。因此当我们文件系统存放的文件是小而多的文件,而此时block又选取的比较大(如4k),就可能造成空间浪费。但是将block选取为1k也不是万能的,有时候因为存放文件比较大而需要占用非常多的block时,就可能导致文件系统的不良读写性能。因此格式化时block大小的选取应该参考未来文件系统的主要用途。
那一旦文件系统已经格式化,怎么查看上述这些数据呢,可以通过dumpe2fs这个命令来详细了解文件系统的信息。dumpe2fs命令的使用方法为: dumpe2fs [-bh] 设备文件名 , dumpe2fs显示的数据可以分为两部分,第一部分主要是该文件系统superblock记录的信息,例如block的数量和大小,indoe的数量等。而第二部分则是各个block group的详细信息,例如该block group的分布情况,block使用情况等信息。
当我们新建一个目录时,Linux的Ext2文件系统会至少分配一个inode与至少一个block给该目录。之前已经讲过,目录其实就是一个文件名列表,因此目录的内容就是就是该目录下的文件名。因此Linux给该目录分配的inode中会记录该目录的权限和属性,以及记录该目录分配到的block的号码。而block中记录的就是该目录下的文件名以及该文件名对应的inode号码。
那当我们访问一个文件时,整个流程到底是如何进行的呢? 这里以/etc/passwd为例:
(1) 通过挂载点信息找到 根目录“/”所在的indoe,一般所有文件系统的最顶层目录所在的node号码都为2,例如在我的系统上,/home是一个单独的分区,可以通过 ls -id /home 命令查询到/home目录所在的inode号码为2。
(2)通过根目录inode里记录的block号码,找到相应的block,block里面就有根目录下面所有的文件名,找到etc/目录所在的indoe号码(前提是有访问根目录的权限)。
(3)在etc/ 所在的indoe中根据相应的权限设置进行检查,如果通过,则读取 etc/的block内容,里面就有passwd文件的indoe号码。
(4)访问passwd文件的indoe,通过权限检查后,就可以通过inode里记录的block号码,读取出相应的blcok,而这些block里就是存放passwd文件的实际数据。
Ext2文件系统由于不支持日志功能,因此当我们的文件系统处于数据不一致状态(例如突然断电导致系统突然中断),就需要在系统重启时通过判断文件系统是否挂载以及文件系统状态是否为clean来判断是否需要强制进行数据一致性检查,如果需要,就调用e2fsck这个程序来进行检查,但是这种检查非常费时,因为要对整个文件系统进行搜索比对。因此此时可以采用日志文件系统,日志文件系统会专门规划出一个块,用来记录写入或修订文件时的步骤。因此出现数据不一致时,可以直接检查日志记录块,就可以快速发现问题。Linux中Ext3是支持日志功能的文件系统。
之前也讲过,由于磁盘的速度比内存慢很多,因此在对内存中的数据修改后,Linux并不会马上就将内存中修改后的数据更新到磁盘上,而是采用异步处理的方式,系统会不定时地将修改后的内存数据(此时内存中的数据设置为dirty)写入到磁盘中,也可以通过sync命令手动强迫写入磁盘,系统正常关机时,关机命令就会主动调用sync命令将修改过的数据写回磁盘,而如果是非正常关机,由于数据未写回磁盘,因此重启后系统可能需要花很多时间进行磁盘检验,甚至可能导致文件系统损坏。
Linux除了支持Linux标准文件系统Ext2,还能支持非常多的文件系统,可以通过以下方式查看Linux支持的文件系统:
ls -l /lib/modules/$(uname -r) /kernel/fs
可以通过以下方式查看已经加载到内存中的文件系统:
cat /proc/filesystems
尽管Linux支持非常多的文件系统,但是对我们用户而言,不需要了解每个分区上的文件系统是什么,Linux会通过VFS(virtual file system)来管理所有文件系统。
本章Linux命令总结:
dumpe2fs。