Dimensionando uma imagem de disco/sistema de arquivos para armazenar exatamente um determinado conjunto de arquivos com espaço livre próximo de zero

Dimensionando uma imagem de disco/sistema de arquivos para armazenar exatamente um determinado conjunto de arquivos com espaço livre próximo de zero

Eu preciso construir, em código adequado para script/make/automação, uma imagem de disco (duas partições, um sistema de arquivos FAT e um sistema de arquivos ext4, para inicialização UEFI/Syslinux USB Linux [instalador do sistema operacional], que nunca mudará na produção) de um tamanho que contém exatamente (ou muito próximo) um conjunto de arquivos de tamanho arbitrário. Em outras palavras, dado um conjunto de arquivos construídos, preciso saber como gerar imagens de sistema de arquivos FAT e ext4, e a imagem de disco que é particionada para mantê-los, que tenham tamanhos calculados para resultar em espaço livre tão próximo de zero quanto razoável para ter. Não há problema em errar por ter um pouco de espaço extra, mas não é certo falhar quando alguém adiciona N+1 bytes ao arquivo daqui a dois anos. Isso precisa ser adequado para um makefile, ou seja, tentativa e erro não resolvem (embora eu suponha que se o pior acontecesse, uma solução iterativa com um limite poderia funcionar). É algo como uma imagem ISO-9660 (que costumava estar em um projeto anterior, mas o Syslinux não suporta imagens ISO-9660 em UEFI).

Estou criando os arquivos usando dd(para alocar a imagem do disco), parted, dd(para alocar o sistema de arquivos FAT), mkfs.vfat, dd(para o ext4), mkfs.ext4, kpartx(para mapear as partições), dd(para escrever a partição FAT), dd(para escrever a partição ext4) e, finalmente, ddgravar a imagem do disco em um USB para inicializar no hardware real.

Minha idéia atual é dudeterminar quanto espaço os arquivos ocupam no disco de construção e, em seguida, adicionar alguma margem para sistema de arquivos adicional e sobrecarga de partição e margem de erro. Portanto, preciso saber a contagem de blocos para cada um dos dddados das dusaídas.

Outra opção é construir uma imagem grande de tamanho fixo, gravar os arquivos e redimensionar o FAT, ext4 e as partições para o tamanho mínimo. Os sistemas de arquivos ext4 podem ser reduzidos e vejo que os sistemas de arquivos FAT podem ser reduzidos. Mas então você ainda terá o problema de calcular quanto reduzir. Querendo saber se alguém já fez isso antes, tem algumas idéias concretas (ou código de exemplo).

Responder1

Acabei usando uma combinação de fatores de correção e uma abordagem iterativa (como proteção contra falhas). Isso não precisa ser tão complicado quanto imaginei originalmente. Acontece que, por enquanto, pouca falsificação foi necessária para o FAT, mas uma enorme quantidade de falsificação negativa foi necessária para o ext; com fator de correção zero para ext4, eu tinha bastante espaço livre (mais de 21M). Eu converti para ext2 (quem precisa de um diário fedorento?!), aumentei o tamanho do meu bloco e contei cuidadosamente os inodes que eu precisava, e consegui ainda mais megabytes de espaço livre com ele. Suponho que poderia ter obtido o "tamanho real" de du e trabalhado a partir daí, mas imaginei que contar a sobrecarga, mesmo que sejam sistemas de arquivos diferentes, seria uma aproximação mais próxima.

# 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

informação relacionada