[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路。 ]
大家好,我是【WeiyiGeek/唯一极客】一个正在向全栈工程师(SecDevOps)前进的技术爱好者
作者微信:WeiyiGeeker
公众号/知识星球:全栈工程师修炼指南
主页博客: https://weiyigeek.top - 为者常成,行者常至
Linux文件元数据之inode表结构
描述:文件元数据(Metadata)是文件的属性,它描述了文件的基本信息,例如文件大小、创建时间、类型、权限等。其通常是存放在inode (index node
) 表中,inode 表中有很多条记录组成,第一条记录对应的存放了一个文件的元数据信息。
此处以ext4文件系统为例,每个 inode 表记录中大致包含以下信息:
inode Number 节点号
文件类型和访问权限;
文件所属用户 UID和组 GID;
文件大小和占用磁盘块数;
文件创建、修改和访问时间戳;
文件的硬链接数;
文件的数据块地址等。
温馨提示:如果小伙伴们在其他平台看到此文章,一定要关注作者首发公众号《全栈工程师修炼指南》,给作者持续创作的动力!
具体来说,一个 inode 结构体通常包含以下字段:
struct ext4_inode {
__le16 i_mode; // 文件类型和访问权限
__le16 i_uid; // 文件所属用户 ID
__le32 i_size_lo; // 文件大小
__le32 i_atime; // 上次访问时间
__le32 i_ctime; // 创建时间
__le32 i_mtime; // 上次修改时间
__le32 i_dtime; // 删除时间
__le16 i_gid; // 文件所属组 ID
__le16 i_links_count; // 硬链接数
__le32 i_blocks_lo; // 占用磁盘块数
__le32 i_flags; // 文件标志
__le32 i_block[EXT4_N_BLOCKS]; // 数据块地址
__le32 i_generation; // 文件版本号
__le32 i_file_acl_lo; // 文件 ACL
__le32 i_size_high; // 文件大小(高位)
__le32 i_obso_faddr; // 文件的 fragment 地址
union {
struct {
__le32 l_i_version;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
} osd1; // 操作系统相关数据
union {
struct {
__le16 l_i_blocks_high;
__le16 l_i_file_acl_high;
__le16 l_i_uid_high;
__le16 l_i_gid_high;
__u16 l_i_checksum_lo; // 低位校验和
__u16 l_i_reserved;
} linux2;
struct {
__le16 h_i_reserved1;
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_author;
} hurd2;
struct {
__le16 h_i_reserved1;
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_reserved2[2];
} masix2;
} osd2; // 操作系统相关数据
};
其中比较重要的字段包括:i_mode
、i_uid
、i_gid
、i_links_count
、i_size_lo
、i_atime
、i_ctime
、i_mtime
、i_blocks_lo
和 i_block
。
1.直接块指针,直接指向内存的数据区域,拥有12个直接指针,由于每个Block大小为
4096B(4KB)
,则前12直接指针可保存48KB文件。2.间接指针,别称一级指针,其可以存储文件大小为
1024*4096=4MB
,存放1024
个指针,每个指针又指向一个Block(4KB)。3.双重间接块指针,别称二级指针,其可存储文件大小为
1024*1024*4096=4GB
,存放1024*1024
个指针,每个指针又指向一个Block(4KB)。4.三重间接块指针,别称三级指针,其可存储文件大小为
1024*1024*1024*4096=4TB
,存放1024*1024*1024
个指针,每个指针又指向一个Block(4KB)。
从上图中可知在 ext4 文件系统中,目录是个特殊文件,目录文件的内容保存了此目录中的文件的列表及inode Number
对应关系, 用户通过文件名访问文件时,首先在目录中查找文件的inode Number
,然后根据inode Number
找到对应的文件。
所以,一般inode表会占用文件系统磁盘空间的1%左右,一个目录文件的内容就是一个该目录下所有文件的目录项的列表。
# 查看 /boot 分区信息
$ df -Th /boot/
文件系统 类型 容量 已用 可用 已用% 挂载点
/dev/sda2 xfs 960M 251M 710M 27% /boot
$ df /boot
文件系统 1K-块 已用 可用 已用% 挂载点
/dev/sda2 983040 256144 726896 27% /boot
# 查看 /boot 分区 Inodes 总数量、已用、可用
$ df -i /boot
文件系统 Inodes 已用(I) 可用(I) 已用(I)% 挂载点
/dev/sda2 524288 22 524266 1% /boot
# 创建新文件验证系统 inodes 数量是否会新增
$ dd if=/dev/zero of=/tmp/test/file.txt bs=1M count=100
$ df -i /tmp/dir01
文件系统 Inodes 已用(I) 可用(I) 已用(I)% 挂载点
/dev/mapper/rl-root 35010560 47121 34963439 1% /
$ dd if=/dev/zero of=/tmp/test/file1.txt bs=1M
$ df -i /tmp/dir01
文件系统 Inodes 已用(I) 可用(I) 已用(I)% 挂载点
/dev/mapper/rl-root 35010560 47122 34963438 1% /
cp 命令复制文件目录时inode变化
首先,分配一个空闲的inode号,并在inode表中生成新条目。 其次,在目录中创一个目录项,将新条目指向inode号(关联)。 最后,将文件数据块拷贝到inode号对应的磁盘块中。
$ ls -li
134349770 -rw-r--r--. 1 root root 23 3月 24 16:12 issue~
$ cp issue~ issue~.bak
$ ls -li issue~.bak
134612838 -rw-r--r--. 1 root root 23 3月 25 02:13 issue~.bak
rm 命令删除文件目录时inode变化
首先,将链接数递减,释放inode号,方便重用。 其次,将数据块存放在空闲列表中。 然后,将目录项从目录中删除。 最后,数据实际上并没有删除,只是被标记为空闲,当另外一个文件使用数据块时将被覆盖。
mv 命令移动重名文件目录时inode变化
首先,若mv命令的目标目录是当前目录,使用新文件名创建对应新的目录项,删除旧目录条目对应的旧的文件名,新文件与原始inode号绑定,变动的是时间戳。 其次,若mv命令的目标目录不是当前目录,mv相当于cp和rm命令的结合,首先将文件数据块拷贝到目标目录中,然后删除旧目录中的文件。
$ ls -li
# 134612806 -rw-r--r--. 1 root root 5 3月 24 15:44 issue
$ mv issue issue.bak
$ ls -li
# 134612806 -rw-r--r--. 1 root root 5 3月 24 15:44 issue.bak
ln 命令创建软、硬链接时inode变化
首先,创建硬链接,同一个文件,不支持目录、跨分区,与源文件的inode号相同。 其次,创建软链接,类似
Windows
快捷方式,支持目录、跨分区,新文件与新的inode号绑定。
# 硬链接
$ ln /tmp/dir01/file.txt /tmp/dir02/file.txt
# 软链接
$ ln -s /tmp/dir01/file.txt /tmp/dir02/file.txt
$ ln -s ../dir01/file.txt /tmp/dir03/file.txt # 特殊:在 /tmp/dir01/ 目录中若要使用相对路径
# 删除软链接目录时,一定不要在尾部加上 /,否则会删除软链接源目录文件
rm -rf /tmp/dir03
Tips: Linux 系统中软链接与硬链接特征区别?
区别 | 软链接 | 硬链接 |
---|---|---|
本质 | 非同一个文件 | 同一个文件 |
垮设备、分区 | 支持 | 不支持 |
文件夹 | 支持 | 不支持 |
inode 值 | 不相同 | 与源文件相同 |
链接数 | 创建、删除链接数不会变化 | 创建新的硬链接,数量会增加,删除硬链接,数量减少 |
相对路径 | 必须使用绝对路径,源文件可以不存在 | 无必须使用绝对路径,也可以使用相对路径,且原文件必须存在 |
文件类型 | 链接文件和源文件无关 | 和源文件相同 |
文件大小 | 源文件的路径的长度 | 和源文件相同 |
删除源文件 | 软链接文件将无法访问 | 链接数减一,删除最后一个链接后,源文件被删除 |
生产案例Tips:
提示磁盘空间满
No Space Left On Device
,但是 df 可以看到空间有剩余,为什么? A: 实际上是因为 inode 表数量使满了,此时删除我们创建的/boot/testdir/
便可以正常使用。
# 以 /boot 分区为例,将硬盘撑满。
$ cp /dev/zero /boot/test.img
# cp: 写入 '/boot/test.img' 出错: 设备上没有空间
$ df -i /boot
文件系统 Inodes 已用(I) 可用(I) 已用(I)% 挂载点
/dev/sda2 524288 502 523786 5% /boot
$ df -h /boot
文件系统 容量 已用 可用 已用% 挂载点
/dev/sda2 960M 960M 112K 100% /boot
# 此时无法再创建文件了
$ touch a.txt
touch: 无法创建 'a.txt': 设备上没有空间
# 然后,删除 /boot/test.img 文件
rm -rf /boot/test.img
# 前面,已知inode数量为524288,我们将剩余的inode数量填满,创建剩余数量的文件。
mkdir -vp /boot/testdir/
echo /boot/testdir/{1..523786}.txt | xargs -n 10000 touch
# 此时,将可以看到剩余的inode数量为 0,创建文件提示 No Space Left On Device,但是 df 命令仍然显示有剩余控制。
提示磁盘空间快满,使用rm命令删除了很大的无用文件后,df仍然看到空间没被释放,为什么,如何解决? A: 一个目录文件若正在使用,则不会立即删除,虽然你在终端中可能看不到了,但是实际上目录文件系统没有及时释放inode,若想立即释放空间则可以按照下述方法。
$ cp /dev/zero /boot/test.img
$ df -h /boot
# 通用
$ cat /dev/null > /boot/test.img
# 在 sh 与 bash Shell 使用的方法,可能不通用
> /boot/test.img
温馨提示:作者最近正在整理自己10年笔记,全栈系列从门到实践教程将会逐步持续同步到公众号内,若需要在线实时浏览作者笔记的童鞋,请添加作者[WeiyiGeeker],当前价格¥168,获取在网络、安全、运维、开发(Sec、Ops、Dev)中的所有学习实践笔记,和问题答疑以及远程技术支持,希望大家多多支持!
至此完毕,更多技术文章,请持续关注公众号并添加星标,获取及时文章推送!
作者博客: https://blog.weiyigeek.top
如果此篇文章对你有帮助,请你将它分享给更多的人!
学习推荐 往期文章
🔥【最新】Linux 运维 | 2.文件系统目录结构及文件目录管理学习实践
🔥【最新】运维学习 | Linux 命令大全,从A到Z
🔥【必备】网络安全攻击防护及等级保护(过保)落地实践
运维必备:Linux系统下的两款终端多重会话工具
Ops实践 | 从零开始:落实企业网络审计日志采集留存,等保合规!
【全栈工程师修炼指南】邀你加入学习交流群!
此文,为作者原创文章,希望大家多多支持,若对看友您有帮助请帮忙转发,点👍、在看,若有疑问的小伙伴,可在文末留言哟!