Compacting virtual disks on Generation 2 Linux Hyper-V 2012 R2 VM’s
I had a very interesting battle with Gen 2 RHEL/CentOS/OracleLinux 7.x VM’s vhdx files not compacting.
Below are a couple of things that made this more difficult than expected:
Hypervisor: Hyper-V 2012 R2
Generation of VM: Generation 2
Boot loader: UEFI without secure boot booting \EFI\redhat\shim.efi (Secure boot currently is only supported by Windows VM’s)
Virtual Disk Type: Virtual SCSI disk as VHDX
VM OS: Redhat Enterprise Linux 7.x or derivative of RHEL as listed above.
Checkpoints: NONE – if you have any then export a copy of the VM for a backup and remove all checkpoints/snapshots.
Compacting virtual disks on Generation 2 Linux Hyper-V 2012 R2 VM’s was a real pain until I figured everything out.
Hyper-V is an interesting Hypervisor when it comes to working with Linux virtual machines because the support is a bit behind other Hypervisors when it comes to Linux. However it exceeds in Windows VM’s because Microsoft wants their product to run their operating systems better than anyone else therefore it is their main focus on support, not Linux or BSD.
After trying various things from forums all over I was about to just create another virtual disk, boot a rescue ISO and just image the original disk to the new one. Then and swap around the vhdx files and boot on the new one but that’s a lot of work if it needs to be done weekly or monthly. I was determined to find a better way, and I did.
To save yourself some trouble don’t waste time with systemrescuecd with zerofree under this configuration as it did not recognize the keyboard at all on the VM. I also tried creating another VM with no disks and mounting a copy of the VHDX file, Gen 1 and 2 with no positive results.
Since these VM’s had logical volumes I needed to check out the following 3 files:
discard_granularity and discard_max_bytes were both greater than zero so that means that it can discard within the VM. Check out the documentation on kernel.org for further understanding.
discard_zeroes_data is set to 0 which I had the feeling that it would be since Hyper-V 2012 R2 as well as 2016 do not support TRIM passthrough to Linux VM’s.
Here’s the solution
You have to fill the virtual disk with zeros using the following command tailored to your requirements.
dd if=/dev/zero of=/home/zerofile.000 bs=1M count=430080
This is writing a file to /home/zerofile.000 zeroing out the space in blocks of 1MB at a time so it can take a while depending on your hardware and size of thinly provisioned disk.
If you are paranoid about having the system lockup if it’s always busy just calculate a comfortable percentage that you would fill your disk to e.g. 80% calculate that out and define the count number to that. If you want to fully fill then just remove the count= option and it will write until it’s full.
Once the file is created then delete the file and shutdown the VM.
Then compact the VHDX file and you are good to go! Finally turn the VM back on and it will boot back up and you will see the free space from the hypervisor. This is extremely important if you are using any block level backup or disaster recovery programs or appliances since it will consume a master backup of the vhdx file(s).