How to resize a qcow2 disk image on Linux

Qcow2 is the default virtual disk storage format used by Qemu (qcow stands for qemu copy-on-write). This image format makes use of thin provisioning, so, after we initially set the maximum virtual size of a disk, space is actually allocated only when used, but not made available back to the host when freed.In this article we see how to “sparsify” a qcow2 disk image to reclaim available space, how to expand it or shrink it, and how to manage the partitions layout on it from the host system, connecting it by using the NBD protocol.

In this tutorial you will learn:

  • What is thin-provisioning
  • How to reclaim unused space from a qcow2 image which uses thin-provisioning
  • What is the NBD protocol
  • How to connect a qcow2 disk image to the host system using the NBD protocol
  • How to expand a qcow2 image
  • How to shrink a qcow2 image
how-to-resize-a-qcow2-disk-image-on-linux
How to resize a qcow2 disk image on Linux
Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Distribution-independent
Software qemu-img, qemu-nbd
Other Root privileges to perform administrative tasks
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user

Reclaiming unused space from a qcow2 image

As we already said, by default, qcow2 images are thin provisioned. This means that when we create them, we provide a maximum virtual size, but only the space actually used on the disk image is subtracted from the space available on the host. Let’s verify this. On my system, I created a virtual machine by using virt-install, and specified a disk virtual size of 20GiB. The disk is named disk.qcow2. We can verify its size by using the ls command:

$ ls -lh disk.qcow2
-rw-------. 1 egdoc egdoc 21G Mar 2 10:10 disk.qcow2



In the above example, we invoked ls with the -l option to get a verbose output, and with -h to get a human-readable size (the size is rounded). The ls command doesn’t understand thin-provisioning, that is why the maximum size of the image is reported. If we check the actual space used by the disk image with a tool that is thin-provisioning aware like du, we get a different result:

$ du -h disk.qcow2 
1.4G disk.qcow2

As you can see, the output reports an actual used space of 1.4G. Information about a qcow2 disk image can also, conveniently, be retrieved using the qemu-img utility, running the info command (only when the disk is not in use):

$ qemu-img info disk.qcow2
image: disk.qcow2
file format: qcow2
virtual size: 20 GiB (21474836480 bytes)
disk size: 1.32 GiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: true
refcount bits: 16
corrupt: false
extended l2: false

In the output of the command, we can clearly see the difference between the virtual size of the disk (20 GiB) and the actual disk size (1.32 GiB).

As we said, thin-provisioning has the advantage of using host space only when it is actually used. To verify this, let’s create a dummy file on it the disk image, from the guest system:

[egdoc@virtualmachine]$ dd if=/dev/urandom of=dummyfile bs=1M count=2048

Above we ran dd using /dev/urandom as source and dummyfile as destination, and wrote 2048 blocks of 1MiB, in order to create a 2GiB file. If we check the disk image again, we can see how its actual size is now bigger:

$ qemu-img info disk.qcow2 
image: disk.qcow2
file format: qcow2
virtual size: 20 GiB (21474836480 bytes)
disk size: 3.32 GiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: true
refcount bits: 16
corrupt: false
extended l2: false

Space is only claimed when used by the guest. This, however, does only work one way: when space is freed on the disk image, it is not “released” to the host machine. We can easily verify this by removing the dummyfile:

[egdoc@virtualmachine]$ rm dummyfile

If we check again the disk image, we can see nothing changed, the space is still claimed:

$ qemu-img info disk.qcow2
image: disk.qcow2
file format: qcow2
virtual size: 20 GiB (21474836480 bytes)
disk size: 3.32 GiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: true
    refcount bits: 16
    corrupt: false
    extended l2: false

How can we make the space available again on the host? To accomplish such task we can use the virt-sparsify utility, which is part of the libguests-tools:

$ virt-sparsify --in-place disk.qcow2

We invoked the command with the --in-place option: this makes the operation takes place without the need of creating a copy of the disk image. Here is the command output:

◓ 25% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒═════════════════════════════════════════════════⟧ --:--
 100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[  18.4] Trimming /dev/sda1
[  18.5] Trimming /dev/sda2
[  19.4] Sparsify in-place operation completed with no errors



One very important thing to remember is that before running the command above, we must shutdown the guest system that is using the disk, to avoid possible corruptions. After the “sparsify” operation takes place, we can verify again the space used by the disk image, and see that it was reduced:

$ qemu-img info disk.qcow2 
image: disk.qcow2
file format: qcow2
virtual size: 20 GiB (21474836480 bytes)
disk size: 1.32 GiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: true
    refcount bits: 16
    corrupt: false
    extended l2: false

The virt-sparsify utility, as we just saw, is what we want to use if we are dealing with a qcow2 image, which by default makes use of thin-provisioning, and we want to make the space previously allocated on the disk image and now not used anymore, available again on the host. If we want to change the virtual size of the disk image (which we declared when we created the virtual machine), instead, we must use another strategy. Let’s see how to proceed.

