pgalloc

package
v0.0.0-...-957f62e Latest Latest
Warning

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

Go to latest
Published: Nov 10, 2023 License: Apache-2.0, MIT Imports: 26 Imported by: 0

Documentation

Overview

Package pgalloc contains the page allocator subsystem, which manages memory that may be mapped into application address spaces.

Lock order:

 pgalloc.MemoryFile.mu
	pgalloc.MemoryFile.mappingsMu

Index

Constants

View Source
const (
	// CtxMemoryFile is a Context.Value key for a MemoryFile.
	CtxMemoryFile contextID = iota

	// CtxMemoryFileProvider is a Context.Value key for a MemoryFileProvider.
	CtxMemoryFileProvider

	// CtxMemoryCgroupID is the memory cgroup id which the task belongs to.
	CtxMemoryCgroupID
)

Variables

This section is empty.

Functions

func IMAWorkAroundForMemFile

func IMAWorkAroundForMemFile(fd uintptr)

IMAWorkAroundForMemFile works around IMA by immediately creating a temporary PROT_EXEC mapping, while the backing file is still small. IMA will ignore any future mappings.

The Linux kernel contains an optional feature called "Integrity Measurement Architecture" (IMA). If IMA is enabled, it will checksum binaries the first time they are mapped PROT_EXEC. This is bad news for executable pages mapped from our backing file, which can grow to terabytes in (sparse) size. If IMA attempts to checksum a file that large, it will allocate all of the sparse pages and quickly exhaust all memory.

func MemoryCgroupIDFromContext

func MemoryCgroupIDFromContext(ctx context.Context) uint32

MemoryCgroupIDFromContext returns the memory cgroup id of the ctx, or zero if the ctx does not belong to any memory cgroup.

Types

type AllocOpts

type AllocOpts struct {
	// Kind is the memory kind to be used for accounting.
	Kind usage.MemoryKind
	// Dir indicates the direction in which offsets are allocated.
	Dir Direction
	// MemCgID is the memory cgroup ID and the zero value indicates that
	// the memory will not be accounted to any cgroup.
	MemCgID uint32
	// Mode allows the callers to select how the pages are allocated in the
	// MemoryFile. Callers that will fill the allocated memory by writing to it
	// should pass AllocateAndWritePopulate to avoid faulting page-by-page. Callers
	// that will fill the allocated memory by invoking host system calls should
	// pass AllocateOnly.
	Mode AllocationMode
	// If Reader is provided, the allocated memory is filled by calling
	// ReadToBlocks() repeatedly until either length bytes are read or a non-nil
	// error is returned. It returns the allocated memory, truncated down to the
	// nearest page. If this is shorter than length bytes due to an error
	// returned by ReadToBlocks(), it returns the partially filled fr and error.
	Reader safemem.Reader
}

AllocOpts are options used in MemoryFile.Allocate.

type AllocationMode

type AllocationMode int

AllocationMode provides a way to inform the pgalloc API how to allocate memory and pages on the host. A page will exist in one of the following incremental states:

  1. Allocated: A page is allocated if it was returned by Allocate() and its reference count hasn't dropped to 0 since then.
  2. Committed: As described in MemoryFile documentation above, a page is committed if the host kernel is spending resources to store its contents. A committed page is implicitly allocated.
  3. Populated: A page is populated for reading/writing in a page table hierarchy if it has a page table entry that permits reading/writing respectively. A populated page is implicitly committed, since the page table entry needs a physical page to point to, but not vice versa.
const (
	// AllocateOnly indicates that pages need to only be allocated.
	AllocateOnly AllocationMode = iota
	// AllocateAndCommit indicates that pages need to be committed, in addition
	// to being allocated.
	AllocateAndCommit
	// AllocateAndWritePopulate indicates that writable pages should ideally be
	// populated in the page table, in addition to being allocated. This is a
	// suggestion, not a requirement.
	AllocateAndWritePopulate
)

type DelayedEvictionType

type DelayedEvictionType int

DelayedEvictionType is the type of MemoryFileOpts.DelayedEviction.

