如何计算分区的精确大小和写入目录所需的 inode 数量

如何计算分区的精确大小和写入目录所需的 inode 数量

我需要将包含文件的目录(具体来说 - Linux chroot)写入包含 LVM 映像的文件中。任务的背景很愚蠢,但我想了解现在发生了什么。我使用以下命令计算目录的大小du

# du -s --block-size=1 chroot
3762733056  chroot

我将其整理并创建一个足够大的文件来包含它:

# fallocate -l 4294967296 image.lvm
# ls -lah
drwxr-xr-x 23 root    root    4.0K мая 27 20:59 chroot
-rw-r--r--  1 root    root    4.0G мая 28 09:59 image.lvm

我将文件挂载(抱歉,不确定正确的术语)为循环设备,并在其上创建一个 LVM 分区。我将为其使用 ext4 fs,我知道 ext4 为根保留了 5% 的空间(我可以对其进行调整)并为 inode 表保留了一些空间,因此我创建了一个比实际目录大约 10%(4139006362 字节)的分区,并将其四舍五入为 512(4139006464 字节)的倍数,以满足 LVM 的需求:

# losetup -f --show image.lvm
/dev/loop0
# pvcreate /dev/loop0
  Physical volume "/dev/loop0" successfully created.
# vgcreate IMAGE /dev/loop0
  Volume group "IMAGE" successfully created
# lvcreate --size 4139006464B -n CHROOT IMAGE
  Rounding up size to full physical extent <3.86 GiB
  Logical volume "CHROOT" created.

然后我在这个 LV 上创建一个 ext4 文件系统:

# mkfs.ext4 /dev/IMAGE/CHROOT
mke2fs 1.45.6 (20-Mar-2020)
Discarding device blocks: done                            
Creating filesystem with 1010688 4k blocks and 252960 inodes
Filesystem UUID: fb3775ff-8380-4f97-920d-6092ae0cd454
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376, 294912, 819200, 884736

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done 

# mount /dev/IMAGE/CHROOT mnt
# df --block-size=1 mnt
Filesystem                   1B-blocks         Used    Available Use% Mounted on
/dev/mapper/IMAGE-CHROOT    4007591936     16179200   3767648256   1% /mnt

虽然 3767648256 大于我从 获得的 3762733056 du,但我仍然对其进行了稍微调整:

# tune2fs -m 0 /dev/IMAGE/CHROOT
tune2fs 1.45.6 (20-Mar-2020)
Setting reserved blocks percentage to 0% (0 blocks)
# df --block-size=1 mnt
Filesystem                1B-blocks     Used  Available Use% Mounted on
/dev/mapper/IMAGE-CHROOT 4007591936 16179200 3974635520   1% /mnt

到目前为止一切顺利,让我们向其中写入一些数据:

# cp -a chroot/. mnt/
...
cp: cannot create regular file 'mnt/./usr/portage/profiles/hardened/linux/powerpc/ppc64/32bit-userland/use.mask': No space left on device

砰。让我们看看df显示了什么:

# df --block-size=1 mnt
Filesystem                1B-blocks       Used Available Use% Mounted on
/dev/mapper/IMAGE-CHROOT 4007591936 3587997696 402817024  90% /mnt

所以实际上还有可用空间。在谷歌上搜索了一下后,我发现你的分区上的 inode 可能会用完,这似乎和我的情况完全一样:

# df -i mnt
Filesystem               Inodes IUsed IFree IUse% Mounted on
/dev/mapper/IMAGE-CHROOT   248K  248K     0  100% /mnt

现在,问题来了!我可以轻松使用更大的文件大小,创建 1.5 倍大的分区,将文件写入其中,这样就可以了。但作为想要保留空间的严谨开发人员,我该如何精确计算写入目录需要多少字节和 inode?我也相当肯定自己在--block-size=1某个地方搞砸了。

“为什么使用 LVM”上下文:它用于快照功能。因此,基本上其他脚本从所述 4G chroot 创建 20G 快照,执行此快照中的内容,然后将其删除,而 chroot 的原始内容保持不变。因此,基本文件系统可能被视为只读。早在 Docker 之前就发明了“简单”愚蠢的 docker 容器,无法用 Docker 本身或其 overlayfs 轻松替换。

