runtime: qemu: Add reclaim_guest_freed_memory [BACKPORT]

Similar to what we've done for Cloud Hypervisor in the commit
9f76467cb7, we're backporting a runtime-rs
feature that would be benificial to have as part of the go runtime.

This allows users to use virito-balloon for the hypervisor to reclaim
memory freed by the guest.

Signed-off-by: Fabiano Fidêncio <fidencio@northflank.com>
This commit is contained in:
Fabiano Fidêncio
2025-08-22 16:10:25 +02:00
parent e396a460bc
commit fd1b8ceed1
15 changed files with 149 additions and 8 deletions

View File

@@ -139,6 +139,7 @@ const (
scsiControllerID = "scsi0"
rngID = "rng0"
fallbackFileBackedMemDir = "/dev/shm"
balloonID = "balloon0"
qemuStopSandboxTimeoutSecs = 15
@@ -632,6 +633,9 @@ func (q *qemu) prepareInitdataMount(config *HypervisorConfig) error {
}
// CreateVM is the Hypervisor VM creation implementation for govmmQemu.
// This function is complex and there's not much to be done about it, unfortunately.
//
//nolint:gocyclo
func (q *qemu) CreateVM(ctx context.Context, id string, network Network, hypervisorConfig *HypervisorConfig) error {
// Save the tracing context
q.ctx = ctx
@@ -801,6 +805,20 @@ func (q *qemu) CreateVM(ctx context.Context, id string, network Network, hypervi
}
}
if q.config.ReclaimGuestFreedMemory && !q.config.ConfidentialGuest {
balloonDev := config.BalloonDev{
ID: balloonID,
DeflateOnOOM: true,
DisableModern: false,
FreePageReporting: true,
}
qemuConfig.Devices, err = q.arch.appendBalloonDevice(ctx, qemuConfig.Devices, balloonDev)
if err != nil {
return err
}
}
if machine.Type == QemuQ35 || machine.Type == QemuVirt {
if err := q.createPCIeTopology(&qemuConfig, hypervisorConfig, machine.Type, network); err != nil {
q.Logger().WithError(err).Errorf("Cannot create PCIe topology")

View File

@@ -116,6 +116,9 @@ type qemuArch interface {
// appendRNGDevice appends a RNG device to devices
appendRNGDevice(ctx context.Context, devices []govmmQemu.Device, rngDevice config.RNGDev) ([]govmmQemu.Device, error)
// appendBalloonDevice appends a Balloon device to devices
appendBalloonDevice(ctx context.Context, devices []govmmQemu.Device, BalloonDevice config.BalloonDev) ([]govmmQemu.Device, error)
// setEndpointDevicePath sets the appropriate PCI or CCW device path for an endpoint
setEndpointDevicePath(endpoint Endpoint, bridgeAddr int, devAddr string) error
@@ -738,6 +741,19 @@ func (q *qemuArchBase) appendRNGDevice(_ context.Context, devices []govmmQemu.De
return devices, nil
}
func (q *qemuArchBase) appendBalloonDevice(_ context.Context, devices []govmmQemu.Device, balloonDev config.BalloonDev) ([]govmmQemu.Device, error) {
devices = append(devices,
govmmQemu.BalloonDevice{
ID: balloonDev.ID,
DeflateOnOOM: balloonDev.DeflateOnOOM,
DisableModern: balloonDev.DisableModern,
FreePageReporting: balloonDev.FreePageReporting,
},
)
return devices, nil
}
func (q *qemuArchBase) setEndpointDevicePath(endpoint Endpoint, bridgeAddr int, devAddr string) error {
bridgeSlot, err := types.PciSlotFromInt(bridgeAddr)
if err != nil {