const (
	// DelayedEvictionDefault has unspecified behavior.
	DelayedEvictionDefault DelayedEvictionType = iota

	// DelayedEvictionDisabled requires that evictable allocations are evicted
	// as soon as possible.
	DelayedEvictionDisabled

	// DelayedEvictionEnabled requests that the MemoryFile delay eviction of
	// evictable allocations until doing so is considered necessary to avoid
	// performance degradation due to host memory pressure, or OOM kills.
	//
	// As of this writing, the behavior of DelayedEvictionEnabled depends on
	// whether or not MemoryFileOpts.UseHostMemcgPressure is enabled:
	//
	//	- If UseHostMemcgPressure is true, evictions are delayed until memory
	//		pressure is indicated.
	//
	//	- Otherwise, evictions are only delayed until the reclaimer goroutine
	//		is out of work (pages to reclaim).
	DelayedEvictionEnabled

	// DelayedEvictionManual requires that evictable allocations are only
	// evicted when MemoryFile.StartEvictions() is called. This is extremely
	// dangerous outside of tests.
	DelayedEvictionManual
)

type Direction

type Direction int

Direction describes how to allocate offsets from MemoryFile.

const (
	// BottomUp allocates offsets in increasing offsets.
	BottomUp Direction = iota
	// TopDown allocates offsets in decreasing offsets.
	TopDown
)

func (Direction) String

func (d Direction) String() string

String implements fmt.Stringer.

type EvictableMemoryUser

type EvictableMemoryUser interface {
	// Evict requests that the EvictableMemoryUser deallocate memory used by
	// er, which was registered as evictable by a previous call to
	// MemoryFile.MarkEvictable.
	//
	// Evict is not required to deallocate memory. In particular, since pgalloc
	// must call Evict without holding locks to avoid circular lock ordering,
	// it is possible that the passed range has already been marked as
	// unevictable by a racing call to MemoryFile.MarkUnevictable.
	// Implementations of EvictableMemoryUser must detect such races and handle
	// them by making Evict have no effect on unevictable ranges.
	//
	// After a call to Evict, the MemoryFile will consider the evicted range
	// unevictable (i.e. it will not call Evict on the same range again) until
	// informed otherwise by a subsequent call to MarkEvictable.
	Evict(ctx context.Context, er EvictableRange)
}

An EvictableMemoryUser represents a user of MemoryFile-allocated memory that may be asked to deallocate that memory in the presence of memory pressure.

type EvictableRange

type EvictableRange struct {
	// Start is the inclusive start of the range.
	Start uint64

	// End is the exclusive end of the range.
	End uint64
}

A Range represents a contiguous range of T.

+stateify savable

func (EvictableRange) CanSplitAt

func (r EvictableRange) CanSplitAt(x uint64) bool

CanSplitAt returns true if it is legal to split a segment spanning the range r at x; that is, splitting at x would produce two ranges, both of which have non-zero length.

func (EvictableRange) Contains

func (r EvictableRange) Contains(x uint64) bool

Contains returns true if r contains x.

func (EvictableRange) Intersect

Intersect returns a range consisting of the intersection between r and r2. If r and r2 do not overlap, Intersect returns a range with unspecified bounds, but for which Length() == 0.

func (EvictableRange) IsSupersetOf

func (r EvictableRange) IsSupersetOf(r2 EvictableRange) bool

IsSupersetOf returns true if r is a superset of r2; that is, the range r2 is contained within r.

func (EvictableRange) Length

func (r EvictableRange) Length() uint64

Length returns the length of the range.

func (EvictableRange) Overlaps

func (r EvictableRange) Overlaps(r2 EvictableRange) bool

Overlaps returns true if r and r2 overlap.

func (*EvictableRange) StateFields

func (r *EvictableRange) StateFields() []string

func (*EvictableRange) StateLoad

func (r *EvictableRange) StateLoad(stateSourceObject state.Source)

+checklocksignore

func (*EvictableRange) StateSave

func (r *EvictableRange) StateSave(stateSinkObject state.Sink)

+checklocksignore

func (*EvictableRange) StateTypeName

func (r *EvictableRange) StateTypeName() string

