
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
( dd
para asignar el sistema de archivos FAT), mkfs.vfat
( dd
para 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.kpartx
dd
dd
dd
Mi idea actual es usarlo du
para 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 dd
dadas 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