关于索引节点的一些事情

为了调到中央配送中心,我会定期去多家大公司(主要是圣彼得堡和莫斯科)面试 DevOps 职位。 我注意到很多公司(很多优秀的公司,例如 Yandex)都会问两个类似的问题:

  • 什么是索引节点;
  • 什么原因会导致磁盘写入错误(或者例如:为什么可能会耗尽磁盘空间,本质是一样的)。

正如经常发生的那样,我确信我很了解这个主题,但当我开始解释时,知识差距就变得明显了。 为了系统化我的知识,填补空白,不再让自己难堪,我写这篇文章,也许对其他人有用。

我将从底部开始,即来自硬盘驱动器(我们将丢弃闪存驱动器、SSD 和其他现代设备;例如,让我们考虑任何 20 或 80 GB 的旧驱动器,因为块大小为 512 字节)。

硬盘驱动器不知道如何逐字节寻址其空间;它被有条件地划分为块。 块编号从0开始。(这称为LBA,详细信息在这里: ru.wikipedia.org/wiki/LBA)

关于索引节点的一些事情

从图中可以看出,我将LBA块指定为HDD级别。 顺便说一句,您可以这样查看磁盘的块大小:

root@ubuntu:/home/serp# blockdev --getpbsz /dev/sdb
512

上面的一层是一个分区,一个分区用于整个磁盘(同样是为了简单起见)。 最常见的是使用两种类型的分区标记:msdos 和 gpt。 因此,msdos 是一种旧格式,支持高达 2Tb 的磁盘,gpt 是一种新格式,能够寻址高达 1 ZB 的 512 字节块。 在我们的例子中,我们有一个 msdos 类型的分区,从图中可以看出,该分区从 1 号块开始,而 MBR 使用零。

在第一个分区中我创建了一个ext2文件系统,它的默认块大小是4096字节,这也在图中有所体现。 您可以这样查看文件系统块大小:

root@ubuntu:/home/serp# tune2fs -l /dev/sdb1
tune2fs 1.42.9 (4-Feb-2014)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          a600bf40-f660-41f6-a3e6-96c303995479
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      ext_attr resize_inode dir_index filetype sparse_super large_file
Filesystem flags:         signed_directory_hash
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              65536
Block count:              261888
Reserved block count:     13094
Free blocks:              257445
Free inodes:              65525
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      63
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
Filesystem created:       Fri Aug  2 15:02:13 2019
Last mount time:          n/a
Last write time:          Fri Aug  2 15:02:14 2019
Mount count:              0
Maximum mount count:      -1
Last checked:             Fri Aug  2 15:02:13 2019
Check interval:           0 (<none>)
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               256
Required extra isize:     28
Desired extra isize:      28
Default directory hash:   half_md4
Directory Hash Seed:      c0155456-ad7d-421f-afd1-c898746ccd76

我们需要的参数是“块大小”。

现在有趣的部分是如何读取 /home/serp/testfile 文件? 文件由一个或多个存储其数据的文件系统块组成。 知道文件名,如何找到它? 我应该阅读哪些块?

这就是 inode 派上用场的地方。 ext2fs 文件系统有一个“表”,其中包含所有 inode 的信息。 ext2fs 的 inode 数量是在创建文件系统时设置的。 我们查看tune2fs输出的“Inode count”参数中所需的数字,即我们有 65536 件。 索引节点包含我们需要的信息:我们正在查找的文件的文件系统块列表。 如何查找给定文件的索引节点号?

目录中包含相应的名称和inode号,ext2fs中的目录是一种特殊类型的文件,即也有自己的索引节点号。 为了打破这个恶性循环,根目录被分配了一个“固定”的inode编号“2”。 我们看一下2号inode的内容:

root@ubuntu:/# debugfs /dev/sdb1
debugfs 1.42.9 (4-Feb-2014)
debugfs:  stat <2>

