uffdgraduate

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 8, 2026 License: MIT Imports: 8 Imported by: 0

README

UFFD Graduation

This controller detaches running VMs from the UFFD snapshot memory pager after they have been up for a while, so long-lived VMs stop depending on a pager (or on the snapshot backing their restore) and old pager versions can drain to zero and exit.

Why detach instead of migrate or fall back to file

A UFFD-backed VM is pinned to its pager session for the life of the restore. The memory backend (anonymous + userfaultfd vs. a private file mapping) is fixed when the VM is restored, so there is no way to move a running VM onto the file backend without restarting the VMM — which would drop its network connections.

What can be done without touching the VM is to let the pager finish its job: it populates every page that has not yet been faulted in from the backing file, then unregisters userfaultfd and closes the session. The guest never pauses and its network is untouched. The VM ends up running on resident memory with no pager dependency.

The cost is that the populated pages become resident anonymous memory (reclaimable only to swap, unlike clean file-backed pages), and completion reads the whole image once (already-resident pages are re-read from disk; only the copy is skipped). That is why graduation is paced and only applied to VMs that have already had a soak period.

What it does

On each scan the controller lists running VMs that still depend on a detachable pager, then graduates eligible ones subject to the configured limits:

  • a session must be at least min_session_age old (tracked in memory; a control plane restart restarts the soak, which is only more conservative), so min_session_age is effectively the maximum time a VM spends on the pager
  • at most max_concurrent graduations run at once
  • sessions bound to an outdated pager version are graduated first, so old pager versions retire quickly

Limits

  • The feature is disabled by default and only does anything when the host runs the uffd snapshot memory backend.
  • A failed graduation leaves the VM untouched (still on its pager); it is retried after a fixed backoff, since every attempt re-reads the whole image.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Enabled bool

	// MinSessionAge is how long a session must have been observed before it is
	// eligible to graduate. It gives the pager time to do its job as a restore
	// accelerator and avoids churning a freshly restored VM.
	MinSessionAge time.Duration

	// MaxConcurrent bounds simultaneous graduations. Each one reads the whole
	// memory image, so this is the IO/RAM blast-radius lever.
	MaxConcurrent int

	// ScanInterval is how often the controller evaluates sessions.
	ScanInterval time.Duration

	// CompletionTimeout bounds a single graduation. Completion reads the whole
	// remaining image, so this is generous.
	CompletionTimeout time.Duration
}

Config controls how aggressively the controller graduates VMs off the pager. The zero value is disabled, so the feature is a no-op until explicitly turned on.

func (Config) Normalize

func (c Config) Normalize() Config

Normalize fills in defaults for unset fields.

func (Config) Validate

func (c Config) Validate() error

Validate rejects nonsensical enabled configs.

type Controller

type Controller struct {
	// contains filtered or unexported fields
}

Controller periodically detaches running VMs that have soaked past MinSessionAge from their snapshot memory pager, so long-lived VMs stop depending on a pager and old pager versions drain to zero and exit.

func NewController

func NewController(store InstanceStore, cfg Config, opts ControllerOptions) *Controller

NewController builds a controller. cfg is normalized here.

func (*Controller) Run

func (c *Controller) Run(ctx context.Context) error

Run scans on an interval until ctx is cancelled.

type ControllerOptions

type ControllerOptions struct {
	Log   *slog.Logger
	Meter metric.Meter
	Now   func() time.Time
}

ControllerOptions configures logging, metrics, and time.

type Instance

type Instance struct {
	ID           string
	Name         string
	PagerVersion string
}

Instance is a running VM that currently depends on a detachable snapshot memory pager. PagerVersion is the version it is bound to.

type InstanceStore

type InstanceStore interface {
	// ListPagerInstances returns running instances that still depend on a
	// detachable snapshot memory pager, each tagged with its bound version.
	ListPagerInstances(ctx context.Context) ([]Instance, error)
	// GraduateInstance detaches the instance from its pager. The call blocks
	// until the pager has populated remaining pages and released the session.
	GraduateInstance(ctx context.Context, id string) error
	// TargetVersion is the pager version new restores bind to. Sessions on a
	// different version are prioritised so old pager versions can retire.
	TargetVersion() string
}

InstanceStore is the controller's view of the instance manager. It is kept narrow and free of hypervisor/UFFD types so the controller stays agnostic to how graduation is actually performed.

type Metrics

type Metrics struct {
	// contains filtered or unexported fields
}

Jump to

Keyboard shortcuts

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