Resizing KVM disk images
I like my virtual machines independent and simple. That's why I normally use raw images and not special formats such as qcow2. Should you need snapshots, qcow2 would be the way to go with its copy on write feature. A special case where raw images are especially handy is when you have to shrink an image. I bumped into the issue when upgrading my Windows 7 virtual machine to Windows 10. I had to temporarily grow my 20 GB disk image to a 40 GB image, but shrinking back wasn't as straightforward.
Note: if you do use other than a raw image, you can always temporarily convert it into a raw image and back using qemu-img convert
.
Growing a disk image
To grow a disk image all you have to do is use the command qemu-img resize
, and then grow the guest partition to fill the image. In Windows 7/8/10 you would do this in Disk Management. Windows is capable of expanding a live partition without problems. In Linux you may use whatever tools available, I usually boot into a live CD and use GParted to do the resizing. There's a nice live CD distro to do just that.
Shrinking a guest partition
To shrink a Windows guest image there are a few preparations to make. Windows is terribly bad in shrinking it's volumes, but with a little patience it can be done. There are four things to do before trying to shrink a volume:
- Disable the kernel dump file. The setting is found in Control Panel > System > Advanced system settings > Advanced > Startup and Recovery > Write debugging information.
- Disable the hibernation feature. Open a Command Prompt as Administrator and type
powercfg.exe /hibernate off
. If the file C:\hiberfil.sys is not deleted automatically, you may now delete it. - Disable the paging file. The setting is found in Control Panel > System > Advanced system settings > Advanced > Performance > Advanced > Virtual memory.
- Reboot and defragment your disk.
You might have to repeat the last step until you are able to shrink the volume to a size you wish. The first three steps each remove a file that would prevent Disk Management from shrinking the volume. I was able to shrink my newly upgraded Windows 10 image from 40 GB to 15 GB using the steps above, when initially Windows Disk Management wouldn't let me shrink below 36 GB or so. Also, if you are upgrading your Windows as I did, remember to remove previous Windows installations from the hidden folders in C:\.
To shrink a Linux guest partition, as with growing, use the live CD.
Shrinking a guest image
After the partition inside the image has been shrunk, all there's left to do is shrink the image file itself. When using raw images you can mount them as loop devices.
On the host, set up the loop device using losetup -fv image.img
. If you have no other loop devices, this will probably become /dev/loop0.
Next, use fdisk to list contents of the loop device:
# fdisk -l /dev/loop0
Disk /dev/loop0: 40 GiB, 42949672960 bytes, 83886080 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
Disklabel type: dos
Disk identifier: 0x547e6d01
Device Boot Start End Sectors Size Id Type
/dev/loop0p1 * 2048 206847 204800 100M 7 HPFS/NTFS/exFAT
/dev/loop0p2 206848 31459327 31252480 14.9G 7 HPFS/NTFS/exFAT
In my case the first partition (100M) is a Windows 10 recovery partition. The second partition is the system partition. You can see that at this point the size of the image file is 40 GB but the partitions inside it take only 15 GB. Notice the end sector of the last partition, or 31459327
in this case. You may now detach the loop device (losetup -D
to detach all).
Finally, use dd to copy the interesting parts of the image into a new image file, with the same block size (512) and count of X+2
, where X is the end sector from above. The +2
will result in a one sector gap after the partition, which is what the Windows partitioning tool seems to do, so it's best to use it. Note that even without the gap, X+1
would be required to get the full partition as the index starts from zero. In my case the command looked like this:
$ dd if=image.img of=shrunk.img bs=512 count=31459329
The end result shrunk.img is a raw image with a correct size of 15 GB. Obviously with Linux guests the image shrinking works as with Windows guests as it's all just raw data for the host.
Update 2018-09-08: I just found out, for a couple of years already the dd tool has had a way to monitor the transfer progress. Just add the option: status=progress
. This is just for convenience and obviously not required.
2020-06-06 update: how to remove Windows recovery partition
Sometimes the Windows recovery partition may be annoyingly in the way. Even if you shrink your image and wipe it out, records of the partition still stay somewhere in partition tables. If you later grow the image - for updating your Windows or just for more space - it might be that an old recovery partition pops out of nowhere and blocks you from growing your system partition.
It is possible and quite trivial to remove a Windows recovery partition using the diskpart utility. First, open a Command Prompt as administrator. Then fire up diskpart.exe. The commands you need to give in the DISKPART prompt are as follows:
list disk
(lists all your disks)select disk 1
(replace number with the one you'd like to modify)list partition
(will show all the partitions, note the recovery partition number)select partition 3
(replace number with the recovery partition you want to remove)delete partition override
list partition
(the recovery partition is now gone)exit