Virtual Machines

Disk Images

-> ls --size --human-readable *.vdi
 14G system.vdi  2.1M tinker.vdi

Disk-image formats

There's not much to see in a fresh-made raw image:

-> echo '1024^3' | bc
-> qemu-img create -f raw tinker1.raw 1G
Formatting 'tinker1.raw', fmt=raw size=1073741824
-> dd if=/dev/zero of=tinker2.raw bs=1G count=1
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB) copied, 1.61633 s, 664 MB/s
-> diff --report-identical-files tinker1.raw tinker2.raw 
Files tinker1.raw and tinker2.raw are identical

A potential advantage of the raw format is that you can use familiar command-line tools to configure a raw image directly from your host machine. This lengthy example demonstrates how to create a disk image with four GPT partitions, each with its own file system: a 128 MiB EFI partition, a 1 GiB NTFS partition, a 1 GiB Ext4 partition, and a 1 GiB swap partition. First, create the disk image:

-> qemu-img create -qf raw tinker.raw 3.2G

Next, use sgdisk to create the partitions on tinker.raw in one swoop, like so:

-> sgdisk tinker.raw --new=1:0:+128M --typecode=1:EF00 \
  -n 2:0:+1G -t 2:0700 -n 3:0:+1G -t 3:8300 -n 4:0:+1G -t 4:8200 \
The operation has completed successfully.

Option --new=1:0:+128M creates partition 1 at the first open sector (denoted as 0) and allocates 128 MiB for it. Option --typecode=1:EF00 specifies the type for partition 1. Partitions 2, 3, and 4 are created similarly, but the subsequent style abbreviates option --new as -n and option --typecode as -t for convenience. You can also let sgdisk number the partitions successively in the order listed by using 0 for the partition number:

-> sgdisk tinker.raw -n 0:0:+128M -t 0:EF00 -n 0:0:+1G -t 0:0700 -n 0:0:+1G -t 0:8300 -n 0:0:+1G -t 0:8200 --verify

Either way, here's the result:

-> parted tinker.raw unit B print
Number  Start        End          Size         File system  Name  Flags
 1      1048576B     135266303B   134217728B                      boot, esp
 2      135266304B   1209008127B  1073741824B                     msftdata
 3      1209008128B  2282749951B  1073741824B
 4      2282749952B  3356491775B  1073741824B

Other partition utilities that accept a raw disk image include gdisk, fdisk, gparted, and partx.

The next step is to associate a loopback device with each partition. For this, losetup needs the offset into the backing file tinker.raw where each partition begins, and it needs the size of each partition. These numbers come from parted's report. Start with the first partition:

-> losetup --find --offset 1048576 --sizelimit 134217728 tinker.raw

Option --find chooses the first loopback device available; e.g. /dev/loop0. Options --offset and --sizelimtit locate the start and end of the mapping. Continue similarly for the remaining partitions:

-> losetup -f -o 135266304  --sizelimit 1073741824 tinker.raw
-> losetup -f -o 1209008128 --sizelimit 1073741824 tinker.raw
-> losetup -f -o 2282749952 --sizelimit 1073741824 tinker.raw

Here's the picture when all is done:

-> losetup --list
/dev/loop0  134217728    1048576         0  0 /home/distros/vm/tinker.raw
/dev/loop1 1073741824  135266304         0  0 /home/distros/vm/tinker.raw
/dev/loop2 1073741824 1209008128         0  0 /home/distros/vm/tinker.raw
/dev/loop3 1073741824 2282749952         0  0 /home/distros/vm/tinker.raw

The standard commands to create file systems work transparently on a loopback device:

-> mkfs --type vfat -F 32 -n 'ESP' /dev/loop0
-> mkfs --type ntfs -p 0 -H 0 -S 0 --quick --label 'For Windows' /dev/loop1
-> mkfs --type ext4 -L 'For Linux' /dev/loop2
-> mkswap --label swap /dev/loop3

Finish with a quick sanity check:

-> sgdisk tinker.raw --verify
No problems found. 157219 free sectors (76.8 MiB) available in 2
segments, the largest of which is 155205 (75.8 MiB) in size.

Your system now sees four block devices, each with its own file system:

