Skip to content

Instantly share code, notes, and snippets.

@stoneage7
Last active February 20, 2024 21:00
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save stoneage7/9df39cfac2c28932ed86 to your computer and use it in GitHub Desktop.
Save stoneage7/9df39cfac2c28932ed86 to your computer and use it in GitHub Desktop.
Automatically shrinking VDI images under VirtualBox

Motivation

The purpose of this gist is to set up a virtual machine in such a way that the on-disk image in the host machine automatically grows and shrinks as needed by the guest machine. This utilizes the (still undocumented) "--discard" and "--nonrotational" parameters in "VBoxManage storageattach" which make the attached image appear as an SSD to the guest. Guest OS will then issue TRIM commands to the virtual controller where such an image is attached. VirtualBox is then able to capture the commands and punch holes in the attached VDIs.

Although there is some initial setup needed, I think the time saved with babysitting the VDIs is worth it. Usually you would need to zero out the free space with zerofree or sdelete and then run "VBoxManage --compact" on your images. With this setup you can allocate a large dynamic VDI (1TB or so) and it will keep itself at minimum size for easy syncing, backup, etc. You can also set it up in a template machine if you use one for clones etc.

Requirements

  • Linux (TODO: btrfs / ext4 only?) or Windows 8.1 (7 doesn't work)
  • (TODO: windows 10?)
  • dynamically-sized VDI type disk and SATA type controller (TODO: support for others?)
  • backup of important data
  • tested on VirtualBox 4.3.* only

Set up

Linux

  • In host go to Settings -> Storage

  • Select your attached image and at the bottom select "Remove the attachment highlighted..."

  • Open a command prompt in the directory where your virtual machine is saved

  • Run (replacing machine name, VDI file name, and if you have more than one image attached to the controller, device and port):

      "C:\Program Files\Oracle\VirtualBox\VBoxManage" storageattach "[GuestOsMachineName]" --storagectl "SATA" --port 1 --device 0 --nonrotational on --discard on --medium "[file.vdi]" --type hdd
    
  • Boot your guest OS and add "discard" flag to your fstab (or systemd's .mount unit if you have it set up that way) if needed.

  • If the constant TRIM-ming takes too much power off your computer, mount the filesystems with nodiscard and set up a regular cron job (or systemd .timer unit) to run "fstrim /" (point it at the image's mount point)

Windows 8.1

I never had success using a discard-enabled filesystem under Windows as a guest. You may try to use the same steps as in Linux but my machine starts choking after the image grows above ~6GB in size. This is a way that works for me (tm):

  • In Windows guest, start up an admin prompt and disable TRIM completely using the following command.

      fsutil behavior set disabledeletenotify 1
    
  • Shut down the guest

  • In host machine open a command prompt in the directory where your virtual machine is saved

  • Run (replacing machine name, VDI file name, and if you have more than one image attached to the controller, device and port):

      "C:\Program Files\Oracle\VirtualBox\VBoxManage" storageattach "[GuestOsMachineName]" --storagectl "SATA" --port 1 --device 0 --nonrotational on --discard on --medium "[file.vdi]" --type hdd
    
  • Now boot back your guest machine and create a .bat file like this:

      fsutil behavior set disabledeletenotify 0
      defrag /L C:
      fsutil behavior set disabledeletenotify 1
    
  • Note that this needs to run with Admin privileges

  • Optionally set up a task in task scheduler (under Administrative Tools -> Task Scheduler) to run it regularly.

In conclusion

The VDIs themselves are organized in 1MB blocks, so this will only work if the space being TRIM-med is at least a 1MB contiguous block at a 1MB boundary. Occasional defrag (with "defrag.exe /D" under Windows or "btrfs filesystem defrag" under Linux) in the background may be beneficial. VirtualBox will only trim whole 1MB blocks.

@intelfx
Copy link

intelfx commented Feb 28, 2017

Why exactly do you say that "Windows 7 doesn't work"?

In my tests, Windows 7 recognizes a discard-enabled medium and indeed does try to send TRIMs at least at defrag time, but crashes with 0x000000F4 very often. Do you see this too, or do you have some another failure mode?

@obliquid
Copy link

I tried this tutorial: everything went fine, vdi shrinked, till I rebooted the vm after some days with the discard/trim enabled: during reboot of the vm the vdi get corrupted, and completely unusable nor recoverable. My virtualbox is 4.3.40 on ubuntu server host, and the guest was ubuntu server also.
Anyone faced the same problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment