![调整磁盘映像/文件系统的大小以精确容纳一组可用空间接近于零的文件](https://linux22.com/image/95780/%E8%B0%83%E6%95%B4%E7%A3%81%E7%9B%98%E6%98%A0%E5%83%8F%2F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%A4%A7%E5%B0%8F%E4%BB%A5%E7%B2%BE%E7%A1%AE%E5%AE%B9%E7%BA%B3%E4%B8%80%E7%BB%84%E5%8F%AF%E7%94%A8%E7%A9%BA%E9%97%B4%E6%8E%A5%E8%BF%91%E4%BA%8E%E9%9B%B6%E7%9A%84%E6%96%87%E4%BB%B6.png)
我需要用适合脚本/make/自动化的代码构建一个磁盘映像(两个分区,一个 FAT 文件系统和一个 ext4 文件系统,用于 UEFI/Syslinux USB Linux 引导 [操作系统安装程序],在生产中永远不会改变)精确(或非常接近)一组任意大小的文件的大小。换句话说,给定一组构建文件,我需要知道如何生成 FAT 和 ext4 文件系统映像,以及经过分区以保存它们的磁盘映像,其大小经过计算,可导致尽可能接近零的可用空间有。稍微多一点空间是可以犯错的,但两年后有人向文件添加 N+1 字节时失败就不行了。这需要适合 makefile,即反复试验并不能解决问题(尽管我认为如果情况变得更糟,带有阈值的迭代解决方案可能会起作用)。这类似于 ISO-9660 映像(以前的项目中曾使用过该映像,但 Syslinux 不支持 UEFI 上的 ISO-9660 映像)。
我正在使用dd
(分配磁盘映像)、、parted
(dd
分配 FAT 文件系统)、、mkfs.vfat
(dd
对于 ext4)、、mkfs.ext4
(kpartx
映射分区)、dd
(写入 FAT 分区)、dd
(写入ext4 分区),最后dd
将磁盘映像写入 USB 以在实际硬件上启动。
我当前的想法是用来du
确定文件在构建磁盘上占用多少空间,然后为额外的文件系统和分区开销以及误差幅度添加一些余量。所以我需要知道dd
给定输出的每个 的块计数du
。
另一种选择是构建固定大小的大映像,写入文件,然后将 FAT、ext4 和分区的大小调整为最小大小。 ext4 文件系统可以缩小,我看到 FAT 文件系统也可以缩小。但是,您仍然面临计算将其缩小到多少的问题。想知道以前是否有人这样做过,有一些具体的想法(或示例代码)。
答案1
我最终使用了软糖因素和迭代方法的组合(作为故障保护)。这并不需要像我最初设想的那么复杂。事实证明,目前 FAT 几乎不需要捏造,但 ext 需要大量的负捏造;由于 ext4 的软糖系数为零,我有足够的可用空间(超过 21M)。我转换为 ext2(谁需要一个臭日志?!),增加了我的块大小,并仔细计算了我需要的 inode,并从中获得了更多兆字节的可用空间。我想我可以从 du 获得“实际大小”并从那里开始计算,但我认为计算开销,即使它们是不同的文件系统,也会是更接近的近似值。
# Estimated filesystem overhead, in 512-byte blocks
FS_ESP_FUDGE=256
FS_ISO_FUDGE=-80000 # Wow!
FS_FUDGE_INCR=1024
...
read ESP_RSIZE d < <(du --summarize --block-size=512 $ESP)
read ISO_RSIZE d < <(du --summarize --block-size=512 $ISO)
success=false
until $success; do
let ESP_SIZE=ESP_RSIZE+FS_ESP_FUDGE
let ISO_SIZE=ISO_RSIZE+FS_ISO_FUDGE
let ESP_START=2048
let IMG_SIZE=ESP_SIZE+ISO_SIZE+ESP_START
let ESP_END=ESP_START+ESP_SIZE-1
let ISO_START=ESP_END+1
success=true
...
sudo /sbin/mkfs.vfat /dev/mapper/$p1 -F 16 \
|| error_exit "mkfs.vfat failed" 5
# -N: Count the inodes (all files, plus . and .. for each directory,
# which I can't get "find" to include).
sudo /sbin/mke2fs -b 4096 -N $(( $(find $ISO | wc -l ) + 2 * $(find $ISO -type d | wc -l))) -m 0 -q /dev/mapper/$p2 \
|| error_exit "mke2fs failed" 6
...
if ! tar -C $ESP -c --exclude-vcs --exclude-backups . | \
sudo tar -C mnt/esp -x; then
{
read
read fs onek used avail use rest
} < <(df mnt/esp)
# Are we out of disk space? If not, bail, else increase margin, retry
[[ $onek -ne $used || $avail -ne 0 || $use != "100%" ]] && \
error_exit "esp tar failed" 9
let FS_ESP_FUDGE=FS_ESP_FUDGE+FS_FUDGE_INCR
success=false
fi
if ! tar -C $ISO -c --exclude-vcs --exclude-backups . | \
sudo tar -C mnt/iso --owner=root --group=root -x ; then
{
read
read fs onek used avail use rest
} < <(df mnt/iso)
# Are we out of disk space? If not, bail, else increase margin, retry
[[ $onek -ne $used || $avail -ne 0 || $use != "100%" ]] && \
error_exit "iso tar failed" 10
let FS_ISO_FUDGE=FS_ISO_FUDGE+FS_FUDGE_INCR
success=false
fi
$success || echo "Whoops, I guessed too small; please adjust fudge factor. Retrying ..."
...
done