-> lsblk --output NAME,LABEL,FSTYPE,SIZE,PHY-SEC,LOG-SEC /dev/loop?
loop0 EFI/ESP     vfat    128M     512     512
loop1 For Windows ntfs      1G     512     512
loop2 For Linux   ext4      1G     512     512
loop3 swap        swap      1G     512     512

You can mount and use a file system as usual without regard to its underlying disk image (tinker.raw). For example:

-> mount /dev/loop2 /mnt
-> ls /mnt
-> umount /mnt

When you're done tinkering:

-> losetup --detach /dev/loop0 /dev/loop1 /dev/loop2 /dev/loop3

Or in the absence of other loopback devices, you can abbreviate:

-> losetup --detach-all

Once you've configured your partitions, you can convert your disk image to another format, if you wish:

-> qemu-img convert tinker.raw -O qcow2 tinker.qcow2
-> VBoxManage convertfromraw tinker.raw tinker.vdi
-> stat --print "%-12n size in bytes: %10s\n" tinker.raw tinker.vdi tinker.qcow2
tinker.raw   size in bytes: 3435973632
tinker.vdi   size in bytes:   26214400
tinker.qcow2 size in bytes:    7798784


Intel (VT-x) and AMD (AMD-V) i


Use qemu-img to create a file to host a VM's disk image:

-> qemu-img create tinker.raw 5G
Formatting 'tinker.img', fmt=raw size=5368709120
-> qemu-img create -f qcow2 tinker.qcow2 5G
Formatting 'tinker.qcow2', fmt=qcow2 size=5368709120 encryption=off cluster_size=65536 lazy_refcounts=off 
-> echo "5 * 1024^3" | bc

See the command's man page for more on encryption, cluster_size, lazy_refcounts, and other options.

Even out-of-the box, a raw file may occupy its allocated allotment; a QCOW2 file occupies only the space its contents need:

-> stat --print "%n size in bytes: %s\n" tinker.raw tinker.qcow2 
tinker.raw size in bytes: 5368709120
tinker.qcow2 size in bytes: 197120

Use sub-command info to get basic information about an image:

-> qemu-img info tinker.raw
image: tinker.img
file format: raw
virtual size: 5.0G (5368709120 bytes)
disk size: 0
-> qemu-img info tinker.qcow2
image: tinker.qcow2
file format: qcow2
virtual size: 5.0G (5368709120 bytes)
disk size: 196K
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: false

To list the image formats that QEMU supports:

-> qemu-img --help | grep "Supported formats" | fold --spaces
Supported formats: blkdebug blkverify bochs cloop cow dmg file ftp ftps gluster 
host_cdrom host_device host_floppy http https iscsi nbd parallels qcow qcow2 
qed quorum raw rbd sheepdog ssh tftp vdi vhdx vmdk vpc vvfat

Command qemu-kvm is a shortcut:

-> cat `which qemu-kvm`
exec /usr/bin/qemu-system-x86_64 -machine accel=kvm "$@"

Here's how to install Fedora 22 (Beta) to file fedora22.qcow2:

-> qemu-img create -qf qcow2 fedora22.qcow2 10G
-> qemu-kvm -m 4G -bios efi.bin -boot d -cdrom ../fedora/Fedora-Live-Xfce-x86_64-22_Beta-3.iso -hda fedora22.qcow2
-> qemu-kvm -m 4G -bios efi.bin -hda fedora22.qcow2

If you prefer that QEMU emulate a BIOS host, drop -bios efi.bin from the last two commands.

Two drives

-> qemu-img create -q -f qcow2 system.qcow 10G
-> qemu-img create -q -f qcow2 data.qcow 10G
-> qemu-kvm -m 2G -bios efi.bin -boot d -cdrom Fedora/Fedora-Live-Xfce-x86_64-22_Beta-3.iso -hda system.qcow -hdb data.qcow 2> /dev/null &
-> qemu-kvm -m 2G -bios efi.bin -boot c -hda system.qcow -hdb data.qcow 2> /dev/null &

Here's how to install Windows 8 from its setup DVD to image file windows8.img, for example.

First, create an image file to serve as the hard disk underlying Windows:

-> qemu-img create -f raw windows8.img 15G
Formatting 'windows8.img', fmt=raw size=16106127360

