balloon

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2026 License: BSD-3-Clause Imports: 2 Imported by: 0

README

go-virtio/balloon

Pure-Go virtio-balloon (memory balloon) driver targeting the go-virtio/common transport interfaces. Implements the modern-transport (Virtio 1.0+) init sequence and the two-virtqueue page-transfer path for the standard PCI-bound virtio-balloon device (VID 0x1AF4, DID 0x1045).

virtio-balloon (Virtio 1.1 §5.5) lets the host reclaim guest RAM on demand. "Inflating" the balloon hands guest pages back to the host (shrinking the guest's effective memory); "deflating" reclaims them. The device-config num_pages field is the host's desired balloon size in 4096-byte pages.

This package owns the spec-level driver (the feature-acceptance mask, the init sequence per Virtio 1.1 §3.1.1, the inflate/deflate state machine, and the on-the-wire page-frame-number array format) and routes every transport-level operation through go-virtio/common's Transport interface. Drop in any implementation of that interface (UEFI's EFI_PCI_IO_PROTOCOL, bare-metal MMIO, virtio-mmio adapter) and the same driver code drives the device.

Only VIRTIO_F_VERSION_1 is negotiated — in particular VIRTIO_BALLOON_F_STATS_VQ is not negotiated, so the device exposes exactly two queues (inflateq = 0, deflateq = 1) and there is no stats queue.

Quick start

import (
    virtioballoon "github.com/go-virtio/balloon"
)

// transport is any value that implements go-virtio/common.Transport.
vb, err := virtioballoon.OpenVirtioBalloon(transport)
if err != nil {
    return err
}

// vb.NumPages is the host's desired balloon size (in 4096-byte pages),
// read from device config. Inflate toward it, deflate away from it.
if err := vb.Inflate(64); err != nil { // hand 64 pages to the host
    return err
}
if err := vb.Deflate(32); err != nil { // reclaim 32 of them
    return err
}
// vb.Actual now tracks the driver-side current balloon size.

OpenVirtioBalloon leaves the device in DRIVER_OK state with both page-transfer queues ready. A request packs an array of le32 page frame numbers (phys >> 12) into a single device-readable DMA buffer (at most 256 PFNs per buffer; larger requests are chunked), posts it to inflateq or deflateq, rings the doorbell, and busy-polls the used ring.

Limitation: actual is tracked driver-side only

The spec asks the driver to write the current balloon size back to the device-config actual field (Virtio 1.1 §5.5.6.1). common.ModernConfig exposes only DeviceCfgRead* (no device-config write path), so this driver cannot perform that write. The current balloon size is tracked in the Actual field instead. This is an intentional, noted limitation.

Sibling packages

License

BSD-3-Clause. See LICENSE.

Documentation

Overview

Package balloon is a pure-Go virtio-balloon (memory balloon) driver. It drives a modern (Virtio 1.0+) PCI virtio-balloon device through the transport interfaces defined in github.com/go-virtio/common; the same code drives a UEFI-backed device, a bare-metal device, or a virtio-mmio device depending on which common.Transport implementation the caller supplies.

