Dimensionar una imagen de disco/sistema de archivos para contener exactamente un determinado conjunto de archivos con espacio libre casi nulo

Dimensionar una imagen de disco/sistema de archivos para contener exactamente un determinado conjunto de archivos con espacio libre casi nulo

Necesito construir, en código adecuado para scripting/make/automatización, una imagen de disco (dos particiones, un sistema de archivos FAT y un sistema de archivos ext4, para arranque UEFI/Syslinux USB Linux [instalador del sistema operativo], que nunca cambiará en producción) de un tamaño que contiene exactamente (o muy cerca) un conjunto de archivos de tamaño arbitrario. En otras palabras, dado un conjunto de archivos creados, necesito saber cómo generar imágenes de sistemas de archivos FAT y ext4, y la imagen de disco que está particionada para contenerlas, que tengan tamaños calculados para dar como resultado un espacio libre tan cercano a cero como sea razonable. tener. Está bien pecar de tener un poco más de espacio, pero no está bien fallar cuando alguien agrega N+1 bytes al archivo dentro de dos años. Esto debe ser adecuado para un archivo MAKE, es decir, prueba y error no es suficiente (aunque supongo que, en el peor de los casos, una solución iterativa con un umbral podría funcionar). Esto es algo así como una imagen ISO-9660 (que solía estar en un proyecto anterior, pero Syslinux no admite imágenes ISO-9660 en UEFI).

Estoy creando los archivos usando dd(para asignar la imagen del disco), parted( ddpara asignar el sistema de archivos FAT), mkfs.vfat( ddpara ext4), (para asignar las particiones), mkfs.ext4( para escribir la partición FAT), (para escribir la partición ext4) y finalmente escribir la imagen del disco en un USB para arrancar en el hardware real.kpartxdddddd

Mi idea actual es usarlo dupara determinar cuánto espacio ocupan los archivos en el disco de compilación, luego agregar algo de margen para la sobrecarga adicional del sistema de archivos y la partición, y el margen de error. Entonces necesito saber el recuento de bloques para cada una de las salidas dddadas du.

Otra opción es construir una imagen grande de tamaño fijo, escribir los archivos y luego cambiar el tamaño de FAT, ext4 y las particiones al tamaño mínimo. Los sistemas de archivos ext4 se pueden reducir y veo que los sistemas de archivos FAT se pueden reducir. Pero todavía te queda el problema de calcular a cuánto reducirlo. Me pregunto si alguien ha hecho esto antes y tiene algunas ideas concretas (o código de muestra).

Respuesta1

Terminé usando una combinación de factores de manipulación y un enfoque iterativo (como método de seguridad). Esto no tiene por qué ser tan complicado como lo imaginé originalmente. Resulta que, por ahora, se requirió poca manipulación para FAT, pero se requirió una gran cantidad de manipulación negativa para ext; con un factor de manipulación cero para ext4, tenía mucho espacio libre (más de 21 millones). Me convertí a ext2 (¡¿quién necesita un diario apestoso?!), aumenté el tamaño de mi bloque, conté cuidadosamente los inodos que necesitaba y obtuve aún más megabytes de espacio libre. Supongo que podría haber obtenido el "tamaño real" de du y trabajar desde allí, pero pensé que contar los gastos generales, incluso si son sistemas de archivos diferentes, sería una aproximación más cercana.

# 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

información relacionada