Resizing Qemu Disk Image
A while ago I created a number of virtual machines using libvirt to isolate various tasks. At the time I created the virtual disks to be 20G due to storage limitations. After upgrading my hardware and over time that 20GB wasn’t enough for basic desktop environment and single task virtual machine.
When running libvirt, there are two main formats, raw and qcow2 used with qmeu.
- qcow2 which stands for qemu copy-on-write. is the most versatile format. This format will be smaller than the following, raw format and should be used if the filesystem does not support holes, such as Windows, zlib compression and support of multiple VM snapshots. When creating a disk image of this type, a file that only holds the necessary information for a blank disk. This can range from several hundred kilobytes to a few megabytes. The file will grow as more data gets added. However, when data is removed, the space is not reclaimed.
- raw disk image format, which is the default when running the
qemu-img create
command. This format has the advantage of being simple and easy to export to all other emulators. When using this format the size that you specify when creating the image will be reflected when you runls -lh
There are other formats supported by qemu-img, such as qcow, luks, vdi, vmdk, vpc, vmdx, and parallels. Personally, I’ve never used any other format for my virtual machines with the exception of converting from VirtualBox or VMWare.
The major difference between raw and qcow2 is that the aforementioned will be faster since it doesn’t have to go through two layers of indirection before being written. However, qcow2 does support snapshots which may be important. At home, I use qcow2 for the ability to make snapshots and I have those images on NVMe drives so the performance hit won’t be noticeable for what I am doing.
Raw Image Size Reporting
This section illustrates what was mentioned about how the reported size of a raw file compared to actual disk usage.
qemu-img create debian.img 120G
Formatting 'debian2.img', fmt=raw size=128849018880
ls -l
total 120G
-rw-r--r-- 1 root root 120G Jun 2 01:50 debian2.img
du -h debian.img
4.0K debian.img
qemu-img info debian.img
image: debian.img
file format: raw
virtual size: 120 GiB (128849018880 bytes)
disk size: 4 KiB
The ls
command doesn’t understand thin provisioning and will report the maximum size. The du
command will report the actual space that the file is using. Using the qemu-img
command will give the results from the ls
and du
command.
Inside the virtual machine we partition and format the virtual disk and then write some data onto the disk.
parted
GNU Parted 3.5
Using /dev/vdb
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print
Error: /dev/vdb: unrecognised disk label
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 129GB
Sector size (logical/physical): 512B/512B
Partition Table: unknown
Disk Flags:
(parted) mklabel gpt
(parted) mkpart
Partition name? []?
File system type? [ext2]?
Start? 1MiB
End? -1MiB
(parted) print
Model: Virtio Block Device (virtblk)
Disk /dev/vdb: 129GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 129GB 129GB ext2
(parted) quit
Information: You may need to update /etc/fstab.
mkfs.ext4 /dev/vdb1
mke2fs 1.47.0 (5-Feb-2023)
Discarding device blocks: done
Creating filesystem with 31456768 4k blocks and 7864320 inodes
Filesystem UUID: 80c01d19-a3e2-41be-8f7a-0a66581bb3c8
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872
Allocating group tables: done
Writing inode tables: done
Creating journal (131072 blocks): done
Writing superblocks and filesystem accounting information: done
mount /dev/vdb1 /mnt
dd if=/dev/urandom of=/mnt/random.txt bs=1M count=2048
Back on the host machine we can see that the disk usage has increased.
du -h debian.img
2.2G debian.img
Now lets delete the file we just created.
rm /mnt/random.txt
systemctl poweroff
Although the file was deleted, and space was freed on the virtual disk, the disk usage of the host machine is still the same.
du -h debian.img
2.2G debian.img
To reclaim disk space, we must power off the virtual machine and run the virt-sparsify
command that is in the libguests-tools package
du -h debian.img
2.5G debian.img
virt-sparsify --in-place debian2.img
[ 2.6] Trimming /dev/sda1
[ 3.0] Sparsify in-place operation completed with no errors
du -h debian2.img
518M debian2.img
Resizing the Disk Image
Resizing the disk is the easy part since the boundries of the partitions and filesystems do not change so you’ll have to resize those as well. When it comes to partitions and filesystems it’s generally painless.
The qemu-img resize
allows you to resize the image in two ways. You can resize it to a fixed size, or relative amount. First start by making a backup of the virtual disk.
cp debian.img debian-backup.img
Resize the virtual disk to a fixed size of 250GB.
qemu-img resize debian.img 250G
Image resized.
Resize virtual disk by adding 50G to it.
qemu-img resize debian.img +50G
Image resized.
Now that the virtual disk has been resized we can now resize the partitions. First we must load the nbd kernel module so we can bind a /dev/dbd block device to a QEMU server.
modprobe nbd
qemu-nbd -c /dev/nbd0 debian.img
parted /dev/nbd0
GNU Parted 3.5
Using /dev/nbd0
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) print
Model: Unknown (unknown)
Disk /dev/nbd0: 183GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 129GB 129GB ext4
(parted) resizepart 1
End? [129GB]? -1MiB
(parted) print
Model: Unknown (unknown)
Disk /dev/nbd0: 183GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 1049kB 183GB 183GB ext4
Next we need to resize the filesystem followed by disconnecting the virtual disk.
resize2fs /dev/nbd0p1
resize2fs 1.47.0 (5-Feb-2023)
Resizing the filesystem on /dev/nbd0p1 to 44563968 (4k) blocks.
The filesystem on /dev/nbd0p1 is now 44563968 (4k) blocks long.
qemu-nbd -d /dev/nbd0
TIP: You can also use
gparted
, which is not only easier, but allows you to move partitions arround and automatically resizes filesystems for you.