Scope — like go-virtio/blk this package owns device bring-up, the two page-transfer virtqueues (inflateq + deflateq), and the on-the-wire page-frame-number (PFN) array format (Virtio 1.1 §5.5.6), exposing an Inflate / Deflate API. "Inflating" the balloon hands guest pages back to the host (shrinking the guest's effective RAM); "deflating" reclaims them. The device-config `num_pages` field is the host's desired balloon size in 4096-byte pages.

  • Modern transport (VIRTIO_F_VERSION_1 mandatory). Legacy devices are rejected by the common init sequence.
  • Only VIRTIO_F_VERSION_1 is negotiated — in particular VIRTIO_BALLOON_F_STATS_VQ is NOT negotiated, so the device exposes exactly two queues (inflateq, deflateq) and there is no stats queue.
  • A request posts an array of le32 PFNs in a single DMA buffer to inflateq (or deflateq), device-readable (the host reads the PFN list), then rings the doorbell and busy-polls the used ring. Each buffer carries at most MaxPFNsPerBuffer (256) PFNs; larger requests are split into multiple buffers.

Limitation — the driver does NOT write the `actual` field back to device config. common.ModernConfig exposes only DeviceCfgRead* (no device-config write path), so the spec's "tell the device the current balloon size" step (Virtio 1.1 §5.5.6.1) cannot be performed through this transport. The current balloon size is tracked driver-side in the Actual field instead. This is an intentional, noted limitation.

References:

  • Virtio 1.1 §5.5 "Memory Balloon Device" — device-type 5 binding.
  • Virtio 1.1 §5.5.5 "Device configuration layout" — le32 num_pages, le32 actual.
  • Virtio 1.1 §5.5.6 "Device Operation" — inflate/deflate PFN arrays.
  • Virtio 1.1 §3.1.1 "Device Initialization".

Index

Constants

View Source
const (
	InflateQueueIdx uint16 = 0
	DeflateQueueIdx uint16 = 1
)

InflateQueueIdx and DeflateQueueIdx are the two virtqueue indices the driver uses (Virtio 1.1 §5.5.2): inflateq = 0, deflateq = 1.

View Source
const AcceptedFeatures uint64 = common.FeatureVersion1

AcceptedFeatures is the feature mask the driver negotiates ON — only the non-negotiable VIRTIO_F_VERSION_1. (VIRTIO_BALLOON_F_STATS_VQ is deliberately NOT accepted, so no stats queue exists.)

View Source
const DeviceType uint16 = 5

DeviceType is the virtio device-type encoding for virtio-balloon (Virtio 1.1 §5.5.1).

View Source
const MaxPFNsPerBuffer = 256

MaxPFNsPerBuffer is the maximum number of le32 PFNs the driver packs into a single DMA buffer before posting it. Requests larger than this are split into multiple buffers. 256 PFNs = 1024 bytes, well within a single 4 KiB page.

View Source
const PFNShift = 12

PFNShift is VIRTIO_BALLOON_PFN_SHIFT (Virtio 1.1 §5.5.6): a page frame number is a physical address shifted right by 12 (the balloon always works in 4096-byte units regardless of the host page size).

View Source
const PFNSize = 4

PFNSize is the on-the-wire size of one page frame number — a le32 (Virtio 1.1 §5.5.6).

View Source
const QueueSize uint16 = 16

QueueSize is the desired ring size for each page-transfer queue (clamped + rounded during setup). One request occupies a single descriptor, so this bounds the number of in-flight buffers; the driver issues them one at a time.

View Source
const TxPollIterations = 200000

TxPollIterations is the default busy-poll budget for one posted buffer.

Variables

View Source
var (
	ErrNotModernDevice   = commonBalloonError("go-virtio/balloon: device doesn't offer VIRTIO_F_VERSION_1 (legacy-only)")
	ErrFeaturesNotOK     = commonBalloonError("go-virtio/balloon: FEATURES_OK status bit didn't stick after DriverFeature write")
	ErrInitWrongDeviceID = commonBalloonError("go-virtio/balloon: PCI device ID is not 0x1045 (modern balloon device)")
	ErrQueueNotAvailable = commonBalloonError("go-virtio/balloon: device reports QueueSize=0 for a page-transfer queue")
	ErrRequestTimeout    = commonBalloonError("go-virtio/balloon: request poll timeout (device did not consume the PFN buffer)")
	ErrZeroPages         = commonBalloonError("go-virtio/balloon: page count must be positive")
	ErrDeflateTooMany    = commonBalloonError("go-virtio/balloon: deflate count exceeds the number of held (ballooned) pages")
)

Sentinel errors for the virtio-balloon path.

Functions

func AcceptFeatures

func AcceptFeatures(deviceFeatures uint64) (uint64, error)

AcceptFeatures returns the negotiated mask (requires VERSION_1).

Types

type VirtioBalloon

type VirtioBalloon struct {
	// Cfg is the modern-transport handle.
	Cfg *common.ModernConfig

	// NumPages is the host's desired balloon size in 4096-byte pages,
	// read from DeviceCfg `num_pages` at OpenVirtioBalloon. It is the
	// last-read target; callers re-read it from device config to observe
	// changes.
	NumPages uint32

	// Actual is the driver-tracked current balloon size in pages. The
	// driver does NOT write this back to device config (the transport
	// exposes no device-config write path); it is maintained here as
	// Inflate/Deflate succeed. See the package doc's limitation note.
	Actual uint32

	// NegotiatedFeatures records the driver-feature handshake result.
	NegotiatedFeatures uint64
	// contains filtered or unexported fields
}

VirtioBalloon wraps one initialised virtio-balloon device.

func OpenVirtioBalloon

func OpenVirtioBalloon(t common.Transport) (*VirtioBalloon, error)

OpenVirtioBalloon drives the full bring-up of one virtio-balloon device:

  1. Verify the PCI device ID is 0x1045 (modern balloon).
  2. InitModernConfig walks PCI caps + populates the BAR locators.
  3. Reset → ACK → DRIVER status progression.
  4. Read DeviceFeature, require VERSION_1, mask, write DriverFeature.
  5. Set FEATURES_OK, verify it stuck.
  6. Allocate + publish inflateq (queue 0) then deflateq (queue 1).
  7. DRIVER_OK status.
  8. Read num_pages (le32) from DeviceCfg offset 0.

func (*VirtioBalloon) Deflate

func (v *VirtioBalloon) Deflate(nPages int) error

Deflate reclaims nPages previously-ballooned pages from the host, shrinking the balloon. It posts their page frame numbers to deflateq, drops them from the held set, and decreases Actual by nPages.

nPages must not exceed the number of pages currently held; otherwise ErrDeflateTooMany is returned.

func (*VirtioBalloon) DeflateQueue

func (v *VirtioBalloon) DeflateQueue() *common.Virtqueue

DeflateQueue exposes the deflate virtqueue handle for diagnostics.

func (*VirtioBalloon) Inflate

func (v *VirtioBalloon) Inflate(nPages int) error

Inflate hands nPages guest pages to the host, growing the balloon. It allocates nPages single-page DMA buffers, holds a reference to each so the GC cannot reclaim them while the host owns them, and posts their page frame numbers to inflateq in chunks of at most MaxPFNsPerBuffer. On success Actual is increased by nPages.

nPages must be positive; otherwise ErrZeroPages is returned.

func (*VirtioBalloon) InflateQueue

func (v *VirtioBalloon) InflateQueue() *common.Virtqueue

InflateQueue exposes the inflate virtqueue handle for diagnostics.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL