Author: Siro Mugabi

Category: qemu

Summary:

This page describes the process of transferring root filesystem data into a QEMU disk image. A Buildroot compiled root filesystem is considered.

Tags: qemu gnu linux

QEMU Disk Image Formats

QEMU supports a number of disk image formats. To view the complete listing:

$ qemu-img [-h|--help]
...
Supported formats: vvfat vpc vmdk vdi sheepdog rbd raw host_cdrom host_floppy host_device file qed qcow2 qcow parallels nbd dmg tftp ftps ftp https http cow cloop bochs blkverify blkdebug

and also,

$ man [1] qemu-img
...
Supported image file formats:
 raw ...
   qcow2 ...
     ...

Each disk format has its own advantages and limitations. For example, the raw format has the advantage of being simple and portable across other emulators. Unlike other formats, it fully supports growing and shinking via the qemu-img resize command. The qcow2 format, on the other hand, is the most versatile format. It presents several options including support for AES encryption, zlib based compression and support for multiple VM snapshots.

Ultimately, choice of an image format will depend on your particular requirements. Keep in mind that there exists the qemu-img convert command that allows conversion between image formats whenever necessary.

It is assumed that the current working directory already contains a Buildroot-based filesystem image and a kernel image to boot against1:

$ ls
bzImage rootfs.ext3

$ mkdir {boot,rfs,source}

$ WORKDIR=$PWD

Buildroot Compiled Filesystem Image Data into a raw Disk Image

Start off by creating a raw disk image via qemu-img2:

$ cd $WORKDIR
$ qemu-img create -f raw disk-img.raw 2.5G
$ qemu-img info disk-img.raw 
image: disk-img.raw
file format: raw
virtual size: 2.5G (2684354560 bytes)
disk size: 0

The disk image contains neither filesystem nor partitions. You may now partition the image with, say, fdisk. For instance:

$ sudo losetup /dev/loop0 disk-img.raw
$ sudo fdisk /dev/loop0
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xd1266856.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Partition type:
   p   primary (0 primary, 0 extended, 4 free)
 e   extended
Select (default p): p
Partition number (1-4, default 1): 
Using default value 1
First sector (2048-5242879, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-5242879, default 5242879): +500M

Command (m for help): n
Partition type:
   p   primary (1 primary, 0 extended, 3 free)
   e   extended
Select (default p): p
Partition number (1-4, default 2): 
Using default value 2
First sector (1026048-5242879, default 1026048): 
Using default value 1026048
Last sector, +sectors or +size{K,M,G} (1026048-5242879, default 5242879): 
Using default value 5242879

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 22: Invalid argument.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.

$ sudo fdisk -l -u /dev/loop0

Disk /dev/loop0: 2684 MB, 2684354560 bytes
255 heads, 63 sectors/track, 326 cylinders, total 5242880 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x56a8c587

    Device Boot      Start         End      Blocks   Id  System
/dev/loop0p1            2048     1026047      512000   83  Linux
/dev/loop0p2         1026048     5242879     2108416   83  Linux

$ qemu-img info disk-img.raw 
image: disk-img.raw
file format: raw
virtual size: 2.5G (2684354560 bytes)
disk size: 4.0K

Then format the newly created disk image partitions with a filesystem, for example:

$ sudo losetup -o $((2048*512)) /dev/loop1 /dev/loop0
$ sudo losetup -o $((1026048*512)) /dev/loop2 /dev/loop0
$ sudo mkfs.ext3 /dev/loop1
$ sudo mkfs.ext3 /dev/loop2
$ qemu-img info disk-img.raw 
image: disk-img.raw
file format: raw
virtual size: 2.5G (2684354560 bytes)
disk size: 200M

Now, mount and transfer the Buildroot filesystem data:

$ sudo mount /dev/loop1 boot
$ sudo mount /dev/loop2 rfs

$ sudo losetup /dev/loop3 rootfs.ext3 
$ sudo mount /dev/loop3 source
$ ls source/ 
bin   dev  home  linuxrc     media  opt   root  sbin  tmp  var
boot  etc  lib   lost+found  mnt    proc  run   sys   usr

$ sudo sh -c "(cd source/ && tar cf - . ) | (cd rfs/ && tar xvpf - )"
$ sudo sh -c "(cd source/boot/ && tar cf - . ) | (cd boot/ && tar xvpf - )"

$ sudo umount source
$ sudo umount rfs
$ sudo umount boot
$ sudo losetup -d /dev/loop3
$ sudo losetup -d /dev/loop2
$ sudo losetup -d /dev/loop1

$ qemu-img info disk-img.raw 
image: disk-img.raw
file format: raw
virtual size: 2.5G (2684354560 bytes)
disk size: 867M

Test the disk image. Your QEMU commandline may vary somewhat. The important thing to note here is the root=/dev/sda2 option:

$ sudo qemu-system-i386 -smp 2 -enable-kvm -kernel bzImage -drive file=disk-img.raw -append "root=/dev/sda2 fbcon=map:-1 rw"

Converting raw to qcow2