func (EvictableRange) WellFormed

func (r EvictableRange) WellFormed() bool

WellFormed returns true if r.Start <= r.End. All other methods on a Range require that the Range is well-formed.

type MemoryFile

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

MemoryFile is a memmap.File whose pages may be allocated to arbitrary users.

func MemoryFileFromContext

func MemoryFileFromContext(ctx context.Context) *MemoryFile

MemoryFileFromContext returns the MemoryFile used by ctx, or nil if no such MemoryFile exists.

func NewMemoryFile

func NewMemoryFile(file *os.File, opts MemoryFileOpts) (*MemoryFile, error)

NewMemoryFile creates a MemoryFile backed by the given file. If NewMemoryFile succeeds, ownership of file is transferred to the returned MemoryFile.

func (*MemoryFile) Allocate

func (f *MemoryFile) Allocate(length uint64, opts AllocOpts) (memmap.FileRange, error)

Allocate returns a range of initially-zeroed pages of the given length with the given accounting kind and a single reference held by the caller. When the last reference on an allocated page is released, ownership of the page is returned to the MemoryFile, allowing it to be returned by a future call to Allocate.

Preconditions: length must be page-aligned and non-zero.

func (*MemoryFile) DecRef

func (f *MemoryFile) DecRef(fr memmap.FileRange)

DecRef implements memmap.File.DecRef.

func (*MemoryFile) Decommit

func (f *MemoryFile) Decommit(fr memmap.FileRange) error

Decommit releases resources associated with maintaining the contents of the given pages. If Decommit succeeds, future accesses of the decommitted pages will read zeroes.

Preconditions: fr.Length() > 0.

func (*MemoryFile) Destroy

func (f *MemoryFile) Destroy()

Destroy releases all resources used by f.

Preconditions: All pages allocated by f have been freed.

Postconditions: None of f's methods may be called after Destroy.

func (*MemoryFile) FD

func (f *MemoryFile) FD() int

FD implements memmap.File.FD.

func (*MemoryFile) File

func (f *MemoryFile) File() *os.File

File returns the backing file.

func (*MemoryFile) IncRef

func (f *MemoryFile) IncRef(fr memmap.FileRange, memCgID uint32)

IncRef implements memmap.File.IncRef.

func (*MemoryFile) IsDiskBacked

func (f *MemoryFile) IsDiskBacked() bool

IsDiskBacked returns true if f is backed by a file on disk.

func (*MemoryFile) LoadFrom

func (f *MemoryFile) LoadFrom(ctx context.Context, r wire.Reader) error

LoadFrom loads MemoryFile state from the given stream.

func (*MemoryFile) MapInternal

func (f *MemoryFile) MapInternal(fr memmap.FileRange, at hostarch.AccessType) (safemem.BlockSeq, error)

MapInternal implements memmap.File.MapInternal.

func (*MemoryFile) MarkAllUnevictable

func (f *MemoryFile) MarkAllUnevictable(user EvictableMemoryUser)

MarkAllUnevictable informs f that user no longer considers any offsets to be evictable. It otherwise has the same semantics as MarkUnevictable.

func (*MemoryFile) MarkEvictable

func (f *MemoryFile) MarkEvictable(user EvictableMemoryUser, er EvictableRange)

MarkEvictable allows f to request memory deallocation by calling user.Evict(er) in the future.

Redundantly marking an already-evictable range as evictable has no effect.

func (*MemoryFile) MarkUnevictable

func (f *MemoryFile) MarkUnevictable(user EvictableMemoryUser, er EvictableRange)

MarkUnevictable informs f that user no longer considers er to be evictable, so the MemoryFile should no longer call user.Evict(er). Note that, per EvictableMemoryUser.Evict's documentation, user.Evict(er) may still be called even after MarkUnevictable returns due to race conditions, and implementations of EvictableMemoryUser must handle this possibility.

Redundantly marking an already-unevictable range as unevictable has no effect.

func (*MemoryFile) SaveTo

func (f *MemoryFile) SaveTo(ctx context.Context, w wire.Writer) error

SaveTo writes f's state to the given stream.

