空き容量がほぼゼロの状態で、特定のファイルセットを正確に保持できるようにディスクイメージ/ファイルシステムのサイズを設定する

空き容量がほぼゼロの状態で、特定のファイルセットを正確に保持できるようにディスクイメージ/ファイルシステムのサイズを設定する

スクリプト/make/自動化に適したコードで、任意のサイズのファイル セットを正確に (または非常に近いサイズに) 保持できるディスク イメージ (UEFI/Syslinux USB Linux ブート [OS インストーラー] 用の 2 つのパーティション、FAT ファイルシステムと ext4 ファイルシステム、本番環境で変更されることはありません) を構築する必要があります。言い換えると、ビルドされたファイル セットが与えられた場合、FAT および ext4 ファイルシステム イメージと、それらを保持するためにパーティション分割されたディスク イメージを生成する方法を知る必要があります。これらのサイズは、空き領域が可能な限りゼロに近くなるように計算されます。少し余裕を持たせても問題ありませんが、2 年後に誰かがファイルに N+1 バイトを追加したときに失敗するのは問題です。これは makefile に適したものである必要があります。つまり、試行錯誤では不十分です (ただし、最悪の場合、しきい値を使用した反復的なソリューションが機能すると思います)。これは ISO-9660 イメージのようなものです (以前のプロジェクトではそうでしたが、Syslinux は UEFI 上の ISO-9660 イメージをサポートしていません)。

私は、dd(ディスク イメージを割り当てるため)、、parted( ddFAT ファイルシステムを割り当てるため)、、mkfs.vfat( ddext4 用)、、(パーティションをマップするため)、mkfs.ext4( FAT パーティションを書き込むため)、(ext4 パーティションを書き込むため) を使用してファイルを作成し、最後に実際のハードウェアで起動するためにディスク イメージを USB に書き込みます。kpartxdddddd

私の現在のアイデアは、 を使用してビルド ディスク上でファイルが占めるスペースの量を判断し、追加のファイル システムとパーティションのオーバーヘッドとエラーのマージンをいくらか追加することです。 そのため、出力が与えられた場合、 のduそれぞれのブロック数を知る必要があります。 dddu

もう 1 つのオプションは、固定サイズの大きなイメージを作成し、ファイルを書き込んでから、FAT、ext4、パーティションを最小サイズに変更することです。ext4 ファイルシステムは縮小できますし、FAT ファイルシステムも縮小できるようです。しかし、それでも、どれだけ縮小するかを計算するという問題が残ります。これまでにこれを実行したことがある人や、具体的なアイデア (またはサンプル コード) を持っている人はいないでしょうか。

答え1

結局、私は、ファッジ係数と反復アプローチの組み合わせ (フェイルセーフとして) を使用することにしました。これは、当初私が思い描いていたほど複雑である必要はありません。今のところ、FAT ではほとんどファッジは必要ありませんでしたが、ext では大量のネガティブなファッジが必要でした。ext4 のファッジ係数がゼロの場合、十分な空き領域 (21 MB 以上) がありました。私は ext2 に変換し (誰がジャーナルを必要としますか?!)、ブロック サイズを増やし、必要な inode を慎重に数えて、さらに多くの MB の空き領域を得ました。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

関連情報