前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >运维Tips | Linux系统文件命令执行时inode表如何变化?

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

作者头像
全栈工程师修炼指南
发布2024-05-28 16:24:23
810
发布2024-05-28 16:24:23
举报

Linux文件元数据之inode表结构

描述:文件元数据(Metadata)是文件的属性,它描述了文件的基本信息,例如文件大小、创建时间、类型、权限等。其通常是存放在inode (index node) 表中,inode 表中有很多条记录组成,第一条记录对应的存放了一个文件的元数据信息。

此处以ext4文件系统为例,每个 inode 表记录中大致包含以下信息:

  • inode Number 节点号
  • 文件类型和访问权限;
  • 文件所属用户 UID和组 GID;
  • 文件大小和占用磁盘块数;
  • 文件创建、修改和访问时间戳;
  • 文件的硬链接数;
  • 文件的数据块地址等。

温馨提示:如果小伙伴们在其他平台看到此文章,一定要关注作者首发公众号《全栈工程师修炼指南》,给作者持续创作的动力!

具体来说,一个 inode 结构体通常包含以下字段:

代码语言:javascript
复制
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)。

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

从上图中可知在 ext4 文件系统中,目录是个特殊文件,目录文件的内容保存了此目录中的文件的列表及inode Number对应关系, 用户通过文件名访问文件时,首先在目录中查找文件的inode Number,然后根据inode Number找到对应的文件。

所以,一般inode表会占用文件系统磁盘空间的1%左右,一个目录文件的内容就是一个该目录下所有文件的目录项的列表。

代码语言:javascript
复制
# 查看 /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号对应的磁盘块中。

代码语言:javascript
复制
$ 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命令的结合,首先将文件数据块拷贝到目标目录中,然后删除旧目录中的文件。

代码语言:javascript
复制
$ 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号绑定。

代码语言:javascript
复制
# 硬链接
$ 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/ 便可以正常使用。
代码语言:javascript
复制
# 以 /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 命令仍然显示有剩余控制。

weiyigeek.top-inode数量用完结果图

  1. 提示磁盘空间快满,使用rm命令删除了很大的无用文件后,df仍然看到空间没被释放,为什么,如何解决? A: 一个目录文件若正在使用,则不会立即删除,虽然你在终端中可能看不到了,但是实际上目录文件系统没有及时释放inode,若想立即释放空间则可以按照下述方法。
代码语言:javascript
复制
$ 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)中的所有学习实践笔记,和问题答疑以及远程技术支持,希望大家多多支持!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈工程师修炼指南 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Linux文件元数据之inode表结构
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档