uffdpager

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jun 12, 2026 License: MIT Imports: 27 Imported by: 0

README

UFFD Snapshot Pager

The UFFD pager lets Firecracker restore snapshot memory lazily. A restored VM gets a per-session UFFD socket, and page faults are served from the snapshot memory file by a local pager process.

The pager is local to the host. It is not backed by Redis or another external cache because page faults are latency-sensitive and the kernel-facing UFFD socket is local. The process keeps one shared in-memory page cache, bounded by hypervisor.firecracker_uffd_cache_max_bytes. Cache entries are keyed by a snapshot cache key plus page offset, so restore sessions with the same propagated snapshot cache key can reuse hot pages without starting one pager per snapshot.

UFFD is opt-in through hypervisor.firecracker_snapshot_memory_backend=uffd. The default backend remains file. Enabling UFFD does not change already running VMs; it only changes future Firecracker snapshot restores. If a restore uses UFFD, the VM is pinned to the pager session created for that restore until the instance stops, is deleted, or otherwise closes the session.

The pager version is declared in lib/uffdpager/VERSION. Installed Linux hosts run versioned systemd units named hypeman-uffd@<version>.service. Hypeman connects to the pager version from VERSION, so regular Hypeman releases do not start a new pager unless the UFFD pager version changes. Older pager versions are drained: they reject new sessions but continue serving existing sessions until those sessions close. Systemd runs the pager through the dedicated hypeman-uffd-pager binary rather than an alternate API-server mode. UFFD requires that systemd unit template to be installed; Hypeman does not launch an unmanaged pager subprocess if the template is missing.

Control HTTP API

Hypeman talks to the pager over Unix HTTP at <data_dir>/uffd/<version>/control.sock:

  • GET /health
  • GET /stats
  • POST /sessions
  • POST /sessions/{id}/close
  • POST /drain

Firecracker does not use this control socket directly. Each restore session gets its own Unix socket that receives Firecracker's UFFD file descriptor and memory regions.

The instance health check currently verifies that the pager version is healthy; it does not prove that a particular UFFD session still exists after an unplanned pager restart. If a pager disappears while serving active UFFD VMs, those VMs should be treated as unhealthy and recycled.

Documentation

Index

Constants

View Source
const (
	BackendFile = "file"
	BackendUFFD = "uffd"
)

Variables

This section is empty.

Functions

func Main

func Main(args []string) error

func Version

func Version() string

Types

type CreateSessionRequest

type CreateSessionRequest struct {
	SessionID         string `json:"session_id,omitempty"`
	InstanceID        string `json:"instance_id"`
	BackingMemoryPath string `json:"backing_memory_path"`
	CacheKey          string `json:"cache_key"`
}

CreateSessionRequest describes one Firecracker UFFD restore session.

type CreateSessionResponse

type CreateSessionResponse struct {
	SessionID      string `json:"session_id"`
	UFFDSocketPath string `json:"uffd_socket_path"`
	PagerVersion   string `json:"pager_version"`
}

CreateSessionResponse returns the per-session socket Firecracker should use as mem_backend.backend_path.

type HealthResponse

type HealthResponse struct {
	Version        string `json:"version"`
	Draining       bool   `json:"draining"`
	ActiveSessions int    `json:"active_sessions"`
}

type PageCache

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

func NewPageCache

func NewPageCache(maxBytes int64) *PageCache

func (*PageCache) Add

func (c *PageCache) Add(cacheKey string, offset int64, data []byte)

func (*PageCache) Borrow

func (c *PageCache) Borrow(cacheKey string, offset int64, size int) ([]byte, bool)

Borrow returns the immutable cached page without copying or touching LRU state.

func (*PageCache) Get

func (c *PageCache) Get(cacheKey string, offset int64, size int) ([]byte, bool)

func (*PageCache) SnapshotStats

func (c *PageCache) SnapshotStats() (bytes, maxBytes int64, items int, hits, misses int64)

func (*PageCache) SnapshotTimingStats

func (c *PageCache) SnapshotTimingStats() (shards int, lookupNanos, lookupMaxNanos, addNanos, addMaxNanos int64)

type Stats

type Stats struct {
	Version        string `json:"version"`
	Draining       bool   `json:"draining"`
	ActiveSessions int    `json:"active_sessions"`

	CacheBytes          int64 `json:"cache_bytes"`
	CacheMax            int64 `json:"cache_max"`
	CacheItems          int   `json:"cache_items"`
	CacheHits           int64 `json:"cache_hits"`
	CacheMisses         int64 `json:"cache_misses"`
	CacheShards         int   `json:"cache_shards"`
	CacheLookupNanos    int64 `json:"cache_lookup_nanos"`
	CacheLookupMaxNanos int64 `json:"cache_lookup_max_nanos"`
	CacheAddNanos       int64 `json:"cache_add_nanos"`
	CacheAddMaxNanos    int64 `json:"cache_add_max_nanos"`

	Faults           int64 `json:"faults"`
	BackingBytesRead int64 `json:"backing_bytes_read"`
	Copies           int64 `json:"copies"`
	CopyErrors       int64 `json:"copy_errors"`

	ActiveFaults        int64 `json:"active_faults"`
	MaxConcurrentFaults int64 `json:"max_concurrent_faults"`
	FaultNanos          int64 `json:"fault_nanos"`
	FaultMaxNanos       int64 `json:"fault_max_nanos"`
	ReadPageNanos       int64 `json:"read_page_nanos"`
	ReadPageMaxNanos    int64 `json:"read_page_max_nanos"`
	BackingReadNanos    int64 `json:"backing_read_nanos"`
	BackingReadMaxNanos int64 `json:"backing_read_max_nanos"`
	CopyNanos           int64 `json:"copy_nanos"`
	CopyMaxNanos        int64 `json:"copy_max_nanos"`
}

type Supervisor

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

func NewSupervisor

func NewSupervisor(ctx context.Context, dataDir string, cacheMaxBytes int64) (*Supervisor, error)

func (*Supervisor) CloseSession

func (s *Supervisor) CloseSession(ctx context.Context, sessionID string) error

func (*Supervisor) CloseSessionVersion

func (s *Supervisor) CloseSessionVersion(ctx context.Context, versionKey, sessionID string) error

func (*Supervisor) CreateSession

func (*Supervisor) HealthVersion

func (s *Supervisor) HealthVersion(ctx context.Context, versionKey string) (*HealthResponse, error)

func (*Supervisor) Stats

func (s *Supervisor) Stats(ctx context.Context) (*Stats, error)

func (*Supervisor) VersionKey

func (s *Supervisor) VersionKey() string

Jump to

Keyboard shortcuts

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