Inode: 2   Type: directory    Mode:  0755   Flags: 0x0
Generation: 0    Version: 0x00000000:00000002
User:     0   Group:     0   Size: 4096
File ACL: 0    Directory ACL: 0
Links: 3   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x5d43cb51:16b61bcc -- Fri Aug  2 16:34:09 2019
 atime: 0x5d43c247:b704301c -- Fri Aug  2 15:55:35 2019
 mtime: 0x5d43cb51:16b61bcc -- Fri Aug  2 16:34:09 2019
crtime: 0x5d43b5c6:00000000 -- Fri Aug  2 15:02:14 2019
Size of extra inode fields: 28
BLOCKS:
(0):579
TOTAL: 1

正如您所看到的,我们需要的目录包含在块号 579 中。在其中我们将找到主文件夹的节点号,依此类推,直到在 serp 目录中我们看到所请求文件的节点号。 如果突然有人想检查号码是否正确,必要的信息是否有,这并不困难。 我们的确是:

root@ubuntu:/# dd if=/dev/sdb1 of=/home/serp/dd_image bs=4096 count=1 skip=579
1+0 records in
1+0 records out
4096 bytes (4,1 kB) copied, 0,000184088 s, 22,3 MB/s
root@ubuntu:/# hexdump -c /home/serp/dd_image

在输出中,您可以读取目录中文件的名称。

那么我就来到了主要问题:“什么原因会导致录音错误?”

当然,如果文件系统中没有剩余空闲块,就会发生这种情况。 在这种情况下可以做什么? 除了明显的“删除任何不必要的东西”之外,您应该记住,在 ext2,3、4 和 13094 文件系统中还有“保留块计数”之类的东西。 如果您查看上面的列表,我们有“XNUMX”这样的块。 这些块只能由 root 用户写入。 但如果您需要快速解决问题,作为临时解决方案,您可以将它们提供给所有人,从而产生一些可用空间:

root@ubuntu:/mnt# tune2fs -m 0 /dev/sdb1
tune2fs 1.42.9 (4-Feb-2014)
Setting reserved blocks percentage to 0% (0 blocks)

那些。 默认情况下,您有 5% 的磁盘空间不可用于写入,并且考虑到现代磁盘的容量,该空间可能达到数百 GB。

还能是什么? 也有可能存在空闲块,但没有更多节点。 如果文件系统上有一堆小于文件系统块大小的文件,通常会发生这种情况。 考虑到 1 个 inode 花费在 1 个文件或目录上,并且(对于给定的文件系统)总共有 65536 个 inode - 这种情况非常现实。 这可以从 df 命令的输出中清楚地看出:

serp@ubuntu:~$ df -hi
Filesystem     Inodes IUsed IFree IUse% Mounted on
udev             493K   480  492K    1% /dev
tmpfs            493K   425  493K    1% /run
/dev/xvda1       512K  240K  273K   47% /
none             493K     2  493K    1% /sys/fs/cgroup
none             493K     2  493K    1% /run/lock
none             493K     1  493K    1% /run/shm
none             493K     2  493K    1% /run/user
/dev/xvdc1       320K  4,1K  316K    2% /var
/dev/xvdb1        64K   195   64K    1% /home
/dev/xvdh1       4,0M  3,1M  940K   78% /var/www
serp@ubuntu:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            2,0G  4,0K  2,0G   1% /dev
tmpfs           395M  620K  394M   1% /run
/dev/xvda1      7,8G  2,9G  4,6G  39% /
none            4,0K     0  4,0K   0% /sys/fs/cgroup
none            5,0M     0  5,0M   0% /run/lock
none            2,0G     0  2,0G   0% /run/shm
none            100M     0  100M   0% /run/user
/dev/xvdc1      4,8G  2,6G  2,0G  57% /var
/dev/xvdb1      990M  4,0M  919M   1% /home
/dev/xvdh1       63G   35G   25G  59% /var/www

从 /var/www 分区上可以清楚地看到,文件系统中的空闲块数和空闲节点数差异很大。

如果你用完了索引节点,我不会告诉你任何咒语,因为...... 没有(如果我错了,请告诉我)。 因此,对于小文件较多的分区,应该明智地选择文件系统。 例如,btrfs inode 无法结束,因为如有必要,会动态创建新的。

来源: habr.com

添加评论