func (*MemoryFile) ShouldCacheEvictable

func (f *MemoryFile) ShouldCacheEvictable() bool

ShouldCacheEvictable returns true if f is meaningfully delaying evictions of evictable memory, such that it may be advantageous to cache data in evictable memory. The value returned by ShouldCacheEvictable may change between calls.

func (*MemoryFile) StartEvictions

func (f *MemoryFile) StartEvictions()

StartEvictions requests that f evict all evictable allocations. It does not wait for eviction to complete; for this, see MemoryFile.WaitForEvictions.

func (*MemoryFile) String

func (f *MemoryFile) String() string

String implements fmt.Stringer.String.

Note that because f.String locks f.mu, calling f.String internally (including indirectly through the fmt package) risks recursive locking. Within the pgalloc package, use f.usage directly instead.

func (*MemoryFile) TotalSize

func (f *MemoryFile) TotalSize() uint64

TotalSize returns the current size of the backing file in bytes, which is an upper bound on the amount of memory that can currently be allocated from the MemoryFile. The value returned by TotalSize is permitted to change.

func (*MemoryFile) TotalUsage

func (f *MemoryFile) TotalUsage() (uint64, error)

TotalUsage returns an aggregate usage for all memory statistics except Mapped (which is external to MemoryFile). This is generally much cheaper than UpdateUsage, but will not provide a fine-grained breakdown.

func (*MemoryFile) UpdateUsage

func (f *MemoryFile) UpdateUsage(memCgID uint32) error

UpdateUsage ensures that the memory usage statistics in usage.MemoryAccounting are up to date. If forceScan is true, the UsageScanDuration is ignored and the memory file is scanned to get the memory usage.

func (*MemoryFile) WaitForEvictions

func (f *MemoryFile) WaitForEvictions()

WaitForEvictions blocks until f is no longer evicting any evictable allocations.

type MemoryFileOpts

type MemoryFileOpts struct {
	// DelayedEviction controls the extent to which the MemoryFile may delay
	// eviction of evictable allocations.
	DelayedEviction DelayedEvictionType

	// If UseHostMemcgPressure is true, use host memory cgroup pressure level
	// notifications to determine when eviction is necessary. This option has
	// no effect unless DelayedEviction is DelayedEvictionEnabled.
	UseHostMemcgPressure bool

	// DecommitOnDestroy indicates whether the entire host file should be
	// decommitted on destruction. This is appropriate for host filesystem based
	// files that need to be explicitly cleaned up to release disk space.
	DecommitOnDestroy bool

	// If ManualZeroing is true, MemoryFile must not assume that new pages
	// obtained from the host are zero-filled, such that MemoryFile must manually
	// zero newly-allocated pages.
	ManualZeroing bool

	// If DisableIMAWorkAround is true, NewMemoryFile will not call
	// IMAWorkAroundForMemFile().
	DisableIMAWorkAround bool

	// DiskBackedFile indicates that the MemoryFile is backed by a file on disk.
	DiskBackedFile bool
}

MemoryFileOpts provides options to NewMemoryFile.

type MemoryFileProvider

type MemoryFileProvider interface {
	// MemoryFile returns the Kernel MemoryFile.
	MemoryFile() *MemoryFile
}

MemoryFileProvider provides the MemoryFile method.

This type exists to work around a save/restore defect. The only object in a saved object graph that S/R allows to be replaced at time of restore is the starting point of the restore, kernel.Kernel. However, the MemoryFile changes between save and restore as well, so objects that need persistent access to the MemoryFile must instead store a pointer to the Kernel and call Kernel.MemoryFile() as required. In most cases, depending on the kernel package directly would create a package dependency loop, so the stored pointer must instead be a MemoryProvider interface object. Correspondingly, kernel.Kernel is the only implementation of this interface.

func MemoryFileProviderFromContext

func MemoryFileProviderFromContext(ctx context.Context) MemoryFileProvider

MemoryFileProviderFromContext returns the MemoryFileProvider used by ctx, or nil if no such MemoryFileProvider exists.

Jump to

Keyboard shortcuts

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