Etiquetas

viernes, 20 de diciembre de 2013

Correr Raspian en una máquina virtual (qemu) y redimensionar su Sistema de Archivos (FS)

Si bien, la Raspberry Pi es de las cosas más transportables en este mundo, a veces nos la olvidamos. Contra ese olvido y otras aplicaciones puede servir correr Raspbian u otra distribución para arm1176 desde qemu.

A mí me resulta útil para probar algunas cosas sin tener que andar reescribiendo repetidamente en una SD, o para compilar algún programa que vaya a correr en la Raspberry desde un i386.
También esto puede servir para ajustar y customizar una imagen del S.O a nuestro gusto, darle el tamaño adecuado y después transferirla a memorias SDs.
Siguen algunos tips al respecto.

Como muchos sabrán QEMU es el acrónimo de "Quick Emulator", es un hypervisor que realiza emulación de hardware. Sirve para "traducir" binarios compilados de una arquitectura para correrlos en otra arquitectura de CPU o bien para correr una máquina virtual completa. Para esto último es que lo usaremos, para que nuestra VM sea una Raspberry corriendo en i386 o derivados.
Sin más introducciones, manos a la obra.
Las instrucciones para usar qemu con la variante arm de las Raspberry Pi puede encontrarse aquí:

http://xecdesign.com/qemu-emulating-raspberry-pi-the-easy-way/ En español y resumiendo el procedimiento puede resumirse de la siguiente forma:

1) Preparar el ambiente

Crear el directorio de trabajo.
Descargar el kernel "custom" para funcionar con qemu-arm:

wget http://xecdesign.com/downloads/linux-qemu/kernel-qemu

2) Bajar la imagen de Raspbian que vamos a usar como base

La imagen puede ser Raspbian o cualquier otra distro para RasPi. En el caso de Raspbian se puede descargar desde http://www.raspberrypi.org/downloads

Descompactar la imagen, de modo que quede, por ejemplo: 2013-09-25-wheezy-raspbian.img


3) Si no tenemos qemu instalado, instalarlo

En mi caso en el sistema "host" es un i386 con Debian, para instalar el paquete de qemu:
# aptitude install qemu-system

4) Ver que tengamos todo lo necesario

Primero verificamos que la versión de qemu fue compilada con soporte para arm1176

$ qemu-system-arm -cpu ?
Available CPUs:
arm1026
arm1136
arm1136-r2
arm1176
arm11mpcore
arm926
arm946
cortex-a15
cortex-a8
cortex-a9
cortex-m3
pxa250
pxa255
pxa260
pxa261
pxa262
pxa270
pxa270-a0
pxa270-a1
pxa270-b0
pxa270-b1
pxa270-c0
pxa270-c5
sa1100
sa1110
ti925t
any

En negrita puede verse que el paquete por defecto para Debian soporta arm1176, la arquitectura de la CPU de la Raspberry.
Si tenemos la imagen del S.O (Raspbian o el que fuere) y el kernel (archivo kernel-qemu), tenemos todo listo.


Como dice el tuturial citado, basta correr la siguiente línea en el directorio de trabajo para bootear el Raspbian:

$ qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -hda 2012-12-16-wheezy-raspbian.img
Véase: -m 256 indica cuántos Megabytes de la memoria de la máquina host (i386) le asignaremos a la MV Guest ("RasPi", digamos). Yo llegué a probar hasta con um mínimo de 64Mb (sin correr X) y todo fue bien.

PERO: en versiones más recientes de la imagen de raspbian (ejemplo, la que usé para este tutorial que es la 2013-09-25-wheezy-raspbian.zip) es necesario agregar el siguiente paso extra:

En el dir de trabajo creamos un sub-dir para punto de montaje de la imagen:
$ mkdir mnt
$ /sbin/fdisk -lu 2013-09-25-wheezy-raspbian.img
GNU Fdisk 1.2.4
Copyright (C) 1998 - 2006 Free Software Foundation, Inc.
This program is free software, covered by the GNU General Public License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.


Disk /mnt/backup/RaspberryPi/qemu-vms/raspbian/2013-09-25-wheezy-raspbian.img: 2 GB, 2961100800 bytes
255 heads, 63 sectors/track, 360 cylinders, total 5783400 sectors
Units = sectors of 1 * 512 = 512 bytes