答案1

mkfs.ext4为您提供三个有趣的选项(参见手册页了解详细信息)。

  • -i bytes-per-inode

    • 指定字节/inode 比率。
    • mke2fs 为磁盘上每个 inode 字节的空间创建一个 inode。
    • 每 inode 字节数比率越大,创建的 inode 越少。
  • -I inode-size

    • 指定每个 inode 的大小(以字节为单位)。
    • 默认 inode 大小由 mke2fs.conf(5) 文件控制。在 e2fsprogs 附带的 mke2fs.conf 文件中
      • 默认 inode 大小为 256 字节对于大多数文件系统,
      • 小型文件系统除外,其 inode 大小为 128 字节
  • -N number-of-inodes

    • 覆盖为文件系统保留的 inode 数量的默认计算(基于块数量和每 inode 的字节数比率)。
    • 这允许用户直接指定所需的 inode 数量。

使用这些组合,您可以精确地塑造文件系统。如果您确信永远不需要创建任何额外的文件或者将文件系统挂载为只读,那么理论上你可以给出-N ${number-of-entities}

$ truncate -s 10M ino.img
$ mkfs.ext4 -N 5 ino.img
mke2fs 1.44.1 (24-Mar-2018)
Discarding device blocks: done
Creating filesystem with 10240 1k blocks and 16 inodes
Filesystem UUID: 164876f1-bbfa-405f-8b2d-704830d7c165
Superblock backups stored on blocks:
        8193

Allocating group tables: done
Writing inode tables: done
Creating journal (1024 blocks): done
Writing superblocks and filesystem accounting information: done

$ mount -o loop ino.img ./mnt
$ df -i mnt
Filesystem     Inodes IUsed IFree IUse% Mounted on
/dev/loop0         16    11     5   69% /home/attie/box/mnt
$ touch ./mnt/1
$ touch ./mnt/2
$ touch ./mnt/3
$ touch ./mnt/4
$ touch ./mnt/5
$ touch ./mnt/6
touch: cannot touch './mnt/6': No space left on device
$ df -B1 mnt
Filesystem     1B-blocks   Used Available Use% Mounted on
/dev/loop0       9425920 176128   8516608   3% /home/attie/box/mnt
$ df -i mnt
Filesystem     Inodes IUsed IFree IUse% Mounted on
/dev/loop0         16    16     0  100% /home/attie/box/mnt

请记住目录也需要 inode:

$ mkfs.ext4 -N 5 ino.img
mke2fs 1.44.1 (24-Mar-2018)
ino.img contains a ext4 filesystem
        last mounted on /home/attie/box/mnt on Thu May 28 09:08:41 2020
Proceed anyway? (y/N) y
Discarding device blocks: done
Creating filesystem with 10240 1k blocks and 16 inodes
Filesystem UUID: a36efc6c-8638-4750-ae6f-a900ada4330f
Superblock backups stored on blocks:
        8193

Allocating group tables: done
Writing inode tables: done
Creating journal (1024 blocks): done
Writing superblocks and filesystem accounting information: done

$ mount -o loop ino.img ./mnt
$ mkdir mnt/1
$ mkdir mnt/2
$ touch mnt/a
$ touch mnt/b
$ touch mnt/1/c
$ touch mnt/2/d
touch: cannot touch 'mnt/2/d': No space left on device

您可以使用 或 类似方法获取实体的数量find,记得也要计算目录的数量!(即:不要使用-type f-not -type d)。

find "${source_dir}" | wc -l

现在您也知道(或可以指定)inode大小,您可以更精确地确定需要分配多少空间,并且可以避免“消瘦“未使用的 inode 上的空间。


如果你使用只读文件系统,那么另一个选择可能是研究 squashfs 而不是 ext4,它将根据输入文件分配一个连续的(和压缩的)块……而不是创建一个你希望足够大的容器并填充它。

除非您真的需要 LVM 的某些功能,否则您可以轻松摆脱它,如上所示(我建议也不要使用它)。您可能喜欢/想要 MBR,具体取决于您将如何部署映像。

相关内容