Now boot a VM from the Windows 8 setup DVD to install Windows 8 to windows8.img:

-> qemu-kvm -m 4G -boot d -cdrom /dev/cdrom -hda windows8.img -usbdevice tablet -net none

Here, the option -net none disables networking during the installation for the convenient side effect of dissuading the Windows installer from pushing creation of a Microsoft account. To facilitate repeated installations, you can first copy the ISO image of the DVD to file win8.iso, say, and subsequently substitute win8.iso for the actual DVD:

-> dd if=/dev/cdrom of=win8.iso
7615812+0 records in
7615812+0 records out
3899295744 bytes (3.9 GB) copied, 272.626 s, 14.3 MB/s
-> qemu-kvm -m 4G -boot d -cdrom win8.iso -hda windows8.img -usbdevice tablet -net none

To run Windows 8 from windows8.img:

-> qemu-kvm -m 4G -hda windows8.img -usbdevice tablet

You do not need the setup DVD to run the VM. You can add option -net none to dissuade Windows from asking you to activate your installation.

As an aside, note that the Windows installer formats windows8.img as an MSDOS disk and creates two partitions on it:

-> parted windows8.img unit MiB print
Partition Table: msdos
Number … Size      Type     File system  Flags
 1     … 350MiB    primary  ntfs         boot
 2     … 15008MiB  primary  ntfs

The installer chooses this configuration because QEMU emulates a BIOS-based computer (by default).

This next example repeats the installation of Windows 8 above but for a UEFI computer. Here, QEMU replaces its built-in BIOS firmware with the UEFI firmware in efi.bin from OVMF.

The choice of firmware does not affect how the disk image is created:

-> qemu-img create -f raw windows8-efi.img 15G
Formatting 'windows8-efi.img', fmt=raw size=16106127360

For installing and subsequently running Windows 8, just add -bios efi.bin to the commands used for the default BIOS:

-> qemu-kvm -m 4G -bios efi.bin -boot d -cdrom win8.iso -hda windows8-efi.img -usbdevice tablet -net none
-> qemu-kvm -m 4G -bios efi.bin -boot c -hda windows8-efi.img -usbdevice tablet

The screen resolution is limited to 800x600 with OVMF, however.

When installing to an UEFI computer, Windows setup formats the disk as GPT and creates four partitions on it:

-> parted windows8-efi.img unit MiB print
Partition Table: gpt
Number … Size      File system  Name                          Flags
 1     … 300MiB    ntfs         Basic data partition          hidden, diag
 2     … 99.0MiB   fat32        EFI system partition          boot, esp
 3     … 128MiB                 Microsoft reserved partition  msftres
 4     … 14831MiB  ntfs         Basic data partition          msftdata

The installer chooses this configuration when it detects a UEFI host.


To install VirtualBox:

-> dnf install VirtualBox kmod-VirtualBox-$(uname -r) kmod-VirtualBox

VirtualBox requires driver vboxdrv synced with the version of the running kernel, and it cannot boot a virtual machine without this driver. It will detect a missing driver civilly, tell you what's going on, and then give a remedy:

Kernel driver not installed (rc=-1908)
The VirtualBox Linux kernel driver (vboxdrv) is probably not loaded.You may not have kernel driver installed for kernel that is runnig, if so you may do as root: 'yum install kmod-VirtualBox-$(uname -r) kmod-VirtualBox'

This remedy does the trick provided that the desired module is available. But you may encounter a lag between the release of a kernel and subsequent release of the matching VirtualBox driver. For a simple workaround, drop back to an earlier release of the kernel until the driver catches up.

To copy a raw disk image into VDI-format image:

-> VBoxManage convertfromraw tinker.raw tinker.vdi
Converting from raw image file="tinker.raw" to file="tinker.vdi"...
Creating dynamic image with size 1073741824 bytes (1024MB)...

-> VBoxManage showhdinfo tinker.vdi 
UUID:           9ac846c8-e821-4cd2-8196-73b46e4f1beb
Parent UUID:    base
State:          created
Type:           normal (base)
Location:       /home/distros/vm/tinker.vdi
Storage format: VDI
Format variant: dynamic default
Capacity:       1024 MBytes
Size on disk:   2 MBytes