Device Boot Start End Blocks Id System
/mnt/backup/RaspberryPi/qemu-vms/raspbian/2013-09-25-wheezy-raspbian.img1 8192 122879 64228 c FAT32 LBA
Warning: Partition 1 does not end on cylinder boundary.
/mnt/backup/RaspberryPi/qemu-vms/raspbian/2013-09-25-wheezy-raspbian.img2 122880 5785599 2835472 83 Linux
Warning: Partition 2 does not end on cylinder boundary.

El dato que nos interesa es el bloque de inicio de la segunda partición, que es donde está el sistema. Como el tamaño de los bloques es 512 bytes deberemos pasarle el offset a losetup haciendo el cálculo 122880 * 512:

# losetup -f --show -o `echo "122880 * 512" | bc` 2013-09-25-wheezy-raspbian.img
/dev/loop0
# mount /dev/loop0 mnt
# ls mnt
bin boot dev etc home lib lost+found media mnt opt proc root run sbin selinux srv sys tmp usr var

Primero, creamos el loop device, y después lo montamos en el dir mnt.

# vim mnt/etc/ld.so.preload

En ese archivo es necesario comentar la única línea que lo compone:

#/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so

# umount mnt
# losetup -d /dev/loop0

Esto último es importante, porque de lo contrario el raspbian en la MV no iniciará.

Fuente: http://www.raspberrypi.org/phpBB3/viewtopic.php?f=29&t=37386&p=311360#p311360

Redimensionando la imagen, para que la SD "virtual" sea más grande

Así como establecía el tuto http://xecdesign.com/qemu-emulating-raspberry-pi-the-easy-way/ ya podremos correr Raspbian virtualizado. El problema es que resta redimensionar la imagen de la SD, la cual viene reducida a 1.8Gb aproximadamente. Si no la redimensionamos el sistema no nos servirá de mucho, ya que le queda muy poco espacio disponible en el File System para, por ejemplo, instalar soft nuevo.
Dicho esto, vamos a "hacer" una SD "virtual" más grande, digamos de unos 4Gb:

1) Crear uma img "contenedora"

$ dd if=/dev/zero of=4gbraspi.img bs=1M count=4000
4000+0 registros leídos
4000+0 registros escritos
4194304000 bytes (4,2 GB) copiados, 59,7716 s, 70,2 MB/s

Como siempre digo, mucho cuidado con dd. Especialmente cuando estamos obligados a correrlo como root. Por eso, es bueno tener una máquina de "laboratorio" para hacer estas cosas que no sea una máquina "de trabajo". Por eso, el resto lo hacés a tu propia cuenta y riesgo. En este texto el caracter '$' indica que el comando puede ejecutarse como usuario plano y '#' indica que debe ejecutarse como root (con muuucho cuidado).
/dev/zero es un archivo especial del sistema, que cuando se lo lee siempre devuelve el caracter \0 (NULL).

2) Copiar la imagen original a la nuestra

2.1) Preparamos los loop devices:

Vamos a utilizar las "loop device" tools que son las encargadas de la enorme magia de permitirnos leer la imagen del FS como si fueran nodos de dispositivos. En la práctica eso se entiende mejor:

# losetup -f --show 4gbraspi.img
/dev/loop0
# losetup -f --show 2013-09-25-wheezy-raspbian.img
/dev/loop1

Véase que en /dev/loop tenemos nuestra imagen SD "nueva" y en /dev/loop1 tenemos la imagen de raspbian original.

2.2) Copiamos los datos a nuestra "nueva" imagen OJO, es como root

# dd if=/dev/loop1 of=/dev/loop0
5785600+0 registros leídos
5785600+0 registros escritos
2962227200 bytes (3,0 GB) copiados, 227,464 s, 13,0 MB/s

2.3) Podemos "desmontar" la imagen original, que ya no usaremos:

# losetup -d /dev/loop1

Llegado a este punto podríamos bootear con qemu nuestra imagen, pero no tendrá nada nuevo, porque el espacio restante estará repleto de bytes NULL. Entonces vamos a redimensionar la partición ext4 de la imagen raspbian y su File System para que ocupen todo el espacio restante.

3) A redimensionar

3.1) Veamos el tamaño total de la imagen (SD "virtual"):

# fdisk -l /dev/loop0
GNU Fdisk 1.2.4
Copyright (C) 1998 - 2006 Free Software Foundation, Inc.
This program is free software, covered by the GNU General Public License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.


