文件系统
Linux使用文件系统来组织和管理硬盘,例如下图:
我们知道,磁盘的最小寻址单位是扇区(sector),一个扇区通常存储512Bytes,而操作系统如果一个扇区一个扇区的读取数据的话效率就太低了,所以文件系统又将几个扇区看作一块(block),块是操作系统对文件存取的最小单位。
例如,新建一个文件,填入很少的数据:
如果你用ls
命令去查看,可能确实显示这个文件只占了几个字节:
但想要查看一个文件到底在磁盘中占了多大的空间,需要使用du -sh
命令:
该文件在磁盘中实际占据了4KB的空间,这也就是这个文件系统的一个block的大小,所以说块是对文件存取的最小单位。
看上面的文件系统示意图,其中的Data blocks就是存储数据的块区域。那假如一个文件存在磁盘上,那文件系统又怎么知道具体存在哪些blocks中呢,这就引出了i-node。
i-node
文件系统为了管理存在其上的文件,为每个文件建立了一个i-node结构体,这个结构存储了对应文件的元信息,例如文件字节数、文件所有者ID、文件权限、硬链接数、文件所在的blocks序号等等。而文件系统上所有文件的i-node信息就构成了文件系统示意图中的inode Table。只要找到一个文件的i-node,就能找到对应的blocks从而找到文件。
当一个文件在文件系统中被建立,会同时分配一个文件名和一个i-node ID(即inode Table的索引)。可以通过命令ls -i
查看文件的i-node ID:
根据Unix万物皆文件的信条,其实目录也是一个文件,其中存储了该目录下所有文件的文件名与i-node ID的对应关系。
当一个用户或一个程序尝试通过文件名访问文件的时候,操作系统首先会通过文件名寻找到对应的i-node ID,之后便可以通过这个i-node节点中存储的信息来对文件进行更多的操作。所以可以说,在Unix-like系统中,文件名只是一个为了得到i-node节点的入口而已,文件名本身并不直接对应文件(与之对应,例如Windows等操作系统中,文件名直接对应文件)。
磁盘文件系统结构
上面已经介绍了文件系统中的Data Blocks和inode Table,下面是对其他部分的介绍。
当文件系统新建一个文件,可以想到,首先需要在Data blocks中找到空闲的块来存储文件,然后在inode Table中找到空闲的表项存储文件的i-node信息。而其实Data blocks和i-node表项非常非常多,如果一个一个检查是否空闲未免太慢了,于是又有了Block Bitmap和inode Bitmap,这两个位图就用来表示对应的block或inode表项是否空闲。
文件系统中还有一个重要的部分,即超级块(Super Block),超级块中存储了文件系统本身的结构信息。记录的信息主要有:一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统就被破坏了,所以每一个块组(见下段)中都有一份超级块的拷贝。
而文件系统又将整个磁盘分成若干个Block Group,每一组中都有上述的结构。
最后,每一个块组里还有一个块组描述符表(Block Descriptor Table),它由多个块组描述符组成,有多少个Block Group就有几个块组描述符。每个块组描述符(Block Descriptor)描述对应块组的描述信息,例如在这个块组中从哪里开始是inode Table,从哪里开始是Data Block,空闲的inode表项和数据块还有多少个等等。和超级块类似,块组描述符表同样十分重要,所以也在每一个块组中都有一份拷贝。通常文件系统只使用第0个块组中的拷贝。
硬链接
对于硬链接,其实就是不同的文件名指向了同一个i-node ID,前面说过,文件名其实就是找到i-node ID的入口而已,所以文件当然可以具有不同的文件名。而在i-node中记录了当前文件的硬链接数。当硬链接数为0时才从硬盘上删除这个文件。
一个小问题
在我学习的时候发现了一个小问题,用vim打开一个文件并进行了编辑,保存退出后按道理说文件还是原来那个文件,所以i-node的ID按道理来说并不会变,可现实总是事与愿违。
如图,i-node的ID居然变了,百思不得其解。
Google上有网友表示,这其实是vim的锅,https://unix.stackexchange.com/questions/36467/why-inode-value-changes-when-we-edit-in-vi-editor。
vim的文档中介绍了这样一个选项,backupcopy,文档中表示,当你用vim打开一个文件时,会自动生成一个该文件的备份,这就是为了在出现错误的时候可以恢复原来的文件。当你编辑一个文件的时候,vim其实会把你这个文件偷偷重命名,再新建一个完全一样的文件,所有的改动其实都是在这个新文件上改动,而这个新文件其实就是原来的文件名。所以,vim改动一个文件后,这个文件其实就不是以前的文件了,所以i-node的ID也理应会变化。
为了改变这一点,可以将backupcopy选项的值设为yes,在~/.vimrc
中加入这一句:
set backupcopy=yes
这样,vim的动作就会变为,新建一个文件,所有的改动都在新文件上进行,最后保存的时候再把新文件的内容覆盖回旧文件中,这样i-node的ID也就不会变化。