This backports #931 and #935 to stable-1.19.x, together with the EFD_NONBLOCK fix from main (137f84bd) that the reclaim thread needs, and adds a 1.x C API to turn the reclaim on.
On macOS, madvise(MADV_FREE) doesn't release guest memory that the guest has written to, so free page reporting gives nothing back to the host. #931 and #935 fixed that on main only. 1.19.7 has neither, so released krunkit, and with it colima, Lima and podman machine, can't give guest memory back on macOS. In #931, a colima user reported an idle krunkit guest at 21.2 GB phys_footprint with 11.2 GB of its RAM free.
In 1.x, libkrun attaches the balloon itself, so applications have no way to pick the mode. This adds krun_set_balloon_free_page_reporting_mode(ctx_id, mode), which takes KRUN_FREE_PAGE_REPORTING_MODE_DEFAULT (the default, current behaviour) or KRUN_FREE_PAGE_REPORTING_MODE_REPLACE. These are the same values that krun_balloon_device_set_free_page_reporting_mode() takes in the 2.0 API. Nothing changes unless an application calls it with REPLACE; krunkit could then expose a flag for it. TEE builds, which have no balloon, return -ENOTSUP.
The commits, in order:
- utils/eventfd: 137f84bd from main, unchanged. Without it,
pollable_channel()'stry_recv()blocks on 1.19.x, and the new balloon tests hang (I checked by reverting it). - vmm: f24eca98 from main, and a backport of 221a0281. 1.x starts the VMM worker on macOS only when a GPU is configured; this starts it always, and it ends right away when no device keeps a sender.
- the macOS reclaim commits of #931 and slp's d494b231, adapted to the 1.x paths (src/vmm/), to
attach_balloon_device()instead ofBalloonDevice, and to the 1.xInterruptTransportin the tests. - libkrun: the new C API, which is 1.x only.
- the two commits of #935, without the Windows reclaimer.
Each adapted commit has a [backport: ...] note saying what changed. The device keeps the in-flight limit from main: at most 256 reports (the queue size) are reclaimed at a time.
Tested on an M4 Pro with macOS 26.5.1 and Rust 1.99.0. Every commit passes cargo fmt --check, cargo clippy --locked --features efi,gpu -- -D warnings (the macOS CI job), clippy with default features, and the krun-devices and libkrun unit tests. On the last commit, that's 22 balloon tests, including test_reports_in_flight_are_limited, and a new test of the C API. make BLK=1 NET=1 GPU=1 builds, and the dylib exports the new function. On Linux x86_64 (Rust 1.97.1), every commit passes clippy with default features, net,blk, amd-sev and tdx, and the krun-devices and libkrun unit tests. That machine has no /dev/kvm, so the krun-vmm tests that need KVM fail there, on stable-1.19.x as well.
Not tested: I haven't booted a guest with this branch, since the Mac I used runs other VMs and is short of memory. The reclaim code is the same as on main, where #931 was tested with a guest, and vetermanve tested a backport of #931 onto 1.19.6, with the EFD_NONBLOCK fix, under krunkit/colima (in #931). I also didn't run the Linux clippy job with gpu,snd,input, for lack of those libraries.
Thanks @JartX for testing this with krunkit and Colima (results). I've added your
Tested-byto my commits in the series (the code is unchanged; the tree is the same as f3fec24e, which you tested) and put your numbers in the description in place of the "Not tested" note.@slp, this is ready for review whenever you have time. Happy to rename the function or split it into the 1.x-only commits if you'd rather cherry-pick #931/#935 yourself.