1. 磁盘布局
1.1 分区
一个磁盘可分为多个分区, 每个分区须先用格式化工具(如mkfs)格式化成指定格式的文件系统, 才能用于存储文件.
磁盘文件系统布局:
1.2 块
block, 文件系统中的最小存储单位, 大小在格式化时规定
设置方式, 格式化时输入命令:
$ mke2fs -b 1024 # 通常1024, 2048, 或 4096
1.3 自举块/启动块/Boot Block
用于存放磁盘分区信息和启动信息, 其大小是确定的, ext2文件系统启动块大小是1KB, 由PC标准规定. 任何文件系统都不能使用启动块. 启动块之后, 才是ext2文件系统.
1.4 柱面组/块组/Block Group
分区 = 自举块 + 超级块 + 柱面组0..n. 每个柱面组大小一样.
而柱面组 = 超级块 + 配置信息 + i节点图 + 块位图 + i节点数组(i节点0..m) + 数据块
柱面组组成:
1) 超级块/Super Block
描述整个分区的文件系统信息, 例如块大小, 文件系统版本号, 上次mount(挂载)时间等.
超级块在每个块组开头都有一份拷贝(图中称为超级块副本).
超级块丢失 => 整个块组的数据丢失
2) 配置信息
在ext2~4文件系统中, 这部分称为块组描述符表(GDT, Group Descriptor Table), 由很多块组描述符组成, 本分区有多少个块组就有多少个块组描述符.
每个块组描述符(Group Descriptor)存储一个块组的描述信息, 如该块组从哪儿开始是inode表(i节点数组), 从哪儿开始是数据块(Data Blocks), 空闲inode和数据块还有多少个等.
同超级块, 块组描述符在每个块组的开头也有一份拷贝.
块组描述符丢失 => 整个块组的数据丢失
3) i节点图/inode Bitmap
本身占一个块, 如4096byte (4KB), 其中每个bit表示一个inode(i节点)是否空闲.
4) 块位图/Block Bitmap
每个bit位代表本块组中的一个块是否空闲,
- 1 表示该块已用;
- 0 表示该块空闲;
一个块组(Block Group, 柱面组)中的块是这样利用的:
数据块存储所有文件的数据, 如某个分区的块大小1024byte, 某个文件2049byte, 就需要3个数据块存储: 前2个数据块都存放1024byte, 第3个数据块存放1byte;
5)i节点数组/inode Table
inode这里的i可用理解成information node, inode Table专门用于存放文件的描述信息(区别于文件数据), 如文件类型(常规, 目录, fifo文件, 符号链接等), 访问权限, 文件大小, 创建、最后一次修改/访问时间(可用ls -l命令查询).
每个文件都有一个inode, 一个块组(Block Group)中所有inode组成inode表.
inode表总共占多少个块在格式化的时候, 就要决定并写入块组描述符, 由GDT/配置信息管理. mke2fs(格式化工具)的默认策略是一个块组有多少个8KB, 就分配多少个inode.
mke2fs -i命令可以手动指定每多少个字节分配一个inode.
6) 数据块/Data Blocks
不同文件类型, 有不同的存储情况:
- 常规文件
文件的数据存储在数据块中
- 目录
目录下所有文件名和目录名存放在数据块中, 除文件名外, ls -l命令查看到的所有信息都保存在inode中.
注意: 文件名是存放在所在目录的数据块中, 而非inode中.
- 符号链接
符号链接的文件内容就是目标路径名.
如果目标路径名较短, 则直接保存在inode中, 以便快速查找; 如果目标路径名较长, 则分配一个数据块来保存.
---- 疑问: 何为路径名较短, 标准是什么? 如何查看和设置?
- 设备文件/FIFO/socket等特殊文件
没有数据块, 设备文件的主设备号和此设备号, 保存在inode中.
创建testdir后的文件系统实例, 表明硬链接所代表的链接计数如何计算.
注意:
1. 叶子目录(没有子目录的目录)链接计数为2, 分别是"."和命名该目录的目录项(我的理解一般是"..");
2. 普通文件(非目录)链接计数为1, 因为只有当前目录(".", 普通文件的父目录)指向普通文件;
3. (link)不允许构造指向目录的硬链接, 因为一旦构成循环的硬链接, 很难消除;
硬链接和符号链接的区别:
1)inode链接计数
硬链接是文件的别名, 每增加一个, 文件对应的i节点的链接计数+1. 链接计数表示, 目录块中指向i节点编号的目录项的个数;
符号链接是文件的间接指针, 其文件内容直接存储链接的文件的路径名, 不会影响链接计数;
2)所处位置
硬链接一般要求链接和文件位于同一个文件系统中;
符号链接没有这个限制;
3)创建权限
只有root用户才能创建硬链接;
符号链接没有这个限制;
具体验证方法, 可查看下面的实验.
2. FAQ
2.1 如何查看一个数据块的大小(Block Size)?
参见 Linux查看系统块大小
(1)stat查看 根目录"/" 所在磁盘分区的Block Size
$ stat -f / 文件:"/" ID:7e5c5070d17ef5e7 文件名长度:255 类型:ext2/ext3 块大小:4096 基本块大小:4096 块:总计:7220231 空闲:3479622 可用:3107091 Inodes: 总计:1843200 空闲:1533150
这里4096(byte)就是Block Size
(2)fdisk -l查看指定磁盘分区的Block Size (/dev/sda?, 根据实际需要查询的分区决定)
$ sudo fdisk -l /dev/sda6 Disk /dev/sda6:44 GiB,47227863040 字节,92241920 个扇区 单元:扇区 / 1 * 512 = 512 字节 扇区大小(逻辑/物理):512 字节 / 4096 字节 I/O 大小(最小/最佳):4096 字节 / 4096 字节
这里4096就是Block Size
(3) tune2fs命令查看指定分区的Block Size
$ sudo tune2fs -l /dev/sda6 | grep "Block size" Block size: 4096
(4)blockdev命令查看指定分区的Block Size
$ sudo blockdev --getbsz /dev/sda6 4096
2.2 如何查看文件系统类型?
使用lsblk命令, 参见 如何查看linux文件系统类型?
$ lsblk -f
2.3 如何创建并查看符号链接?
使用ln -s命令创建, ls -l命令查看
如果已经有了hello文件, 则不用touch命令创建. 用ln命令创建了halo后, 发现hello的硬链接数1不变, 而halo文件大小为7byte, 即内容文件名./hello (7个字符).
$ touch hello $ ln -s ./hello halo $ ls -l 总用量 0 lrwxrwxrwx 1 martin martin 7 5月 15 00:59 halo -> ./hello -rw-r--r-- 1 martin martin 0 5月 15 00:58 hello
2.4 如何创建并查看硬链接?
假设已经用touch命令创建了hello. 在用ln命令创建了hello2后, 发现hello的硬链接数由原来的1变成了2, 而且新建的硬链接文件hello2链接数也是2(与hello一样).
我们知道, 普通文件硬链接数一般是1, 也就是说, 如果一个普通文件硬链接数>1, 说明有其他硬链接文件指向了该文件.
$ ln ./hello hello2 $ ls -l 总用量 0 lrwxrwxrwx 1 martin martin 7 5月 15 00:59 halo -> ./hello -rw-r--r-- 2 martin martin 0 5月 15 00:58 hello -rw-r--r-- 2 martin martin 0 5月 15 00:58 hello2
2.5 如果往文件写入数据, 是否会影响符号链接文件/硬链接文件?
往文件hello写3个字符"abc", 可以看到, 符号链接文件hallo并未受到影响, 而硬链接文件helo2文件大小改变.
$ cat hello abc $ ls -l 总用量 8 lrwxrwxrwx 1 martin martin 7 5月 15 00:59 halo -> ./hello -rw-r--r-- 2 martin martin 4 5月 15 01:05 hello -rw-r--r-- 2 martin martin 4 5月 15 01:05 hello2