VMEM(9)

VMEM(9) | Kernel Developer's Manual | VMEM(9)

# NAME

`vmem` — virtual memory allocator

# SYNOPSIS

`#include <sys/vmem.h>`

vmem_t *
`vmem_create`(const char *name, vmem_addr_t base, vmem_size_t size, vmem_size_t quantum, int (*allocfn)(void *, vmem_size_t, vm_flag_t, vmem_addr_t *), void (*freefn)(void *, vmem_addr_t, vmem_size_t), void *arg, vmem_size_t qcache_max, vm_flag_t flags, int ipl);

vmem_t *
`vmem_xcreate`(const char *name, vmem_addr_t base, vmem_size_t size, vmem_size_t quantum, int (*allocfn)(void *, vmem_size_t, vmem_size_t *, vm_flag_t, vmem_addr_t *), void (*freefn)(void *, vmem_addr_t, vmem_size_t), void *arg, vmem_size_t qcache_max, vm_flag_t flags, int ipl);

int
`vmem_add`(vmem_t *vm, vmem_addr_t addr, vmem_size_t size, vm_flag_t flags);

int
`vmem_xalloc`(vmem_t *vm, vmem_size_t size, vmem_size_t align, vmem_size_t phase, vmem_size_t nocross, vmem_addr_t minaddr, vmem_addr_t maxaddr, vm_flag_t flags, vmem_addr_t *addrp);

int
`vmem_xalloc_addr`(vmem_t *vm, vmem_addr_t addr, vmem_size_t size, vm_flag_t flags);

void
`vmem_xfree`(vmem_t *vm, vmem_addr_t addr, vmem_size_t size);

void
`vmem_xfreeall`(vmem_t *vm);

int
`vmem_alloc`(vmem_t *vm, vmem_size_t size, vm_flag_t flags, vmem_addr_t *addrp);

void
`vmem_free`(vmem_t *vm, vmem_addr_t addr, vmem_size_t size);

void
`vmem_destroy`(vmem_t *vm);

# DESCRIPTION

The `vmem` is a general purpose resource allocator. Despite its name, it can be used for arbitrary resources other than virtual memory.

`vmem_create`() creates a new vmem arena.

name
  The string to describe the vmem.
base
  The start address of the initial span. Pass `0` if no initial span is required.
size
  The size of the initial span. Pass `0` if no initial span is required.
quantum
  The smallest unit of allocation.
allocfn
  The callback function used to import spans from the backend arena. Set both allocfn and freefn to `NULL` to disable automatic imports. `vmem` calls `(*allocfn)`(arg, size, flags, &addrp); to import a span of size at least size. allocfn must accept the same flags as `vmem_alloc`(). allocfn must return `ENOMEM` to indicate failure, or 0 on success. If allocfn succeeds, it must write the starting address of the imported span to addrp.
freefn
  The callback function used to free spans to the backend arena. freefn may be `NULL` even if allocfn is not `NULL`. `vmem` calls `(*freefn)`(arg, addr, size) to return to arg a span of size size, starting at addr, that was previously allocated by allocfn.
arg
  The backend arena. arg may be `NULL`. `vmem` passes arg as the first argument of allocfn and freefn.
qcache_max
  The largest size of allocations which can be served by quantum cache. It is merely a hint and can be ignored.
flags
  Either of:
  `VM_SLEEP`
    If the allocation cannot be satisfied immediately, sleep until enough resources are available.
  `VM_NOSLEEP`
    Don't sleep. Immediately return `NULL` if there are not enough resources available.
ipl
  Interrupt level to be blocked for allocating from vmem.

`vmem_xcreate`() creates a new vmem arena.

name
  The string to describe the vmem.
base
  The start address of the initial span. Pass `0` if no initial span is required.
size
  The size of the initial span. Pass `0` if no initial span is required.
quantum
  The smallest unit of allocation.
allocfn
  The callback function used to import spans from the backend arena. Set both allocfn and freefn to `NULL` to disable automatic imports. `vmem` calls `(*allocfn)`(arg, size, &actualsize, flags, &addrp); to import a span of size at least size. allocfn must accept the same flags as `vmem_alloc`(). allocfn must return `ENOMEM` to indicate failure, or 0 on success. If allocfn succeeds, it must write the actual size of the allocation to actualsize and the starting address of the imported span to addrp. The actual size will always be greater than or equal to the requested size.
freefn
  The callback function used to free spans to the backend arena. freefn may be `NULL` even if allocfn is not `NULL`. `vmem` calls `(*freefn)`(arg, addr, size) to return to arg a span of size size, starting at addr, that was previously allocated by allocfn.
arg
  The backend arena. arg may be `NULL`. `vmem` passes arg as the first argument of allocfn and freefn.
qcache_max
  The largest size of allocations which can be served by quantum cache. It is merely a hint and can be ignored.
flags
  Either of:
  `VM_SLEEP`
    If the allocation cannot be satisfied immediately, sleep until enough resources are available.
  `VM_NOSLEEP`
    Don't sleep. Immediately return `NULL` if there are not enough resources available.
ipl
  Interrupt level to be blocked for allocating from vmem.

`vmem_add`() adds a span of size size starting at addr to the arena. Returns 0 on success, `ENOMEM` on failure.

flags
  Either of:
  `VM_SLEEP`
    If the allocation cannot be satisfied immediately, sleep until enough resources are available.
  `VM_NOSLEEP`
    Don't sleep. Immediately return `ENOMEM` if there are not enough resources available.

`vmem_xalloc`() allocates a resource from the arena.

