运维Tips | Linux系统文件命令执行时inode表如何变化?

5e8107e7763fa7fdcf8f75d50bd25409.jpeg

[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路。 ]

大家好,我是【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_modei_uidi_gidi_links_counti_size_loi_atimei_ctimei_mtimei_blocks_loi_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)。

06e96de7c1989a346dc4c98e54c7eb71.png

weiyigeek.top-inode表结构及其指针和存储空间图

从上图中可知在 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

  1. 提示磁盘空间满 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 命令仍然显示有剩余控制。

152dd08fa3f65fb5d121bc86402544d2.png

weiyigeek.top-inode数量用完结果图
  1. 提示磁盘空间快满,使用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

89a6e86e247fbe5f26cdd4348086dc95.png

温馨提示:作者最近正在整理自己10年笔记,全栈系列从门到实践教程将会逐步持续同步到公众号内,若需要在线实时浏览作者笔记的童鞋,请添加作者[WeiyiGeeker],当前价格¥168,获取在网络、安全、运维、开发(Sec、Ops、Dev)中的所有学习实践笔记,和问题答疑以及远程技术支持,希望大家多多支持!

a18572f3e8c8ae7b1685306e00a8d3ec.png

至此完毕,更多技术文章,请持续关注公众号并添加星标,获取及时文章推送!

作者博客: https://blog.weiyigeek.top


如果此篇文章对你有帮助,请你将它分享给更多的人! 

382dfb71b0ff1a92d96fd91c8a6ebc1e.gif

8a6f298a1ece35613e6834e1f24060f9.png 学习推荐 往期文章 6cb17e0dc3620ce14c849fa614b73f2b.png

bbc8d26d0e107b1205e9f15a6ac75a9b.gif

全栈工程师修炼指南】邀你加入学习交流群!

feaa03cb3bff33b42b6df5bbdf6070f6.gif

1a6d65eacd6d686f057e9b56c7caeac3.gif

此文,为作者原创文章,希望大家多多支持,若对看友您有帮助请帮忙转发,点👍、在看,若有疑问的小伙伴,可在文末留言哟!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈工程师修炼指南

原创不易,赞赏鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值