Linux filesystem
文件系统的运作与操作系统的文件数据有关。较新的操作系统的文件数据除了文件实际内容外,通常含有非常多的属性,例如Linux操作系统的文件权限(rwx)与文件属性(属主、属组、时间参数等)。文件系统通常会将这两部分数据存放在不同的区块,权限与属性放置到inode 中,实际数据则放置到data block 中。还有一个超级区块(superblock) 会记录整个文件系统的整体信息,包括inode与block 的总量、使用量、剩余量等。
由于每个inode与block都有编号,而每个文件都会占用一个inode,inode内则存有文件数据放置的block号码,因此,如果能够找到文件的inode,自然就能知道这个文件放置数据的block 号码,当然就能读取该文件的实际数据了。这种数据存取方法称为索引式文件系统(indexed allocation)。
Ext2就是索引式文件系统。
文件系统一开始就将inode与block规划好了,除非重新格式化(或利用resize2fs等指令变更文件系统大小),否则inode 与block 固定后就不再变动。
data block:
data block 是用来放置文件内容数据的,在Ext2 文件系统中所支持的block 大小有1K,2K,4K 三种。在格式化时block 的大小就固定了,而且每个block 都有编号,以便inode 记录。由于block 大小的差异,会导致该文件系统能够支持的最大磁盘容量与最大单一文件容量并不相同。
每个block 内最多只能放置一个文件的数据。
如果文件大于block 的大小,则一个文件会占用多个block。
如果文件小于block,则该block 的剩余容量就不能再存放其他文件。
至于到底该选择多大的block,师实际情况而定。
inode table:
inode 记录的文件数据至少有以下这些:
该文件的存取模式(read/write/excute)
该文件的属主与属组(owner/group)
该文件的容量
该文件创建或状态改变的时间(ctime)
最近一次的读取时间(atime)
最近一次的修改时间(mtime)
定义文件特性的flag,比如SetUID
该文件真正内容的指向(pointer)
inode 的数量与大小也在格式化时就固定了,
每个inode 大小均固定为128bytes(ext4 可设为256bytes)
每个文件只占用一个inode,因此文件系统能够建立的文件数量与inode数量有关
系统读取文件时,需要先找到inode,并分析inode 所记录的权限与用户是否符合,若符合才能够开始实际读取block 的内容。
Ext2 的inode/block 与文件大小的关系:
一个inode 大小为128bytes,而inode 记录一个block 号码要花掉4bytes。这时采取的策略是定义12个直接,一个间接,一个双间接,一个三间接记录区。
superblock:
记录的信息主要有以下这些:
block 与inode 的总量
未使用与已使用的inode/block 数量
block 与 inode 的大小(block 为1,2,4K,inode 为128,256bytes)
filesystem 的挂载时间、最近一次写入数据的时间、最近一次检验磁盘的时间等文件系统的相关信息。
一个valid bit 数值,若此文件系统已被挂载,则valid bit 为0,若未被挂载,则valid bit 为1。
superblock 的大小为1024bytes。
dumpe2fs: 查询Ext 家族superblock 信息的指令
df 与dumpe2fs 配合使用
输出的部分结果:
Group 0: (Blocks 0-32767) # 第一块 block group 位置
Checksum 0x13be, unused inodes 8181
Primary superblock at 0, Group descriptors at 1-1 # 主要 superblock 的所在喔!
Reserved GDT blocks at 2-128
Block bitmap at 129 (+129), Inode bitmap at 145 (+145)
Inode table at 161-672 (+161) # inode table 的所在喔!
28521 free blocks, 8181 free inodes, 2 directories, 8181 unused inodes
Free blocks: 142-144, 153-160, 4258-32767 # 底下两行说明剩余的容量有多少
Free inodes: 12-8192
文件系统与目录树的关系
目录:
当在Linux下的文件系统创建一个目录时,文件系统会分配一个inode 与至少一块block 给该目录。其中,inode 记录该目录的相关权限与属性,并可记录分配到的那块block 号码;而block 则是记录在这个目录下的文件名与该文件名占用的inode 号码数据。
查看某目录内的文件所占用的inode 号码
ls -i
执行 ll / 命令,出现的目录几乎都是1024的整倍数,这还是与block的单位大小有关。
dr-xr-xr-x 253 root root 0 3月 20 09:42 proc/ # /proc 不占用磁盘容量,所以为0.
文件:
假设一个block 为4K,那么创建一个100K 的文件,除了分配一个inode 与25个block 来存储该文件外,还需要多一个block 来作为区块号码的记录(因为一个inode 仅有12个直接指向)
目录树读取:
inode 本身并不记录文件名,文件名的记录是在目录的block中。因此当我们要读取某个文件时,就会经过目录的inode 与block,然后才能找到那个待读取文件的inode 号码,最终才会读到文件的block 数据。
由于目录树是由根目录开始读起,因此系统通过挂载的信息可以找到挂载点的inode 号码,此时就能够得到根目录的inode 内容,并依据该inode 读取根目录的block 内的文件名数据,再一层一层往下读到正确的文件名。
以读取 /etc/passwd中的内容为例:
创建文件时文件系统的行为:
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 table 称为数据存放区域,superblock、block bitmap、inode bitmap 称为metadata。
数据不一致状态:
一般情况下,上述新增动作可以顺利完成。但也有万一,例如在文件写入文件系统时,因为突然断电、系统核心发生错误等原因导致系统中断,所以写入的数据仅有inode table 及data block,而最后一个同步更新步骤没有完成,就会发生metadata 的内容与实际数据存放区产生不一致。
在早起的Ext2 文件系统中,如果发生数据不一致问题,那么系统在重新启动时,就会藉由superblock 中记录的valid bit(是否有挂载) 与filesystem state(clearn 与否)等状态来判断是否强制进行数据一致性检查。这个过程是很费时的。这就催生了日志式文件系统(Journaling filesystem)。
日志式文件系统:
在文件系统中另开辟一个区块,专门记录写入或修改时的步骤。
1). 预备:当系统要写入一个文件时,会先在日志记录区块中记录某个文件准备要写入的信息;
2). 实际写入:开始写入文件的权限与数据;更新metadata 的数据;
3. 结束:完成数据与metadata 的更新后,在日志记录区块中完成该文件的记录。
这样,在数据出现问题时,只要去检查日志记录区块,就可以知道哪个文件发生了问题,然后针对该问题做一致性检查即可,速度大大加快。
Ext3、Ext4就是日志式文件系统。通过dumpe2fs 可以看到superblock 里面含有下面的信息:
通过inode 8 记录journal 区块的block 指向,而且有8MB 的容量在处理日志。
磁盘写入的速度比内存慢得多,这会影响读写效率。为了解决这个问题,Linux有一个异步处理的方式。
当系统加载一个文件到内存后,如果该文件没有被更动过,则在内存区段的文件数据会被设定为干净的(clean)的。如果内存中文件数据被更动了,内存中的数据就会被设定为脏的(dirty),此时所有的动作都还在内存中,并没有写入磁盘,系统会不定时地将内存中设定为dirty的数据写回磁盘,以保持磁盘与内存数据的一致性。可以利用sync 指令来手动写入磁盘。
若正常关机,关机指令会主动调用sync 来将内存中的数据回写到磁盘。
每个filesystem 都有独立的inode/ block/ superblock 等信息,这个文件系统要能够链接到目录树才能被使用。将文件系统与目录树结合的动作称为挂载。挂载点一定是目录,该目录是进入该文件系统的入口。
查看系统支持哪些文件系统:
$ ls -l /lib/modules/$(uname -r)/kernel/fs
查看系统目前已加载到内存中文件系统:
$ cat /proc/filesystems
Linux 通过一个名叫Virtual Filesystem Switch(VFS) 的核心功能去管理filesystem。