当我们在 Linux 下的 ext2 文件系统创建一个目录时, ext2 会分配一个 inode 与至少一块 block 给该目录。其中,inode 记录该目录的相关权限与属性,并可记录分配到的那块 block 号码; 而 block 则是记录在这个目录下的文件名与该文件名占用的 inode 号码数据。也就是说目录所占用的 block 内容在记录如下的信息:
[root@www ~]# ls -li
total 92
654683 -rw------- 1 root root 1474 Sep 4 18:27 anaconda-ks.cfg
648322 -rw-r--r-- 1 root root 42304 Sep 4 18:26 install.log
648323 -rw-r--r-- 1 root root 5661 Sep 4 18:25 install.log.syslog
[root@www ~]# ll -d / /bin /boot /proc /lost+found /sbin
drwxr-xr-x 23 root root 4096 Sep 22 12:09 /
drwxr-xr-x 2 root root 4096 Sep 24 00:07 /bin
drwxr-xr-x 4 root root 1024 Sep 4 18:06 /boot
drwx------ 2 root root 16384 Sep 5 01:49 /lost+found
dr-xr-xr-x 96 root root 0 Sep 22 20:07 /proc
drwxr-xr-x 2 root root 12288 Sep 5 12:33 /sbin
文件:
当我们在 Linux 下的 ext2 创建一个一般文件时, ext2 会分配一个 inode 与相对于该文件大小的 block 数量给该文件。例如:假设我的一个 block 为 4 Kbytes ,而我要创建一个 100 KBytes 的文件,那么 linux 将分配一个 inode 与 25 个 block 来储存该文件! 但同时请注意,由于 inode 仅有 12 个直接指向,因此还要多一个 block 来作为区块号码的记录。
目录树读取:
由于目录树是由根目录开始读起,因此系统透过挂载的信息可以找到挂载点的 inode 号码(通常一个 filesystem 的最顶层 inode 号码会由 2 号开始喔!),此时就能够得到根目录的 inode 内容,并依据该 inode 读取根目录的 block 内的文件名数据,再一层一层的往下读到正确的档名。
[root@www ~]# ll -di / /etc /etc/passwd
2 drwxr-xr-x 23 root root 4096 Sep 22 12:09 /
1912545 drwxr-xr-x 105 root root 12288 Oct 14 04:02 /etc
1914888 -rw-r--r-- 1 root root 1945 Sep 29 02:21 /etc/passwd
/ 的 inode:
透过挂载点的信息找到 /dev/hdc2 的 inode 号码为 2 的根目录 inode,且 inode 规范的权限让我们可以读取该 block 的内容(有 r 与 x) ;
/ 的 block:
经过上个步骤取得 block 的号码,并找到该内容有 etc/ 目录的 inode 号码 (1912545);
etc/ 的 inode:
读取 1912545 号 inode 得知 vbird 具有 r 与 x 的权限,因此可以读取 etc/ 的 block 内容;
etc/ 的 block:
经过上个步骤取得 block 号码,并找到该内容有 passwd 文件的 inode 号码 (1914888);
passwd 的 inode:
读取 1914888 号 inode 得知 vbird 具有 r 的权限,因此可以读取 passwd 的 block 内容;
passwd 的 block:
最后将该 block 内容的数据读出来。
EXT2/EXT3 文件的存取与日志式文件系统的功能
上一小节谈到的仅是读取而已,那么如果是新建一个文件或目录时,我们的 Ext2 是如何处理的呢? 这个时候就得要 block bitmap 及 inode bitmap 的帮忙了!假设我们想要新增一个文件,此时文件系统的行为是:
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 block 称为数据存放区域,至于其他例如 superblock、 block bitmap 与 inode bitmap 等区段就被称为 metadata (中介数据) 啰,因为 superblock, inode bitmap 及 block bitmap 的数据是经常变动的,每次新增、移除、编辑时都可能会影响到这三个部分的数据,因此才被称为中介数据的啦。
日志式文件系统 (Journaling filesystem)
为了避免上述提到的文件系统不一致的情况发生,因此我们的前辈们想到一个方式, 如果在我们的 filesystem 当中规划出一个区块,该区块专门在记录写入或修订文件时的步骤, 那不就可以简化一致性检查的步骤了?也就是说:
1.预备:当系统要写入一个文件时,会先在日志记录区块中纪录某个文件准备要写入的信息;
2.实际写入:开始写入文件的权限与数据;开始升级 metadata 的数据;
3.结束:完成数据与 metadata 的升级后,在日志记录区块当中完成该文件的纪录。