一、简介
1、通常所做的磁盘分区格式化,为什么要对磁盘分区进行格式化?
那就是因为每种操作系统所设置的文件属性/权限等数据并不相同,为了存放这些文件所需的数据,那么就需要将分区进行格式化,以成为操作系统能够利用的文件系统格式。
2、一个文件系统就是一个分区吗?
在早期,一个分区只能被格式化为一个文件系统,所以一个文件系统就是一个分区。但是由于新技术的到来,可以将一个分区格式化为多个文件系统,也可以将多个分区合成一个文件系统,所以说一个文件系统就是一个分区是不完全正确的。在格式化时就不能说成是针对分区来格式化了,通常可以称呼一个可被挂载的数据为一个文件系统,而不是将一个分区称为一个文件系统。
3、Linux正规文件系统Ext2:Linux Second Extended File System,Ext2fs。
二、Linux的Ext2文件系统的运作与其它文件系统的比较
1、Linux的Ext2文件系统是如何运作的?
一个文件除了实际的文件数据以外,通常还含有其它很多的文件属性。Linux的Ext2文件系统通常会将这两部分的数据分别存放在不同的块。分别如下:
- block:实际记录文件的内容。若文件太大可能会占用多个block。有编号。
- inode:记录文件的属性,一个文件占用一个inode,同时还记录此文件的内容所在的那些block的号码。有编号。
- super block:记录此文件系统的整体信息,包括inode/block的总量、使用量、剩余量,以及文件系统的格式与相关信息等。
由以上内容就可以得知,当知道一个文件的inode时,就可以知道这个文件所放置数据的那些block的号码,所以就能够读出该文件的数据,如下图所示,上面两排表示inode,下面三排表示block,文件系统一开始就将inode和block规划好了,除非重新格式化或者利用resize2fs等命令更改文件系统大小,否则inode和block固定后就不再变动。图中表示一个文件占用的是4号inode,则该文件的一些属性就是存在于4号inode中的,且箭头指向就是表示该inode记录了文件数据的实际放置点为箭头指向的这几个block号码中。当读取该文件数据时,操作系统就可以据此来排列磁盘的阅读顺序,可以一下子将4个block的内容读取出来。我们把这种数据访问方式的文件系统称为索引式文件系统。
2、其他文件系统
比如在Windows系统中有一个文件系统叫做FAT,该文件系统并不存在inode,而采用的方式是实际存放数据的block指向下一个存放数据的block,所以该文件系统不可以将一个文件的所有block在一开始就全部读取出来,它必须要一个一个地将block读出来,才会知道下一个block。如下图。而且如果一个文件数据写入的block分散得过于厉害时,磁盘磁头将无法在磁盘转一圈就读到所有的数据,因此磁盘可能就会多转几圈才能完整地读取该文件的数据,所以就有了所谓的“碎片整理”来将同一个文件所属的block汇合在一起以便使数据的读取更容易。Linux的Ext2文件系统由于是索引式文件系统,基本上不需要碎片整理,但是如果文件系统使用太久,经常删除/编辑/新增文件时,还是可能会造成文件数据过于离散的问题,此时或许还是需要进行碎片整理。
三、Ext2文件系统的块组
1、如果文件系统很大时,则inode和block的数量也会很大,将它们放在一起则不容易管理,所以Ext2文件系统在格式化时基本上是区分多个块租的,每个块组都有独立的inode/block/super block系统。整个Ext2文件系统格式化后如下图所示。注意:在整体的规划当中,文件系统最前面有一个启动扇区,它可以安装引导装载程序。
2、data block(数据块)
data block就是前面说的用来存放文件实际数据内容的block。在Ext2文件系统中支持的block大小有1KB、2KB和4KB三种大小,且在格式化时block的大小就固定了。注意:采用不同大小的block,会导致该文件系统能够支持的最大磁盘容量与最大单一文件容量并不相同,详细分析见后面的inode table。除了这些特性之外,block还有其它一些特性,如下:
- 原则上,block的大小和数量在格式化后就不能再改变了,除非重新格式化。
- 每个block内最多只能放置一个文件的数据。
- 如果文件大于block的大小,则一个文件会占用多个block。
- 如果文件小于block的大小,则该block的剩余空间就不能够再被使用了。
如上最后一个特性,该特性会导致磁盘空间的浪费问题,比如Ext2文件系统采用的block大小为4KB,该文件系统中有10000个大小为50byte的小文件,在这种情况下,由于每个block内最多只能放置一个文件的数据,所以存放这10000个文件的每个block浪费的大小为(4KB * 1024)byte - 50byte = 4046byte,所以10000个文件总共就会浪费4046byte * 10000,大约38.6M大小的磁盘空间就被浪费了,而这10000个文件真正的总大小才50byte * 10000,还不到1MB。所以较大的block可能会造成磁盘空间浪费的问题,但是如果block过小的话,大型文件就会占用较多的block,而inode也要记录更多的block号码,这也可能会导致文件系统不良的读写性能,所以使用多大的block,应该看系统预计使用的情况来决定。
3、inode table(inode表格)
这个东西也就是前面说的inode,inode的特性如下:
- 记录该文件的访问模式(read/write/excute)。
- 记录该文件的所有者与组。
- 记录该文件的大小。
- 记录该文件创建或状态改变的时间(ctime)。
- 记录该文件最近一次的读取事件(atime)。
- 记录该文件最近修改的时间(mtime)。
- 定义文件特性的标志,如SetUID。
- 记录该文件真正内容的指向。
- inode的数量和大小在格式化时已经固定了。
- 每个inode的大小均固定为128byte。
- 每个文件都仅仅会占用一个inode而已。
- 文件系统能够创建的文件数量与inode的数量有关。
- inode记录一个block号码需要4byte。
正因为inode记录了文件的这些属性,所以当系统读取文件时是先找到文件的inode,并分析inode记录的权限与用户是否符合,若符合才能读取文件的内容,也就是block的内容。
如果文件的内容很大,那么可能会花费很多的block,但是inode的大小才128byte,那么如何记录数量很多的block号码,所以Ext2文件系统将inode记录block号码的区域定义为12个直接、一个间接、一个双间接和一个三间接记录区。inode的结构如下图。其中的12个直接就是直接保存了存放实际数据的block的号码;而一个间接就是再拿一个block来当作记录保存了实际数据的block号码的记录区;双间接就是第一个block仅指出下一个记录编号的block在那里,实际记录在第二个block中,三间接就是利用第三层block来记录编号。
有了12个直接、一个间接、一个双间接和一个三间接记录区,那么inode能记录多少个block呢?以1KB的block来说明。计算如下:
- 12个直接:由于是直接,所以能记录12个block编号。
- 一个间接:由于间接是拿一个block来记录存放了实际数据的block的编号,这里的block大小为1KB,而记录一个block需要花掉4byte,所以这个间接能记录(1KB * 1024)byte / 4byte = 256,所以该间接能记录256个block编号。
- 一个双间接:双间接是使用第二层block来记录存放了实际数据的block的编号,由上面的间接可以发现第一层能记录256个block,这256个block在双间接中就是处于第二层,所以它们每个又能记录256个block编号,所以双间接能记录256 * 256 = 65535个block编号。
- 一个三间接:由上面的推断可以断定在三间接中第一层block能记录256个第二层,每个第二层又能256个第三层,每个第三层的block又能记录256个block编号,所以三间接能记录256 * 256 * 256 = 16777216个编号。
- 总额:将12个直接、一个间接、一个双间接和一个三间接能记录的block编号的个数相加,即12 + 256 +65535 + 16777216 = 16843019,所以它们总共能记录16843019个block编号,而由于这里的每个block大小为1KB,所以总共的大小为16843019KB,即大约为16G,所以当文件系统将block格式化为1KB大小时,能够容纳的单一文件的最大容量为16G。
- 注意:以上的计算方法不能用在2KB和4KB的block大小的计算中,因为2KB的block将会受到Ext2文件系统本身的限制。
4、super block(超级块)
super block主要记录的信息与特性如下:
- block与inode的总量。
- 未使用与已使用的inode/block数量。
- block与inode的大小。
- 文件系统的挂载时间、最近一次写入数据的时间、最近一次检验磁盘的时间等文件系统相关信息。
- 一个valid bit数值,若此文件系统已被挂载,则valid bit为0,若未挂载则为1。
- 一般情况下,super block大小为1024byte。
- 每个block group都可能含有super block,但是一个文件系统应该仅有一个super block而已,事实上,除了第一个block group内会含有super block之外,其它block group不一定含有super block,而若含有则该super block主要是作为第一个block group内的super block的备份。
5、文件系统描述
该区段可以描述每个block group的开始与结束的block号码,以及说明每个区段(super block、bitmap、indoemap、data block)分别介于哪一个block号码之间。
6、块对应表(block bitmap)
当要添加新文件时,则要用block来存放其内容,那么从块对应表中就可以知道哪些block是空的,就可以找到空的block来存放新文件的数据;同样,当删除一个文件时,文件原本占用的block号码就要释放出来,此时在块对应表中相对应到该block号码的标志就要修改为“未使用”。
7、inode对应表(inode bitmap)
与block对应表功能类似,只不过它记录的是使用与未使用的inode号码。
四、使用dumpe2fs命令来查看文件系统的信息
使用“dumpe2fs 设备文件名”可以查看文件系统的相关信息,如下图是使用该命令(dumpe2fs /dev/sda2)查看我的/目录所挂载的设备的文件系统的部分信息,可以发现block group内的所有信息都是以block的号码来表示的,各部分数据都与block有关。注意其中画红色方框的上部分,这部分表示inode table分布在643~1666的block号码中,总共有1666 - 643 + 1(643本身) = 1024个block花在inode table上,我这个文件系统采用的block大小为4KB,所以inode的数量共有(1024 * 4KB * 1024)byte / 128byte = 32768(每个inode为128byte大小)个inode在block group0中。正好与下面一个红色方框中的数字相符。
五、文件系统与目录树的关系
1、在Linux中不管是一般文件还是目录文件都会占用一个inode,其可依据文件(一般文件和目录统称文件)内容的大小来分配一些block给该文件使用。只不过一般文件是实际记录数据内容,而目录文件的内容是记录该目录中的文件名。
2、目录
当新建一个目录时,系统会分配一个inode与至少一个block给该目录。由上面的介绍可知,inode用于记录该目录的权限与属性,且记录分配到的那块block号码;至于分配给目录的block则是记录在这个目录下的文件名与该文件名占用的inode号码数据。目录所占用的block记录的信息如下图。
3、目录大小、目录内文件大小与block大小的关系
让我们看看根目录所挂载的设备的文件系统采用的block的大小是多大,如下图,可以发现block为4KB大小。
那么,让我们在/tmp目录下新建一个目录叫做test,然后我在test目录下放入了一个大小约为31MB左右的压缩包,如下图:
注意观察,test目录的大小为4096byte,而该目录下的nexus-2.2-01-bundle.zip文件大小约为31MB左右,可以发现目录的大小并不是该目录内所有文件大小的总和,与目录内文件大小无关。那么该目录大小为4096是如何来的啊?因为上上图可以发现根目录所挂载的设备的文件系统的block的大小为4096,因为该目录并不复杂,只占用了一个block,所以该目录大小为4096。如果一个目录的内容很复杂,文件数太多,那么该目录可能会占用多个block,那么目录的大小就会是block大小的整数倍,如下图:其中的/sbin目录的大小为12288,就是大小为4096byte的block的3倍,该目录就是占用了3个大小为4096byte的block。那么为什么其中还有大小为1024byte的/boot目录和大小为0的/proc目录呢?那是因为/boot为独立的分区,和/目录不是同一个分区,/boot目录所挂载的分区的文件系统采用的block大小为1KB。而/proc目录是不占用硬盘容量的,它放置的数据都是在内存中的。
4、文件
当新建一个一般文件时,会分配一个inode和相对于该文件大小的block数量给该文件。比如文件系统的block为4KB,要新建一个100KB大小的文件,那么将会分配一个inode和25个block给该文件。注意:由于inode只有12个直接,所以还需要多一个block来作为块号码的记录。
5、目录树的读取
从上面目录的介绍中,能知道inode本身不记录文件名,文件名的记录是在目录的block中。新增/删除/重命名文件名等操作与目录的w权限有关就是因此原因。所以要读取某个文件时,就会经过该文件所在的目录的inode与block,然后才能找到该文件的inode号码,最终才能读到该文件的block中的数据。
由于目录树是由根目录开始,所以系统可以通过挂载的信息找到挂载点的inode号码(通常一个文件系统的最顶层inode号码会由2号开始),然后就能得到根目录的inode内容,并依据该inode读取根目录的block内的文件名数据,再一层一层地往下读就可以读到正确的文件名。比如要读取/etc/passwd文件,读取流程如下:
- /的inode:通过挂载点的信息找到/dev/sda2的inode号码为2的根目录inode,且根目录的inode记录的权限让root帐号可以读取该inode指向的block的内容。
- /的block:经过上个步骤可以取得根目录inode所记录的block的号码,所以可以找到etc/目录的inode号码(1835009)。
- etc/的inode:读取1835009号inode得知root具有rwx权限,所以可以读取etc/的inode所记录的block内容。
- etc/的block:经过上个步骤取得etc/目录的inode记录的block号码,并找到passwd文件的inode号码(1837426)。
- passwd的inode:读取1837426号的inode得知root帐号具有rw的权限,所以可以读取passwd文件的inode所记录的block的内容。
- passwd的block:将该block内容读取出来。
六、文件系统大小与磁盘读取性能
1、如果文件系统很大时,由于硬盘上面的数据是经常变动的,所以整个文件系统上面的文件通常无法连续写在一起,即block号码不会连续,而是填入式的将数据填入空闲的block中,如果文件写入的block很分散,可能就会造成文件数据离散的问题。虽然ext2的每个inode记录了block号码,数据可以一次性读取,但是如果文件分散过于厉害,读取的效率就可能会很低,因为磁头还是得要在整个文件系统中频繁的读取。解决办法为:将整个文件系统内的数据全部复制出来,将该文件系统重新格式化,再将数据复制回去。
2、如果文件系统很大,当一个文件分别记录在文件系统的最前面和最后面的block号码中,此时会造成硬盘的机械手臂移动幅度过大,而造成数据读取性能低。且磁头在搜寻整个文件系统时也会花费很多的时间。
3、所以分区的规划并不是越大越好,要针对主机的用途来进规划。
七、Ext2/Ext3文件的访问与日志文件系统的功能
1、Ext2文件系统对新建文件或目录的过程如下:
- 先确定用户对于要添加的文件所在的目录是否具有w与x的权限,若有的话才能进行添加。
- 根据inode bitmap找到空闲的inode号码,并将文件的权限/属性写入。
- 根据block bitmap找到空闲的block号码,并将实际的数据写入block中,且更新inode的block指向数据。
- 将以上写入的inode和block数据同步更新到inode bitmap和block bitmap,并更新super block的内容。
2、就以上新建文件的过程,如果在写入inode和block后发生了错误导致系统不能同步更新inode bitmap和block bitmap,那么就会产生数据不一致的情况,在早起的Ext2文件系统中,如果发生了这个问题,那么系统在重启时,就会通过super block中记录的valid bit与文件系统的state(clean与否)等状态来判断是否强制进行数据一致性的检查。这样的检查很费时,因为要针block bitmap、inode bitmap、super block等中间数据与实际数据存放区来进行比对,要搜寻整个文件系统,
3、日志文件系统
为了解决文件系统数据不一致的情况,可以在文件系统中规划一个块,该块专门记录写入或修改文件时的步骤,具体如下:
- 预备:当系统要写入一个文件时,会先在日志记录块中记录某个文件准备要写入的信息。
- 实际写入:开始写入文件的权限与数据;然后开始更新block bitmap、inode bitmap、super block等中间数据。
- 结束:完成数据与中间数据的更新后,在日志记录块中完成该文件的记录。
这样做的好处是,如果在数据的记录过程中发生了问题导致数据不一致,系统只需要去检查日志记录块就可以知道哪个文件发生了问题,针对该问题来做一致性的检查即可,而不必针对整个文件系统去检查。
Ext2文件系统要达到这样的功能是通过Ext3文件系统来实现的,Ext3是Ext2的升级版,且可向下兼容Ext2。
八、Linux文件系统的操作
1、Linux的异步处理
当系统加载一个文件到内存后,如果该文件没有被改动过,则在内存区段的文件数据会被设置为clean的。但若内存中的文件数据被更改过了,此时该内存中的数据会被设置为Dirty,此时所有的操作都还在内存中进行,并没有写入到磁盘中,系统会不定时地将内存中设置为Dirty的数据写回磁盘,以保持磁盘与内容数据的一致性。也可以使用sync命令来手动强迫写入磁盘。
2、Linux文件系统与内存的关系
- 系统会将常用的文件数据放置到主存储器的缓冲区,以加速文件系统的读/写。所以Linux的物理内存最后都会被用光。
- 若正常关机时,关机命令会主动调用sync命令来将内容的数据回写入磁盘内。
- 若不正常关机时,由于数据尚未写入磁盘内,因此重启后可能会花很多的时间在进行磁盘检验,甚至可能导致文件系统的损毁(非磁盘损毁)。
九、挂载点的意义
1、将文件系统与目录树结合的操作称为挂载。
2、挂载点一定是目录,该目录为进入该文件系统的入口。所以一个文件系统必须要挂载到目录树的某个目录后,才能够使用该文件系统。
3、在Linux中一切都是文件,那么磁盘也是文件,有一个文件名,一个分区也是一个文件,有文件名;从上面的目录树介绍中我们可以知道文件名是保存在目录的block中的,那么要使用一个文件,就要知道一个文件所在的目录,因为根据该目录才能找到目录的block,才能找到对应的文件名,所以文件系统需要挂载到目录嘛。
4、如下图所示,在我的系统中有三个分区(除去最后一个tmpfs,这里一个分区就是一个文件系统),对应三个挂载点,而查看每个挂载点的inode号码时,它们的inode均为2(每个文件系统都有独立的inode、block与super block等信息,且文件系统最顶层的目录的inode一般为2号),且每一行的文件属性不同,三个挂载点也均不同,所以可以发现/、/boot、/home为三个不同的文件系统。
4、“.”表示当前目录,而“..”表示当前目录的上一层目录;但是在根目录(/)的“.”与“..”是相同的东西,为什么呢?如下图,由于挂载点均为/,所以这三个目录均在同一个文件系统内,且这三个目录的inode均为2,所以这三个目录都指向同一个inode号码,而从inode的介绍中我们知道同一个文件系统的某个inode只会对应到一个文件内容而已,因为一个文件占用一个inode的原因,所以这三个目录的内容也就是一样的,所以根目录的上层(/..)就是它自己。
十、Linux VFS
1、整个Linux系统是通过一个名为Virtual Filesystem Switch(虚拟文件系统,VFS)的内核功能去读取文件系统的,即整个Linux认识的文件系统其实都是VFS在进行管理的,用户并不需要知道每个分区上面的文件系统是什么,VFS会做好读取的操作。比如假设/使用的是/dev/hda21,用的是ext3文件系统,而/home使用的是/dev/hda2,reiserfs文件系统,当读取/home/jgao/.bashrc文件时,我们都不需要指定要用什么文件系统的模块来读取,VFS会帮我们管理。VFS文件系统示意图如下。