UMA(9) | Kernel Developer's Manual | UMA(9) |
UMA
—
general-purpose kernel object allocator
#include
<sys/param.h>
#include <sys/queue.h>
#include <vm/uma.h>
options UMA_FIRSTTOUCH
options UMA_XDOMAIN
typedef int (*uma_ctor)(void *mem, int size, void *arg, int flags); typedef void (*uma_dtor)(void *mem, int size, void *arg); typedef int (*uma_init)(void *mem, int size, int flags); typedef void (*uma_fini)(void *mem, int size); typedef int (*uma_import)(void *arg, void **store, int count, int domain, int flags); typedef void (*uma_release)(void *arg, void **store, int count); typedef void *(*uma_alloc)(uma_zone_t zone, vm_size_t size, int domain, uint8_t *pflag, int wait); typedef void (*uma_free)(void *item, vm_size_t size, uint8_t pflag);
uma_zcreate
(char *name,
int size, uma_ctor ctor,
uma_dtor dtor, uma_init zinit,
uma_fini zfini, int align,
uint16_t flags);
uma_zone_t
uma_zcache_create
(char *name,
int size, uma_ctor ctor,
uma_dtor dtor, uma_init zinit,
uma_fini zfini, uma_import
zimport, uma_release zrelease,
void *arg, int flags);
uma_zone_t
uma_zsecond_create
(char *name,
uma_ctor ctor, uma_dtor dtor,
uma_init zinit, uma_fini zfini,
uma_zone_t master);
void
uma_zdestroy
(uma_zone_t
zone);
void *
uma_zalloc
(uma_zone_t
zone, int
flags);
void *
uma_zalloc_arg
(uma_zone_t
zone, void *arg,
int flags);
void *
uma_zalloc_domain
(uma_zone_t
zone, void *arg,
int domain,
int flags);
void *
uma_zalloc_pcpu
(uma_zone_t
zone, int
flags);
void *
uma_zalloc_pcpu_arg
(uma_zone_t
zone, void *arg,
int flags);
void
uma_zfree
(uma_zone_t
zone, void
*item);
void
uma_zfree_arg
(uma_zone_t
zone, void *item,
void *arg);
void
uma_zfree_domain
(uma_zone_t
zone, void *item,
void *arg);
void
uma_zfree_pcpu
(uma_zone_t
zone, void
*item);
void
uma_zfree_pcpu_arg
(uma_zone_t
zone, void *item,
void *arg);
void
uma_prealloc
(uma_zone_t
zone, int
nitems);
void
uma_zone_reserve
(uma_zone_t
zone, int
nitems);
void
uma_zone_reserve_kva
(uma_zone_t
zone, int
nitems);
void
uma_zone_set_allocf
(uma_zone_t
zone, uma_alloc
allocf);
void
uma_zone_set_freef
(uma_zone_t
zone, uma_free
freef);
int
uma_zone_set_max
(uma_zone_t
zone, int
nitems);
int
uma_zone_set_maxcache
(uma_zone_t
zone, int
nitems);
int
uma_zone_get_max
(uma_zone_t
zone);
int
uma_zone_get_cur
(uma_zone_t
zone);
void
uma_zone_set_warning
(uma_zone_t
zone, const char
*warning);
void
uma_zone_set_maxaction
(uma_zone_t
zone, void
(*maxaction)(uma_zone_t));
void
uma_reclaim
();
#include
<sys/sysctl.h>
SYSCTL_UMA_MAX
(parent,
nbr,
name,
access,
zone,
descr);
SYSCTL_ADD_UMA_MAX
(ctx,
parent,
nbr,
name,
access,
zone,
descr);
SYSCTL_UMA_CUR
(parent,
nbr,
name,
access,
zone,
descr);
SYSCTL_ADD_UMA_CUR
(ctx,
parent,
nbr,
name,
access,
zone,
descr);
UMA (Universal Memory Allocator) provides an efficient interface for managing dynamically-sized collections of items of identical size, referred to as zones. Zones keep track of which items are in use and which are not, and UMA provides functions for allocating items from a zone and for releasing them back, making them available for subsequent allocation requests. Zones maintain per-CPU caches with linear scalability on SMP systems as well as round-robin and first-touch policies for NUMA systems. The number of items cached per CPU is bounded, and each zone additionally maintains an unbounded cache of items that is used to quickly satisfy per-CPU cache allocation misses.
Two types of zones exist: regular zones and cache zones. In a regular zone, items are allocated from a slab, which is one or more virtually contiguous memory pages that have been allocated from the kernel's page allocator. Internally, slabs are managed by a UMA keg, which is responsible for allocating slabs and keeping track of their usage by one or more zones. In typical usage, there is one keg per zone, so slabs are not shared among multiple zones.
Normal zones import items from a keg, and release items back to that keg if requested. Cache zones do not have a keg, and instead use custom import and release methods. For example, some collections of kernel objects are statically allocated at boot-time, and the size of the collection does not change. A cache zone can be used to implement an efficient allocator for the objects in such a collection.
The
uma_zcreate
()
and uma_zcache_create
() functions create a new
regular zone and cache zone, respectively. The
uma_zsecond_create
()
function creates a regular zone which shares the keg of the zone specified
by the master argument. The name
argument is a text name of the zone for debugging and stats; this memory
should not be freed until the zone has been deallocated.
The ctor and
dtor arguments are callback functions that are called
by the UMA subsystem at the time of the call to
uma_zalloc
()
and uma_zfree
() respectively. Their purpose is to
provide hooks for initializing or destroying things that need to be done at
the time of the allocation or release of a resource. A good usage for the
ctor and dtor callbacks might be
to initialize a data structure embedded in the item, such as a
queue(3) head.
The zinit and
zfini arguments are used to optimize the allocation of
items from the zone. They are called by the UMA subsystem whenever it needs
to allocate or free items to satisfy requests or memory pressure. A good use
for the zinit and zfini
callbacks might be to initialize and destroy a mutex contained within an
item. This would allow one to avoid destroying and re-initializing the mutex
each time the item is freed and re-allocated. They are not called on each
call to
uma_zalloc
()
and uma_zfree
() but rather when an item is imported
into a zone's cache, and when a zone releases an item to the slab allocator,
typically as a response to memory pressure.
For
uma_zcache_create
(),
the zimport and zrelease
functions are called to import items into the zone and to release items from
the zone, respectively. The zimport function should
store pointers to items in the store array, which
contains a maximum of count entries. The function must
return the number of imported items, which may be less than the maximum.
Similarly, the store parameter to the
zrelease function contains an array of
count pointers to items. The arg
parameter passed to uma_zcache_create
() is provided
to the import and release functions. The domain
parameter to zimport specifies the requested
numa(4) domain for the allocation. It is either a NUMA
domain number or the special value
UMA_ANYDOMAIN
.
The flags argument of
uma_zcreate
()
and uma_zcache_create
() is a subset of the following
flags:
UMA_ZONE_NOFREE
UMA_ZONE_NODUMP
UMA_ZONE_PCPU
sizeof
(struct
pcpu):
foo_zone = uma_zcreate(..., UMA_ZONE_PCPU); ... foo_base = uma_zalloc(foo_zone, ...); ... critical_enter(); foo_pcpu = (foo_t *)zpcpu_get(foo_base); /* do something with foo_pcpu */ critical_exit();
M_ZERO
cannot be used when allocating
items from a PCPU zone. To obtain zeroed memory from a PCPU zone, use the
uma_zalloc_pcpu
()
function and its variants instead, and pass
M_ZERO
.UMA_ZONE_OFFPAGE
UMA_ZONE_VTOSLAB
or
UMA_ZONE_HASH
, since subsystem requires a
mechanism to find a book-keeping structure to an item being freed. The
subsystem may choose to prefer offpage book-keeping for certain zones
implicitly.UMA_ZONE_ZINIT
UMA_ZONE_ZINIT
flag would not return zeroed memory
on every uma_zalloc
().UMA_ZONE_HASH
UMA_ZONE_VTOSLAB
UMA_ZONE_MALLOC
UMA_ZONE_VM
UMA_ZONE_NUMA
UMA_FIRSTTOUCH
kernel option is
configured, all zones implicitly use a first-touch policy, and the
UMA_ZONE_NUMA
flag has no effect. The
UMA_XDOMAIN
kernel option, when configured, causes
UMA to do the extra tracking to ensure that allocations from first-touch
zones are always local. Otherwise, consumers that do not free memory on
the same domain from which it was allocated will cause mixing in per-CPU
caches. See numa(4) for more details.Zones can be destroyed using
uma_zdestroy
(),
freeing all memory that is cached in the zone. All items allocated from the
zone must be freed to the zone before the zone may be safely destroyed.
To allocate an item from a zone, simply call
uma_zalloc
()
with a pointer to that zone and set the flags argument
to selected flags as documented in malloc(9). It will
return a pointer to an item if successful, or NULL
in the rare case where all items in the zone are in use and the allocator is
unable to grow the zone and M_NOWAIT
is
specified.
Items are released back to the zone from which they
were allocated by calling
uma_zfree
()
with a pointer to the zone and a pointer to the item. If
item is NULL
, then
uma_zfree
() does nothing.
The variants
uma_zalloc_arg
()
and
uma_zfree_arg
()
allow callers to specify an argument for the ctor
and dtor
functions of the zone, respectively. The
uma_zalloc_domain
()
function allows callers to specify a fixed numa(4) domain
to allocate from. This uses a guaranteed but slow path in the allocator
which reduces concurrency. The
uma_zfree_domain
()
function should be used to return memory allocated in this fashion. This
function infers the domain from the pointer and does not require it as an
argument.
The
uma_prealloc
()
function allocates slabs for the requested number of items, typically
following the initial creation of a zone. Subsequent allocations from the
zone will be satisfied using the pre-allocated slabs. Note that slab
allocation is performed with the M_WAITOK
flag, so
uma_prealloc
() may sleep.
The
uma_zone_reserve
()
function sets the number of reserved items for the zone.
uma_zalloc
() and variants will ensure that the zone
contains at least the reserved number of free items. Reserved items may be
allocated by specifying M_USE_RESERVE
in the
allocation request flags. uma_zone_reserve
() does
not perform any pre-allocation by itself.
The
uma_zone_reserve_kva
()
function pre-allocates kernel virtual address space for the requested number
of items. Subsequent allocations from the zone will be satisfied using the
pre-allocated address space. Note that unlike
uma_zone_reserve
(),
uma_zone_reserve_kva
() does not restrict the use of
the pre-allocation to M_USE_RESERVE
requests.
The
uma_zone_set_allocf
()
and
uma_zone_set_freef
()
functions allow a zone's default slab allocation and free functions to be
overridden. This is useful if the zone's items have special memory
allocation constraints. For example, if multi-page objects are required to
be physically contiguous, an allocf function which
requests contiguous memory from the kernel's page allocator may be used.
The
uma_zone_set_max
()
function limits the number of items (and therefore memory) that can be
allocated to zone. The nitems
argument specifies the requested upper limit number of items. The effective
limit is returned to the caller, as it may end up being higher than
requested due to the implementation rounding up to ensure all memory pages
allocated to the zone are utilised to capacity. The limit applies to the
total number of items in the zone, which includes allocated items, free
items and free items in the per-cpu caches. On systems with more than one
CPU it may not be possible to allocate the specified number of items even
when there is no shortage of memory, because all of the remaining free items
may be in the caches of the other CPUs when the limit is hit.
The
uma_zone_set_maxcache
()
function limits the number of free items which may be cached in the zone,
excluding the per-CPU caches, which are bounded in size. For example, to
implement a ‘pure
’ per-CPU cache, a
cache zone may be configured with a maximum cache size of 0.
The
uma_zone_get_max
()
function returns the effective upper limit number of items for a zone.
The
uma_zone_get_cur
()
function returns an approximation of the number of items currently allocated
from the zone. The returned value is approximate because appropriate
synchronisation to determine an exact value is not performed by the
implementation. This ensures low overhead at the expense of potentially
stale data being used in the calculation.
The
uma_zone_set_warning
()
function sets a warning that will be printed on the system console when the
given zone becomes full and fails to allocate an item. The warning will be
printed no more often than every five minutes. Warnings can be turned off
globally by setting the vm.zone_warnings sysctl
tunable to 0.
The
uma_zone_set_maxaction
()
function sets a function that will be called when the given zone becomes
full and fails to allocate an item. The function will be called with the
zone locked. Also, the function that called the allocation function may have
held additional locks. Therefore, this function should do very little work
(similar to a signal handler).
The
SYSCTL_UMA_MAX
(parent,
nbr, name,
access, zone,
descr) macro declares a static
sysctl(9) oid that exports the effective upper limit
number of items for a zone. The zone argument should
be a pointer to uma_zone_t. A read of the oid returns
value obtained through uma_zone_get_max
(). A write
to the oid sets new value via uma_zone_set_max
().
The
SYSCTL_ADD_UMA_MAX
(ctx,
parent, nbr,
name, access,
zone, descr) macro is provided
to create this type of oid dynamically.
The
SYSCTL_UMA_CUR
(parent,
nbr, name,
access, zone,
descr) macro declares a static read-only
sysctl(9) oid that exports the approximate current
occupancy of the zone. The zone argument should be a
pointer to uma_zone_t. A read of the oid returns value
obtained through uma_zone_get_cur
(). The
SYSCTL_ADD_UMA_CUR
(ctx,
parent, nbr,
name, zone,
descr) macro is provided to create this type of oid
dynamically.
The memory that these allocation calls return is not executable.
The uma_zalloc
() function does not support the
M_EXEC
flag to allocate executable memory. Not all
platforms enforce a distinction between executable and non-executable
memory.
Jeff Bonwick, The Slab Allocator: An Object-Caching Kernel Memory Allocator, 1994.
The zone allocator first appeared in FreeBSD 3.0. It was radically changed in FreeBSD 5.0 to function as a slab allocator.
The zone allocator was written by John S. Dyson. The zone allocator was rewritten in large parts by Jeff Roberson <jeff@FreeBSD.org> to function as a slab allocator.
This manual page was written by Dag-Erling Smørgrav <des@FreeBSD.org>. Changes for UMA by Jeroen Ruigrok van der Werven <asmodai@FreeBSD.org>.
August 20, 2020 | Debian |