“尽管内核是Linux内核,但文件缺失用户与操作系统交互所采用的主要工具”,这就阐述了“文件系统”的作用,如果只有Linux,没有文件系统,那么整个系统是没有意义的
在Linux中普通文件和目录文件保存在称为块物理设备的磁盘或者磁带上。一套Linux系统支持若干物理盘,每个物理盘可以定义一个或者多个文件系统。(类似于微机的磁盘分区)。每个文件系统由逻辑块的序列组成,一个逻辑盘空间一般划分为几个用途各不相同的部分,即引导块、超级块、inode区一级数据区等
引导块:在文件系统的开头,通常为一个扇区,其中存放引导程序,用于读入并启动操作系统;
超级块:用于记录文件系统的管理信息。特定的文件系统定义了特定的超级块;
inode区:索引节点,一个文件或者目录占据一个索引节点。第一个索引节点是该文件系统的根节点。利用根节点,可以把一个文件系统挂载在另一个文件系统的非叶节点上;
数据区:用于存放文件数据或者管理数据。
文件系统与根文件系统区别:
首先根文件系统也是文件系统的一类,该文件系统不仅具有普通文件系统的而存储数据文件的功能,而且相对于普通文件系统,它的特殊之处在于,它是内核启动所“挂载mount”的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导程序会在根文件系统挂载后从中把一些初始化脚本(如rcs,inittab)和服务加载到内存中运行,在嵌入式系统中,只是将内核下载到开发板,是无法真正的启动Linux系统的,会出现无法加载文件系统的错误
根文件系统中有一个“根”,说明它是加载其他文件系统的“根”,既然是根,没有这个根,其他的文件系统也就没有办法进行加载了,根文件系统是引导和使其他文件系统得以mount所必须的文件,根文件系统包括Linux启动时所必须的目录和关键性文件,例如Linux启动时所需要的init目录下的相关文件,在Linux挂载分区时Linux一定会找/etc/fstab这个挂载文件等,根文件系统中包括了很多应用程序bin目录等,包括这些linux系统启动所必须的文件都可以成为根文件系统
在linux中,将一个文件系统与一个存储设备关联起来叫“挂载”,使用指令mount,使用mount指令将一个文件附着到当前文件系统的层次结构中,在执行挂装时,需要提供文件类型、文件系统和一个挂载点,根文件系统被挂装到根目录“/”上后,在根目录下就有根文件系统的各个目录
制作根文件系统的时候需要根据需要剪裁busybox,然后编译busybox到内核中,重启系统会在目录中找到常用命令如ls,和工具vi等
ext2文件系统的储存布局:
Boot Block---Block Group0--------------------------------------------------------Block Group1--..........--Block Groupn
| | | | | |
SuperBlock GDT Block Bitmap Inode Bitmap Inode Table Data Blocks
首先明确Block(块),这个是文件系统中最小的储存单元,一个块的大小是在格式化的时候确定的
①Boot Block:启动块,大小是固定的,由PC标准规定就是1kb,用来存储磁盘分区信息和启动信息,任何文件系统都不能使用启动块。启动块是ext2文件系统的开始
②Block Group:块组,ext2文件系统将整个分区划分成若干个块组,每个块组都由SuperBlock,GDT ,Block Bitmap,Inode Bitmap,Inode Table ,Data Blocks构成
SuperBlock超级块:描述整个分区的文件系统信息,例如块大小,文件系统版本号,上次mount的时间等等。超级块在每个块组开头都由一份拷贝
GDT(Group Descriptor Table,块组描述符表) :由很多块组描述符组成,整个分区分成多少个块组就对应有多少个个块组描述符。每个块组描述符存储一个块组的描述符信息,例如在这个块组中从哪里开始是inode表,从哪里开始是数据块,空闲的inode和数据块还有多少个等等。和超级块类似,块组描述符表在每个块组的开头也有一个备份,这些信息时非常重要的,一旦超级块意外损坏就会导致丢失整个分区的数据,一旦块组描述符意外损坏会丢失整个块组的数据,因此他们有多份备份。通常内核只用到第0块个块组的备份,当执行e2fsck检查文件系统的一致性的时候,第0块组中的超级块和开组描述符表就会拷贝到其他块组,这样当第0个块组的开头意外损坏时就可以用其他备份来恢复,从而减少损失
Block Bitmap(块位图):一个块组的块是这样利用的:数据块存储所有文件的数据,比如某个分区的块大小是1024字节,某个文件是2049字节,那么就需要三个数据块来存储,即使第三个块只存储了一个字节也需要占用一个整块;超级块、块描述符表、块位图、inode位图、inode表这几部分存储该块组额描述信息。那么如何知道哪些块已经用于存储文件数据或其他描述信息,哪些块仍然空闲可用呢?块位图就是用来描述整个块组中哪些块已用哪些块空闲,它本身占用一个块,其中的每一个bit代表本块组中的一个块,这个bit为1表示该块已用,为0表示空闲可用
为什么用df命令统计磁盘的已用空间非常快?因为只需要查看每个块组的块位图就可以了,而不需要搜遍整个分区。相反,用du命令查看一个较大目录的已用空间会非常慢,因为不可避免的搜遍整个目录的所有文件
与此相联系的另外一个问题是:在格式化一个分区时究竟会划出多少个块组?主要的限制在于块位图本身必须只占一个块。用mke2fs格式化时默认块的大小是1024字节,可以用-b参数指定块大小,现在设块大小指定为b字节,那么一个块可以有8b个bit,这样代销的一个块位图就可以表示8b个块的占用情况,因此一个块组最多可以有8b个块,如果整个分区有s个块,那么就可以有s/8b个块组。格式化时可以用-g参数制定一个块组有多少个块,但是通常是手动设定,mke2fs工具会计算出最优的数值
inode位图(inode Bitmap):和块位图类似,本身占用一个块,其中每bit表示一个inode是否空闲可用
inode表(inode table):我们知道,一个文件除了数据需要储存外,还要存储一些描述信息,例如文件类型(常规、目录、符号链接等),权限,文件大小,创建/修改/访问时间等,也就是ls -l命令看到的那些信息,这些信息存储在inode中而不是数据块中。每个文件都有一个inode,一个块组中的所有inode组成了inode表(PS:所以有些时候,不能再存储文件,df发现存储空间还有空闲,但是无法存储,这个时候大多数情况就是inode满了)
inode表占多少个块在格式化时就要决定并写入块描述符中,mke2fs格式化工具的默认策略是一个块组有多少个8kb就分配多少个inode,由于数据块占了整个块组的绝大部分,也可以近似认为数据块有多少个8kb就分配多少个inode,换句话说,如果平均每个文件的大小是8kb,当分区存满的时候inode表会得到比较充分的利用,数据块也不浪费,如果这个分区存的都是很大的文件(比如电影),则数据块用完之后inode会有一些浪费。如果这个分区存的都是很小的文件,则有可能数据块还没有用完inode就已经用完了,数据块可能有很大浪费。如果用户在格式化时能够对这个分区以后要存储的文件带下做一个预测,也可以使用mke2fs的-i参数手动指定每个字节分配的inode(PS:这里存储文件的时候最好了解一些inode怎么分的,可以根据这个决定是否压缩或者解压缩)
数据块(Data Block):
a.对于常规文件,文件的数据存储在数据块中
b.对于目录,该目录下的所有文件名和目录名存储在数据块中,注意文件名保存在它所在的目录的数据块中,除文件名之外,ls -l命令看到的其他信息都保存在该文件的inode中。注意这个概念:目录也是一种文件,是一种特殊的文件
c.对于符号链接,如果目标路径名较短则直接保存在inode中以便更快的查找,如果目标路径名较长则分配一个数据块来保存
d.设备文件、FIFO和socket等特殊文件没有数据块,设备文件的主设备号和次设备号保存在inode中