调整磁盘映像/文件系统的大小以精确容纳一组可用空间接近于零的文件

调整磁盘映像/文件系统的大小以精确容纳一组可用空间接近于零的文件

我需要用适合脚本/make/自动化的代码构建一个磁盘映像(两个分区,一个 FAT 文件系统和一个 ext4 文件系统,用于 UEFI/Syslinux USB Linux 引导 [操作系统安装程序],在生产中永远不会改变)精确(或非常接近)一组任意大小的文件的大小。换句话说,给定一组构建文件,我需要知道如何生成 FAT 和 ext4 文件系统映像,以及经过分区以保存它们的磁盘映像,其大小经过计算,可导致尽可能接近零的可用空间有。稍微多一点空间是可以犯错的,但两年后有人向文件添加 N+1 字节时失败就不行了。这需要适合 makefile,即反复试验并不能解决问题(尽管我认为如果情况变得更糟,带有阈值的迭代解决方案可能会起作用)。这类似于 ISO-9660 映像(以前的项目中曾使用过该映像,但 Syslinux 不支持 UEFI 上的 ISO-9660 映像)。

我正在使用dd(分配磁盘映像)、、parteddd分配 FAT 文件系统)、、mkfs.vfatdd对于 ext4)、、mkfs.ext4kpartx映射分区)、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

相关内容