Setting the OS X kernel asynchronous I/O limits to avoid VirtualBox crashing OS X

I had the need to setup a new VM for software testing today, and I kept running into intermittent problems where VirtualBox would freeze and then an OS X kernel panic, freezing/crashing the entire machine.

Luckily, I had made a snapshot in the OS moments earlier to the crash so I had a safe place to revert to, but the crashes kept happing at seemingly random times.

I setup a looped execution of 'dmesg' to see what was going on just before the crash and saw this at the next freeze:

VBoxDrv: host_vmxon  -> vmx_use_count=1 rc=0
VBoxDrv: host_vmxoff -> vmx_use_count=0
VBoxDrv: host_vmxon  -> vmx_use_count=1 rc=0
aio_queue_async_request(): too many in flight for proc: 16.
aio_queue_async_request(): too many in flight for proc: 16.
aio_queue_async_request(): too many in flight for proc: 16.
aio_queue_async_request(): too many in flight for proc: 16.
aio_queue_async_request(): too many in flight for proc: 16.
aio_queue_async_request(): too many in flight for proc: 16.

The first VBoxDrv messages didn't pull anything interesting in Google, but the other messages did: Virtual Box ticket #11219 and this blog post.

It would appear that the default limits for the OS X kernel's asynchronous I/O are very, very low. VirtualBox likely exceeds them when your VM(s) are performing heavy disk I/O, hence the 'too many in flight' message in the logs.

Luckily for us, there's a quick and easy solution:

sudo sysctl -w  kern.aiomax=512 kern.aioprocmax=128 kern.aiothreads=16

then restart VirtualBox. These settings will apply until you reboot. To make the changes permanent, add/update the following lines in /etc/sysctl.conf:

Note: you can probably set those limits even higher, as documentation for Sybase (by SAP) recommends values 2048 / 1024 / 16 when using its software.


Attaching MBR or GPT disk partitions to a VirtualBox VM

On one of my development machines I triple-boot so that I can test in a variety of operating environments. My default is OS X and the other day I wanted to write documentation using DocBook. I knew that my Linux installation already had publican installed and ready to go (publican is a wonderful documentation tool written by Red Hat to facilitate the publishing of DocBook-based documentation) and I really did not want to setup a new Fedora VM that duplicated a setup I already had.

In reality, a new VM would not be all that much effort, but I though it would be really handy to know how to boot a VM up from a physical partition and this way I could kill two birds with one stone. After some research, it seemed using VMWare's VMDK (Virtual Machine Disk Format) images was the most appropriate, as the metadata could be tricked into pointing to physical partitions instead of files. Unfortunately, the tools VirtualBox provide to create them are not compatible with GPT disk tables out of the box. This blog post does mention a trick to convert the VMDK metadata to match the GPT disk layout, but it failed consistently when I tried.

I then, by fluke, found Dave Vasilevsky's vmdk-raw-parts script on GitHub which worked flawlessly! Its usage is well documented so I will not bore you with the details, but with that said after using it to create my custom VMDK, the only change required was to run chmod 666 /dev/diskXsY to grant my user write permissions to the disk (prevents you from having to start VirtualBox as root).

Some Extra Troubleshooting

These details are completely irrelevant to the above, but I wanted to mention them here for others wanting to run the same setup:

  • If you need USB pass-through, remember to set your VCPUs to 1; set it to anything higher and USB stops functioning.
  • You'll need to redo the 'chmod' when ever you reboot your machine, as the permissions on the dev node get reset upon boot.
  • During the trial-and-error process of getting this to work, I often needed to recreate my VMDK and reload it. VirtualBox will moan about mismatched UUIDs... The simple fix is to open File > Virtual Media Manager... to delete then re-add your VMDK file.