[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH] Fix size calculation for EFI image



CD creation fails with "disk full", because of rounding errors.

The minimum size of data-allocation is a 'cluster', which is a
power-of-two multiple of sectors.
mkfs.msdos chooses minimum FAT and cluster size for image: FAT12<16G
mkfs.msdos uses block-count where a block is 1024 B, but must be rounded
up to track_size with 32 sectors.

Round up each file to clusters before summing.
A sub-directory entry needs 1 cluster minimum.
---
 tools/boot/wheezy/boot-x86 | 37 +++++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)

diff --git a/tools/boot/wheezy/boot-x86 b/tools/boot/wheezy/boot-x86
index bf79d6d..d1d3d16 100644
--- a/tools/boot/wheezy/boot-x86
+++ b/tools/boot/wheezy/boot-x86
@@ -420,17 +420,38 @@ if [ -d boot$N/isolinux/grub ] ; then
         >> $CDDIR/boot/grub/grub.cfg
 
     # Stuff the EFI boot files into a FAT filesystem, making it as
-    # small as possible.  24KiB headroom seems to be enough;
-    # (x+31)/32*32 rounds up to multiple of 32.
-    # This is the same as in efi-image, but we need to redo it here in
-    # the case of a multi-arch amd64/i386 image
+    # small as possible.
 
-    size=0
+    sector_bytes=512 # -S
+    cluster_sectors=4 # -s
+    cluster_bytes=$((sector_bytes * cluster_sectors))
+
+    clusters=2 # 1 cluster for each sub-directory
     for file in $CDDIR/efi/boot/boot*.efi; do
-        size=$(($size + $(stat -c %s "$file")))
+        [ -f "$file" ] || continue
+        clusters=$(($clusters + (($(stat -c %s "$file") + $cluster_bytes - 1) / $cluster_bytes)))
     done
-
-    blocks=$((($size / 1024 + 55) / 32 * 32 ))
+    reserved_sectors=1 # boot-sector -R
+    reserved_bytes=$(($reserved_sectors * $sector_bytes))
+    fat_copies=2 # -f
+    if [ "$clusters" -le $(((1 << 12) - 2)) ]; then
+        fat_entry_bytes=3/2 # -F
+    elif [ "$clusters" -le $(((1 << 16) - 2)) ]; then
+        fat_entry_bytes=2 # -F
+    else
+        fat_entry_bytes=4 # -F
+    fi
+    fat_bytes=$((($clusters * $fat_entry_bytes + $sector_bytes - 1) / $sector_bytes * $sector_bytes))
+    root_entries=512 # -r
+    root_entry_bytes=32
+    root_bytes=$(($root_entries * root_entry_bytes))
+    size=$(($reserved_bytes + $fat_copies * $fat_bytes + $root_bytes + $clusters * $cluster_bytes))
+
+    track_sectors=32
+    track_bytes=$((sector_bytes * $track_sectors))
+    tracks=$((($size + $track_bytes - 1) / $track_bytes))
+    block_bytes=1024
+    blocks=$(($tracks * $track_bytes / $block_bytes))
 
     rm -f $CDDIR/boot/grub/efi.img
     mkfs.msdos -C "$CDDIR/boot/grub/efi.img" $blocks >/dev/null
-- 
2.1.4


Reply to: