Compactar imágenes de disco de VirtualBox: vditool vs VBoxManage
En Probar en VirtualBox una memoria USB de arranque obtuvimos una imagen vdi
de una imagen que habíamos obtenido con dd
de una memoria USB de arranque para simular su funcionamiento sin tener que reinciar una y otra vez.
La imagen que creamos allí era, por defecto, de tamaño fijo (no dinámico), de modo que ocupaba en el disco duro el mismo espacio del que disponía la memoria USB, en mi caso 8 GB (que no 8 GiB):
-rwxr-xr-x 1 root root 8000004096 2008-09-26 23:41 imagen_mem_usb.img* -rw------- 1 vicente vicente 8000666112 2008-10-05 18:57 imagen_mem_usb.vdi*
Como vimos en Montar imágenes de disco vdi de VirtualBox, podemos convertir dicha imagen de tamaño fijo en una de tamaño dinámico y además, eliminando los bloques no usados, con “vditool SHRINK
“:
$ vditool SHRINK imagen_mem_usb.vdi vditool Copyright (c) 2004-2008 innotek GmbH. Shrinking VDI image file="imagen_mem_usb.vdi"... progress: 0%Log created: 2008-09-27T12:19:10.484950000Z Executable: /usr/lib/virtualbox/vditool Arg[0]: /usr/lib/virtualbox/vditool Arg[1]: SHRINK Arg[2]: imagen_mem_usb.vdi Dumping VDI image "imagen_mem_usb.vdi" mode=r/w fOpen=0 File=00000004 Header: Version=00010001 Type=2 Flags=0 Size=8000004096 Header: cbBlock=1048576 cbBlockExtra=0 cBlocks=7630 cBlocksAllocated=7630 Header: offBlocks=512 offData=31232 Header: Geometry: C/H/S=15501/16/63 cbSector=512 Mode=2 Header: uuidCreation={53bea69e-c21b-4273-be9e-df3fa8f1ffd7} Header: uuidModification={7a7be4b9-188a-42b2-298e-07eaa266a651} Header: uuidParent={00000000-0000-0000-0000-000000000000} Header: uuidParentModification={00000000-0000-0000-0000-000000000000} Image: fFlags=00000000 offStartBlocks=512 offStartData=31232 Image: uBlockMask=000FFFFF uShiftIndex2Offset=20 uShiftOffset2Index=20 offStartBlockData=0 ...........10%..........20%..........30%..........40%..........50% ..........60%..........70%..........80%..........90%..........100% Dumping VDI image "imagen_mem_usb.vdi" mode=r/w fOpen=0 File=00000004 Header: Version=00010001 Type=2 Flags=0 Size=8000004096 Header: cbBlock=1048576 cbBlockExtra=0 cBlocks=7630 cBlocksAllocated=7621 Header: offBlocks=512 offData=31232 Header: Geometry: C/H/S=15501/16/63 cbSector=512 Mode=2 Header: uuidCreation={53bea69e-c21b-4273-be9e-df3fa8f1ffd7} Header: uuidModification={7a7be4b9-188a-42b2-298e-07eaa266a651} Header: uuidParent={00000000-0000-0000-0000-000000000000} Header: uuidParentModification={00000000-0000-0000-0000-000000000000} Image: fFlags=00000000 offStartBlocks=512 offStartData=31232 Image: uBlockMask=000FFFFF uShiftIndex2Offset=20 uShiftOffset2Index=20 offStartBlockData=0 The operation completed successfully!
Sin embargo, en este caso no conseguimos apenas ningún ahorro de espacio:
-rwxr-xr-x 1 root root 8000004096 2008-09-26 23:41 imagen_mem_usb.img* -rw------- 1 vicente vicente 7993326080 2008-09-30 21:04 imagen_mem_usb.vdi*
La imagen compactada es tan sólo 8000666112-7993326080=7340032 bytes más pequeña que la anterior. Esto es debido a que el proceso de compactación de vditool
sólo es capaz de ahorrarnos los bloques que contengan íntegramente ceros, y en el caso de mi memoria USB, fruto de innumerables movimientos de ficheros, ya vemos que son muy pocos los bloques que continuaban conteniendo exclusivamente ceros. Es bien sabido que cuando borramos un fichero, su contenido sigue estando íntegramente en el disco y sólo anotamos en las estructuras del sistema de ficheros que ese espacio que antes usaba tal fichero, ahora está disponible para cualquier otro fichero. Y eso es en lo que se basan los programas de recuperación de ficheros eliminados para hacer su trabajo con mayor o menor éxito según sea el sistema de ficheros y según las operaciones de ficheros que se hayan realizado desde el borrado.
Por tanto, normalmente las imágenes de disco que hayan tenido mucho trajín de archivos y que no tengan mucho espacio sobrante, tendrán pocos bloques que puedan ser eliminados durante la compactación, ya que esos bloques es muy posible que contengan restos de ficheros ya eliminados y no contengan solo ceros.
Para tener éxito en la compactación, hemos de llenar todos esos bloques no usados de ceros previamente. Una forma muy sencilla de hacerlo es montar la partición y crear un fichero muy grande, que llene el sistema de ficheros, y que sólo contenga ceros. Todo el espacio que antes estaba libre lo ocupará ahora un archivo lleno de ceros que, si a continuación borramos, volveremos a tener el espacio libre, pero ahora lleno de ceros. Lo podemos hacer muy fácilmente con un dd
desde /dev/zero
, y el comando lo podemos ejecutar sobre la partición montada en el sistema operativo Host o desde dentro del sistema operativo Guest cuando éste está arriba y funcionando.
Por ejemplo, si lo queremos hacer desde el Host sobre una imagen vdi
de tamaño fijo, lo haremos así:
$ vditool DUMP imagen_mem_usb.vdi | grep offData Header: offBlocks=512 offData=31232 $ sudo mount -o loop,offset=$(( 31232 + 63 * 512 )) imagen_mem_usb.img /mnt/imgusb $ cd /mnt/imgusb $ sudo dd if=/dev/zero of=ceros dd: writing to `zeros': No space left on device 5677697+0 records in 5677696+0 records out 2906980352 bytes (2.9 GB) copied, 749.509 s, 3.9 MB/s $ rm ceros
y al compactar:
$ vditool SHRINK imagen_mem_usb.vdi vditool Copyright (c) 2008 Sun Microsystems, Inc. Shrinking VDI image file="imagen_mem_usb.vdi"... progress: 0%Log created: 2008-10-05T17:59:58.749328000Z Executable: /usr/lib/virtualbox/vditool Arg[0]: /usr/lib/virtualbox/vditool Arg[1]: SHRINK Arg[2]: imagen_mem_usb.vdi Dumping VDI image "imagen_mem_usb.vdi" mode=r/w fOpen=0 File=00000003 Header: Version=00010001 Type=2 Flags=0 Size=8000004096 Header: cbBlock=1048576 cbBlockExtra=0 cBlocks=7630 cBlocksAllocated=7630 Header: offBlocks=512 offData=31232 Header: Geometry: C/H/S=0/0/0 cbSector=512 Header: uuidCreation={764143e6-e068-4f86-bae6-51de1fd4b374} Header: uuidModification={4ef44cb6-1d79-4fa2-8e00-d6985bdcc6e8} Header: uuidParent={00000000-0000-0000-0000-000000000000} Header: uuidParentModification={00000000-0000-0000-0000-000000000000} Image: fFlags=00000000 offStartBlocks=512 offStartData=31232 Image: uBlockMask=000FFFFF uShiftIndex2Offset=20 uShiftOffset2Index=20 offStartBlockData=0 ...........10%..........20%..........30%..........40%..........50% ..........60%..........70%..........80%..........90%..........100% Dumping VDI image "imagen_mem_usb.vdi" mode=r/w fOpen=0 File=00000003 Header: Version=00010001 Type=2 Flags=0 Size=8000004096 Header: cbBlock=1048576 cbBlockExtra=0 cBlocks=7630 cBlocksAllocated=4918 Header: offBlocks=512 offData=31232 Header: Geometry: C/H/S=0/0/0 cbSector=512 Header: uuidCreation={764143e6-e068-4f86-bae6-51de1fd4b374} Header: uuidModification={4ef44cb6-1d79-4fa2-8e00-d6985bdcc6e8} Header: uuidParent={00000000-0000-0000-0000-000000000000} Header: uuidParentModification={00000000-0000-0000-0000-000000000000} Image: fFlags=00000000 offStartBlocks=512 offStartData=31232 Image: uBlockMask=000FFFFF uShiftIndex2Offset=20 uShiftOffset2Index=20 offStartBlockData=0 The operation completed successfully!
esta vez sí que estaremos ganado todo el espacio posible, todo el que de verdad no se esté usando en el sistema de ficheros:
-rwxr-xr-x 1 root root 8000004096 2008-09-26 23:41 imagen_mem_usb.img* -rw------- 1 vicente vicente 5156928000 2008-10-05 20:13 imagen_mem_usb.vdi*
Ese mismo dd
lo podríamos realizar dentro de un Linux virtualizado o incluso dentro de un Windows virtualizado con el dd
del Cygwin, por ejemplo.
Sin embargo, este sencillo sistema, que tiene la ventaja de que no necesitamos ninguna herramienta externa, tiene la desventaja de que por unos minutos tendremos el sistema de ficheros casi lleno, y por unos segundos, completamente lleno, con los problemas que esto nos podría causar en un sistema en producción real. Es por eso que el Tutorial: All about VDIs, en la sección How can I reduce the size of a dynamic VDI on disk?, nos propone usar herramientas externas para llenar de ceros los bloques no usados por ningún fichero actual. Para Windows nos propone el SDelete, que usaremos así para referirnos a las particiones C y D:
sdelete -c C sdelete -c D
y para Linux nos propone el zerofree, que se ha de usar con particiones ext2 y ext3 montadas sólo de lectura:
mount -n -o remount,ro -t ext2 /dev/sda1 / zerofree /dev/sda1
vditool vs VBoxManage
La herramienta vditool
, de la que venimos haciendo un uso extensivo, no está incluida en la versión cerrada de VirtualBox, aunque sigue estando incluso en las las versiones más recientes de VirtualBox-OSE. Entendemos, por tanto, que el fabricante tal vez quiere que dejemos de usar esta herramienta en futuras versiones. ¿Qué alternativas tenemos?
Su reemplazo lo podemos encontrar en las diferentes opciones del comando VBoxManage
:
VBoxManage registerimage disk|dvd|floppy <filename> [-type normal|immutable|writethrough] (disk only) VBoxManage unregisterimage disk|dvd|floppy <uuid>|<filename> VBoxManage showvdiinfo <uuid>|<filename> VBoxManage createvdi -filename <filename> -size <megabytes> [-static] [-comment <comment>] [-register] [-type normal|writethrough] (default: normal) VBoxManage modifyvdi <uuid>|<filename> compact VBoxManage clonevdi <uuid>|<filename> <outputfile> VBoxManage convertdd [-static] <filename> <outputfile> VBoxManage convertdd [-static] stdin <outputfile> <bytes> VBoxManage internalcommands converttoraw [-format <fileformat>] <filename> <outputfile>
Así, el “vditool DD
” lo podemos sustituir con un “VBoxManage convertdd
“; el “vditool COPYDD
” lo podemos hacer con un “VBoxManage internalcommands converttoraw
“; y el “vditool SHRINK
” lo reemplazaremos con un “VBoxManage modifyvdi /path/imagen.vdi compact
“:
$ VBoxManage modifyvdi /path/imagen_mem_usb.vdi compact VirtualBox Command Line Management Interface Version 2.0.2 (C) 2005-2008 Sun Microsystems, Inc. All rights reserved. Shrinking '/path/imagen_mem_usb.vdi': 0%...........10%..........20%..........30%..........40%..........50% ..........60%..........70%..........80%..........90%..........100%
Únicamente tenemos que tener en cuenta que si no tenemos la imagen registrada (“VBoxManage registerimage disk
” o con el interfaz gráfico) nos aparecerán errores como estos, aunque la tarea se hará igualmente:
$ VBoxManage modifyvdi /path/imagen_mem_usb.vdi compact VirtualBox Command Line Management Interface Version 2.0.2 (C) 2005-2008 Sun Microsystems, Inc. All rights reserved. [!] FAILED calling virtualBox->FindVirtualDiskImage(filepath, vdi.asOutParam()) at line 3320! [!] Primary RC = NS_ERROR_INVALID_ARG (0x80070057) - Invalid argument value [!] Full error info present: true , basic error info present: true [!] Result Code = NS_ERROR_INVALID_ARG (0x80070057) - Invalid argument value [!] Text = Could not find a registered VDI hard disk with the file path '/path/imagen_mem_usb.vdi' [!] Component = VirtualBox, Interface: IVirtualBox, {557a07bc-e6ae-4520-a361-4a8493199137} [!] Callee = IVirtualBox, {557a07bc-e6ae-4520-a361-4a8493199137} Shrinking '/path/imagen_mem_usb.vdi': 0%...........10%..........20%..........30%..........40%..........50% ..........60%..........70%..........80%..........90%..........100%
Mucho peor lo tenemos con el “vditool DUMP
“, necesario para montar las imágenes de tamaño fijo, puesto que no tiene un reemplazo en el “VBoxManage showvdiinfo
“:
$ VBoxManage showvdiinfo /path/imagen_mem_usb.vdi VirtualBox Command Line Management Interface Version 2.0.2 (C) 2005-2008 Sun Microsystems, Inc. All rights reserved. UUID: 53bea69e-c21b-4273-be9e-df3fa8f1ffd7 Registered: no Accessible: yes Size: 7629 MBytes Current size on disk: 4968 MBytes Type: standard Storage type: Virtual Disk Image (VDI) Path: /path/imagen_mem_usb.vdi
Sin embargo, hay una cosa muy útil que VBoxManage
sí aporta sobre el vditool
, y es que desde junio (es decir, en las versiones 2.0.X), el VBoxManage
permite crear imágenes vdi
de tamaño dinámico directamente desde la imagen creada con dd
, dando la opción de crear una imagen de tamaño estático con la opción -static
sólo si lo especificamos:
VBoxManage convertdd [-static] <filename> <outputfile>
Probémoslo convirtiendo una imagen de dd
en la que hemos escrito ceros en todo el espacio vacío a un vdi
de tamaño dinámico directamente:
$ VBoxManage convertdd imagen_mem_usb_ceros.img imagen_mem_usb_vbm.vdi VirtualBox Command Line Management Interface Version 2.0.2 (C) 2005-2008 Sun Microsystems, Inc. All rights reserved. Converting VDI: from DD image file="imagen_mem_usb_ceros.img" to file="imagen_mem_usb_vbm.vdi"... Creating dynamic image with size 8000004096 bytes (7630MB)...
Vemos que el resultado es exactamente el mismo que anteriormente tras los pasos “vditool DD
” y “vditool SHRINK
“:
-rwxr-xr-x 1 root root 8000004096 2008-10-05 18:17 imagen_mem_usb_ceros.img* -rw------- 1 vicente vicente 5156928000 2008-10-05 20:36 imagen_mem_usb.vdi* -rw------- 1 vicente vicente 5156928000 2008-10-05 20:51 imagen_mem_usb_vbm.vdi*
:wq
Interesante artículo sobre el funcionamiento de los discos duros virtuales y su reducción.