Expanding a disk virtual size using qemu-img

Above we saw how to reclaim unused space from a qcow2 disk image using the virt-sparsify command. In certain situations, we may want to change the virtual size of the disk image, instead, so either expand it or shrink it. Both operations are quite simple; let’s start from the former.

The easiest method we can use to expand the virtual size of a qcow2 disk image, is to use the qemu-img and the resize command. All we have to do is to provide the path of the disk and the new absolute size (or the size increment) as arguments. The current disk virtual size, as we saw, is 20GiB. Supposing we want to expand it to 30GiB, we would proceed in the following way. As a first thing we would make a backup of the current disk, just in case something goes wrong:

$ cp disk.qcow2 disk.bk.qcow2

Than, to expand the size of the image, we would run the following command:

$ qemu-img resize disk.qcow2 30G

As an alternative, instead of the final, absolute size, we could specify the size increment:

$ qemu-img resize disk.qcow2 +10G

Once the additional space has been added to the disk image we have to grow the partitions and filesystems so that they make use of it. How to proceed in order to do that depends on what partition/filesystem we want to grow. To grow the last existing partition on the disk, for example, we could just use a partitioning tool from the guest system, while it is running. For other, more complex operations, we need to adopt another strategy: shutdown the guest system and modify the disk with an “external” tool.

Modifying partitions of a disk image using NBD

Some changes to the disk image layout cannot be performed from a running system: we cannot shrink or move partitions when they are mounted, for example. In such cases, we need to modify the disk image from the host system. We can accomplish this by using the NBD protocol to connect the disk image to the host system.

Nbd stands for Network Block Device: it is a protocol which allows a machine access a block device attached to another machine. On Linux this functionality is implemented by the nbd module, which needs to be loaded:

$ sudo modprobe nbd max_part=10

In this case we loaded the module with the max_part option to specify the maximum number of partitions for the device. Once the module is loaded, to actually mount the disk image, we run the following command:

$ sudo qemu-nbd -c /dev/nbd0 disk.qcow2



The qemu-nbdcommand is designed to export a QEMU disk image using the NBD protocol. In the example above, with the -c option we connected the filename (/dev/nbd0 in this case) to the given device: disk.qcow2. Once the disk is connected, we can use our favorite partitioning tool to modify its layout (remember to shutdown the guest system before doing any change!). For the sake of this tutorial we will use gparted:

$ gparted /dev/nbd0

The disk partition layout will be displayed just like that of any other block device:

gparted-qcow2
The qcow2 disk image opened in gparted

In the picture above we can clearly see the yet unused 10 Gib of space we previously added to the disk.

Shrinking a qcow2 image

To reduce the virtual size of a qcow2 disk image, we must first reduce the size of the partitions and filesystem on it. We need to proceed this way since all data in the space that will be removed by the shrinking operation will be lost.

Suppose we are dealing with our original image, which had a virtual size of 20GiB, and we want to reduce its size to 10GiB. First we make sure the guest system is off, than, as we did in the previous examples, than, we connect the disk and use our favorite partitioning tool on it.

In this case, before we shrink the image, we need to reduce the size of the /dev/nbd0p2 partition. We want to reduce the disk image by 10GiB, therefore as a security measure, to be sure data is not truncated, we will reduce the partition size to 8GiB (we can easily re-expand the partition later from the guest system). Here is the disk layout after the operation has been performed:

gparted-resized-nbd0p2
The /dev/nbd0p2 partition resized using gparted

Now that we resized the partition, we can close the partitioning program and disconnect the disk. In order to do so, we use qemu-nbd again. This time we invoke it with the -d option, which takes the path of device to be disconnected as argument:

$ sudo qemu-nbd -d /dev/nbd0

Finally, we can shrink the image:

$ qemu-img resize disk.qcow2 --shrink -10G

We invoked qemu-img just like we did when we expanded the image, but this time we used the -10G notation to specify that we want to subtract that amount of space; we also used the --shrink option: this is necessary in order to confirm the operation, since it is potentially dangerous (as we already said, data existing on the removed space will be lost).

By using the qemu-img info command, we can see the disk image virtual size is now 10G:

$ qemu-img info disk.qcow2
image: disk.qcow2
file format: qcow2
virtual size: 10 GiB (10737418240 bytes)
disk size: 1.32 GiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: true
    refcount bits: 16
    corrupt: false
    extended l2: false

To be sure everything is ok, we can now boot the guest system, no errors should be reported.

Conclusions

Qcow2 disk images uses thin-provisioning by default, so disk space its allocated only when actually used by a guest system, but it is not “released” back, when freed. In this article we saw how to “sparsify” a qcow2 image, in order to make the unused space on the virtual disk image available again on the host system, and we learned how to expand or shrink a qcow2 image. In the process, we saw how it is possible to connect the disk image to the host system by using the NBD protocol on Linux.



Comments and Discussions
Linux Forum