vm
  The arena which we allocate from.
size
  Specify the size of the allocation.
align
  If zero, don't care about the alignment of the allocation. Otherwise, request a resource segment starting at offset phase from an align aligned boundary.
phase
  See the above description of align. If align is zero, phase must be zero. Otherwise, phase must be smaller than align.
nocross
  Request a resource which doesn't cross nocross aligned boundary.
minaddr
  Specify the minimum address which can be allocated, or `VMEM_ADDR_MIN` if the caller does not care.
maxaddr
  Specify the maximum address which can be allocated, or `VMEM_ADDR_MAX` if the caller does not care.
flags
  A bitwise OR of an allocation strategy and a sleep flag.

  The allocation strategy must be one of:

  `VM_BESTFIT`
    Prefer space efficiency.
  `VM_INSTANTFIT`
    Prefer performance.

  The sleep flag must be one of:

  `VM_SLEEP`
    If the allocation cannot be satisfied immediately, sleep until enough resources are available.
  `VM_NOSLEEP`
    Don't sleep. Immediately return `ENOMEM` if there are not enough resources available.
addrp
  On success, if addrp is not `NULL`, `vmem_xalloc`() overwrites it with the start address of the allocated span.

`vmem_xalloc_addr`() allocates a specific address from the arena. The requested address must be aligned with the arena's quantum.

vm
  The arena which we allocate from.
addr
  The address to allocate.
size
  Specify the size of the allocation.
flags
  A sleep flag. Because a specific address is being allocated, any specified allocation strategy is ignored.

  The sleep flag must be one of:

  `VM_SLEEP`
    If the allocation cannot be satisfied immediately, sleep until the requested range can be allocated.
  `VM_NOSLEEP`
    Don't sleep. Immediately return `ENOMEM` if the requested range is not available.

`vmem_xfree`() frees resource allocated by `vmem_xalloc`() or `vmem_xalloc_addr`() to the arena.

vm
  The arena which we free to.
addr
  The resource being freed. It must have been allocated via `vmem_xalloc`() or `vmem_xalloc_addr`(). Notably, it must not have been allocated via `vmem_alloc`(), otherwise, the behaviour is undefined.
size
  The size of the resource being freed. It must be the same as the size argument used for `vmem_xalloc`() or `vmem_xalloc_addr`().

`vmem_xfreeall`() frees all resources that have been allocated by `vmem_xalloc`() to the arena.

vm
  The arena which we free to. Note that this function is may not be used on arenas where resources have been allocated using `vmem_alloc`() or arenas that have a quantum cache (i.e. were created with a non-zero qcache_max).

`vmem_alloc`() allocates a resource from the arena.

vm
  The arena which we allocate from.
size
  Specify the size of the allocation.
flags
  A bitwise OR of an allocation strategy and a sleep flag.

  The allocation strategy must be one of:

  `VM_BESTFIT`
    Prefer space efficiency.
  `VM_INSTANTFIT`
    Prefer performance.

  The sleep flag must be one of:

  `VM_SLEEP`
    If the allocation cannot be satisfied immediately, sleep until enough resources are available.
  `VM_NOSLEEP`
    Don't sleep. Immediately return `ENOMEM` if there are not enough resources available.
addrp
  On success, if addrp is not `NULL`, `vmem_alloc`() overwrites it with the start address of the allocated span.

`vmem_free`() frees resource allocated by `vmem_alloc`() to the arena.

vm
  The arena which we free to.
addr
  The resource being freed. It must have been allocated via `vmem_alloc`(). Notably, it must not have been allocated via `vmem_xalloc`() or `vmem_xalloc`(addr), otherwise, the behaviour is undefined.
size
  The size of the resource being freed. It must be the same as the size argument used for `vmem_alloc`().

`vmem_destroy`() destroys a vmem arena.

vm
  The vmem arena being destroyed. The caller must ensure that no one will use it anymore.

# RETURN VALUES

`vmem_create`() and `vmem_xcreate`() return a pointer to the newly allocated vmem_t on success, or `NULL` if `VM_NOSLEEP` was specified and memory could not be allocated immediately.

`vmem_add`() returns 0 on success, or `ENOMEM` if `VM_NOSLEEP` was specified and memory could not be allocated immediately to record the region.

`vmem_alloc`() and `vmem_xalloc`() return 0 on success, or `ENOMEM` if either:

- `VM_NOSLEEP` was specified and a matching region could not be allocated immediately; or
- non-default align, phase, or nocross parameters were specified, and a matching region could not be allocated without calling the backing allocfn passed to `vmem_create`().

# CODE REFERENCES

The `vmem` subsystem is implemented within the file sys/kern/subr_vmem.c.

# SEE ALSO

intro(9), kmem(9), memoryallocators(9), uvm(9)

Jeff Bonwick and Jonathan Adams, Magazines and Vmem: Extending the Slab Allocator to Many CPUs and Arbitrary Resources, 2001 USENIX Annual Technical Conference, 2001.

# AUTHORS

This implementation of `vmem` was written by YAMAMOTO Takashi.

# BUGS

`vmem` relies on malloc(9), pool(9), and RUN_ONCE(9), so it cannot be used as early during system bootstrap as extent(9).

`vmem` has no way to pass align, phase, nocross, minaddr, or maxaddr constraints into the backing allocator allocfn, so even if `VM_SLEEP` is specified, `vmem_alloc`() and `vmem_xalloc`() may spuriously fail immediately with align, phase, or nocross, or sleep forever with minaddr or maxaddr.

December 2, 2023 | NetBSD 11.0