The next section covers direct transfer of the buildroot compiled filesystem data into a qcow2 image. Included here is a way of converting a pre-existing raw disk image containing filesystem data into a qcow2 image.

# qemu-img convert -O qcow2 disk-img.raw disk-img.qcow2

# qemu-img info disk-img.qcow2 
image: disk-img.qcow2
file format: qcow2
virtual size: 2.5G (2684354560 bytes)
disk size: 701M
cluster_size: 65536

# qemu-img info disk-img.raw 
image: disk-img.raw
file format: raw
virtual size: 2.5G (2684354560 bytes)
disk size: 867M

Test the disk image:

$ sudo qemu-system-i386 -smp 2 -enable-kvm -kernel bzImage -drive file=disk-img.qcow2,cache=writeback -append "root=/dev/sda2 quiet rw"

The cache=writeback option is used here for performance reasons when using QCOW2 images. Below is a screenshot of this VM instance running DirectFB's df_andi:

Buildroot andi

Buildroot Compiled Filesystem Image Data into a qcow2 Disk Image

Start off by creating a qcow2 image:

$ cd $WORKDIR
$ qemu-img create -f qcow2 disk-img.qcow2 2.5G
Formatting 'disk-img.qcow2', fmt=qcow2 size=2684354560 encryption=off cluster_size=65536

$ qemu-img info disk-img.qcow2 
image: disk-img.qcow2
file format: qcow2
virtual size: 2.5G (2684354560 bytes)
disk size: 140K
cluster_size: 65536

Partitioning with fdisk:

$ sudo modprobe nbd
$ sudo qemu-nbd -c /dev/nbd0 ${PWD}/disk-img.qcow2 
$ sudo fdisk /dev/nbd0
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xd2dc6707.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Partition type:
 p   primary (0 primary, 0 extended, 4 free)
e   extended
Select (default p): p
Partition number (1-4, default 1): 
Using default value 1
First sector (2048-5242879, default 2048): 
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-5242879, default 5242879): +500M

Command (m for help): n
Partition type:
 p   primary (1 primary, 0 extended, 3 free)
   e   extended
Select (default p): p
Partition number (1-4, default 2): 
Using default value 2
First sector (1026048-5242879, default 1026048): 
Using default value 1026048
Last sector, +sectors or +size{K,M,G} (1026048-5242879, default 5242879): 
Using default value 5242879

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.

$ sudo fdisk -l -u /dev/nbd0

Disk /dev/nbd0: 2684 MB, 2684354560 bytes
255 heads, 63 sectors/track, 326 cylinders, total 5242880 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xd2dc6707

   Device Boot      Start         End      Blocks   Id  System
/dev/nbd0p1            2048     1026047      512000   83  Linux
/dev/nbd0p2         1026048     5242879     2108416   83  Linux

$ qemu-img info disk-img.qcow2 
image: disk-img.qcow2
file format: qcow2
virtual size: 2.5G (2684354560 bytes)
disk size: 268K
cluster_size: 65536

Format the newly created partitions, for example:

$ sudo mkfs.ext3 /dev/nbd0p1

$ sudo mkfs.ext3 /dev/nbd0p2

$ qemu-img info disk-img.qcow2 
image: disk-img.qcow2
file format: qcow2
virtual size: 2.5G (2684354560 bytes)
disk size: 127M
cluster_size: 65536

Now, mount and transfer the Buildroot filesystem data:

$ sudo mount /dev/nbd0p1 boot
$ sudo mount /dev/nbd0p2 rfs

$ sudo losetup /dev/loop0 rootfs.ext3 
$ sudo mount /dev/loop0 source
# ls source/
bin   dev  home  linuxrc     media  opt   root  sbin  tmp  var
boot  etc  lib   lost+found  mnt    proc  run   sys   usr

$ sudo sh -c "(cd source/ && tar cf - . ) | (cd rfs/ && tar xvpf - )"
$ sudo sh -c "(cd source/boot/ && tar cf - . ) | (cd boot/ && tar xvpf - )"

$ ls rfs/
bin   dev  home  linuxrc     media  opt   root  sbin  tmp  var
boot  etc  lib   lost+found  mnt    proc  run   sys   usr

$ ls boot/
grub  lost+found

$ sudo umount source
$ sudo losetup -d /dev/loop0

$ sudo umount boot
$ sudo umount rfs
$ sudo qemu-nbd -d /dev/nbd0
/dev/nbd0 disconnected

$ qemu-img info disk-img.qcow2 
image: disk-img.qcow2
file format: qcow2
virtual size: 2.5G (2684354560 bytes)
disk size: 797M
cluster_size: 65536

Test the disk image:

$ sudo qemu-system-i386 -smp 2 -enable-kvm -kernel bzImage -drive file=disk-img.qcow2,cache=writeback -append "root=/dev/sda2 rw"

Also See

Resources

  • http://en.wikibooks.org/wiki/QEMU/Images

Footnotes

1. The images used here were x86 IA-32 [go back]

2. See Manipulating Disk Images with qemu-img for a description of QEMU disk image formats. [go back]