Disk /dev/loop0: 4 GB, 4186667520 bytes
255 heads, 63 sectors/track, 509 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/loop0p1 1 8 64228 c FAT32 LBA
Warning: Partition 1 does not end on cylinder boundary.
/dev/loop0p2 8 361 2835472 83 Linux
Warning: Partition 2 does not end on cylinder boundary.

Vamos a agrandar la partición de Linux (tipo ext4) a todo el tamaño de la imagen, para eso usamos la herramienta parted:

# parted /dev/loop0
GNU Parted 2.3
Using /dev/loop0
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print
Model: (file)
Disk /dev/loop0: 4194MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number Start End Size Type File system Flags
1 4194kB 62,9MB 58,7MB primary fat16 lba
2 62,9MB 2962MB 2899MB primary ext4

(parted) rm 2
(parted) mkpart primary 62.9 4194
(parted) print
Model: (file)
Disk /dev/loop0: 4194MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number Start End Size Type File system Flags
1 4194kB 62,9MB 58,7MB primary fat16 lba
2 62,9MB 4194MB 4131MB primary ext4
(parted) quit
En negrita se indican los comandos en la consola de parted. Primero borramos la partición 2 (que originariamente iba hasta los 2962 MB) y luego la redefinimos com mkpart, iniciándose en los 62,9 MB y hasta los 4194, que es el tamaño total del dispositivo, como lo indicaba parted también.
Con esto la partición ya está redimensionada. Solo queda redimensionar el File System, para que la ocupe por completo.


4) Redimensionar el File System ext4

Debemos buscar el punto de inicio de la partición ext4 para pasárselo al offset de losetup
# fdisk -lu /dev/loop0
GNU Fdisk 1.2.4
Copyright (C) 1998 - 2006 Free Software Foundation, Inc.
This program is free software, covered by the GNU General Public License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.


Disk /dev/loop0: 4 GB, 4186667520 bytes
255 heads, 63 sectors/track, 509 cylinders, total 8177085 sectors
Units = sectors of 1 * 512 = 512 bytes

Device Boot Start End Blocks Id System
/dev/loop0p1 8192 122879 64228 c FAT32 LBA
Warning: Partition 1 does not end on cylinder boundary.
/dev/loop0p2 122880 8191999 4032315 83 Linux
Warning: Partition 2 does not end on cylinder boundary.

El número que nos importa es 122880, que es el sector donde comienza la segunda partición.
Lo multiplicamos por el tamaño de cada sector:

# echo '122880 * 512' | bc
62914560

62914560 es el offset que tenemos que pasarle a losetup:

# losetup -f --show -o 62914560 4gbraspi.img
/dev/loop1

Corremos un fsck para verificar la integridad del FS:

# e2fsck -f /dev/loop1
e2fsck 1.42.5 (29-Jul-2012)
Paso 1: Verificando nodos-i, bloques y tamaños
Paso 2: Verificando la estructura de directorios
Paso 3: Revisando la conectividad de directorios
Paso 4: Revisando las cuentas de referencia
Paso 5: Revisando el resumen de información de grupos
/dev/loop1: 72857/177056 files (0.1% non-contiguous), 427737/707840 blocks

Y, finalmente redimensionamos el F.S:

# resize2fs /dev/loop1
resize2fs 1.42.5 (29-Jul-2012)
Resizing the filesystem on /dev/loop1 to 1008640 (4k) blocks.
The filesystem on /dev/loop1 is now 1008640 blocks long.

Desmontamos los loops devices:

# losetup -d /dev/loop1
# losetup -d /dev/loop0

Y podemos probar nuestra "nueva" imagen:

$ qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -hda 4gbraspi.img

Una vez iniciada nuestra VM podremos ver que nuestra "SD" virtual ahora tiene el tamaño que definimos (en este ejemplo 4Gb aprox., pero eso va a gusto de cada cual, claro)

~$ df -h
Filesystem Size Used Avail Use% Mounted on
rootfs 3.8G 1.7G 2.0G 47% /
/dev/root 3.8G 1.7G 2.0G 47% /
devtmpfs 62M 0 62M 0% /dev
tmpfs 13M 184K 13M 2% /run
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 25M 0 25M 0% /run/shm

Si bien en este tuto usamos raspbian, el procedimiento debiera ser muy pero muy similar si se usa otra distro para Raspberry Pi.

1 comentario:

  1. Sobre cómo montar el loop device de la imagen de raspbian usando offset puede verse:

    http://www.equiscentrico.com.ar/2013/08/montar-particion-contenida-en-imagen.html

    ResponderEliminar