KMEM(9) | Kernel Developer's Manual | KMEM(9) |
kmem
—
#include <sys/kmem.h>
void *
kmem_alloc
(size_t
size, km_flag_t
kmflags);
void *
kmem_zalloc
(size_t
size, km_flag_t
kmflags);
void
kmem_free
(void
*p, size_t
size);
void *
kmem_intr_alloc
(size_t
size, km_flag_t
kmflags);
void *
kmem_intr_zalloc
(size_t
size, km_flag_t
kmflags);
void
kmem_intr_free
(void
*p, size_t
size);
char *
kmem_asprintf
(const
char *fmt,
...);
char *
kmem_strdupsize
(const
char *str, size_t
*size, km_flag_t
kmflags);
void
kmem_strfree
(char
*str);
options KMEM_SIZE
options KMEM_REDZONE
options KMEM_GUARD
kmem_alloc
() allocates kernel wired memory. It takes the
following arguments.
KM_SLEEP
KM_SLEEP
is specified,
then the allocation cannot fail.KM_NOSLEEP
NULL
if there
is not enough memory available. It should only be used when failure to
allocate will not have harmful, user-visible effects.
KM_NOSLEEP
is strongly
discouraged as it can create transient, hard to debug failures that
occur when the system is under memory pressure.In situations where it is not possible to sleep, for example because locks are held by the caller, the code path should be restructured to allow the allocation to be made in another place.
The contents of allocated memory are uninitialized.
Unlike Solaris, kmem_alloc(0, flags) is illegal.
kmem_zalloc
() is the equivalent of
kmem_alloc
(), except that it initializes the memory
to zero.
kmem_asprintf
() functions as the well
known asprintf
() function, but allocates memory
using kmem_alloc
(). This routine can sleep during
allocation. The size of the allocated area is the length of the returned
character string, plus one (for the NUL terminator). This must be taken into
consideration when freeing the returned area with
kmem_free
().
kmem_free
() frees kernel wired memory
allocated by kmem_alloc
() or
kmem_zalloc
() so that it can be used for other
purposes. It takes the following arguments.
kmem_alloc
() or
kmem_zalloc
().kmem_alloc
() or
kmem_zalloc
() when the memory was allocated.Freeing NULL
is illegal.
kmem_intr_alloc
(),
kmem_intr_zalloc
() and
kmem_intr_free
() are the equivalents of the above
kmem routines which can be called from the interrupt context. These routines
are for the special cases. Normally,
pool_cache(9) should be
used for memory allocation from interrupt context.
The kmem_strdupsize
() function is a
utility function that can be used to copy the string in the
str argument to a new buffer allocated using
kmem_alloc
() and optionally return the size of the
allocation (the length of the string plus the trailing
NUL
) in the size argument if
that is not NULL
.
The kmem_strfree
() function can be used to
free a NUL
terminated string computing the length of
the string using strlen(3) and
adding one for the NUL
and then using
kmem_free
().
KM_SLEEP
allocations while holding mutexes or
reader/writer locks is discouraged, as the caller can sleep for an unbounded
amount of time in order to satisfy the allocation. This can in turn block
other threads that wish to acquire locks held by the caller. It should be
noted that kmem_free
() may also block.
For some locks this is permissible or even unavoidable. For others, particularly locks that may be taken from soft interrupt context, it is a serious problem. As a general rule it is better not to allow this type of situation to develop. One way to circumvent the problem is to make allocations speculative and part of a retryable sequence. For example:
retry: /* speculative unlocked check */ if (need to allocate) { new_item = kmem_alloc(sizeof(*new_item), KM_SLEEP); } else { new_item = NULL; } mutex_enter(lock); /* check while holding lock for true status */ if (need to allocate) { if (new_item == NULL) { mutex_exit(lock); goto retry; } consume(new_item); new_item = NULL; } mutex_exit(lock); if (new_item != NULL) { /* did not use it after all */ kmem_free(new_item, sizeof(*new_item)); }
KMEM_SIZE
option ensure the
size given in kmem_free
() matches the actual allocated
size. On kmem_alloc
(), the kernel will allocate an
additional contiguous kmem page of eight bytes in the buffer, will register
the allocated size in the first kmem page of that buffer, and will return a
pointer to the second kmem page in that same buffer. When freeing, the kernel
reads the first page, and compares the size registered with the one given in
kmem_free
(). Any mismatch triggers a panic.
KMEM_SIZE
is enabled by default on
DIAGNOSTIC
and DEBUG
.
KMEM_REDZONE
option add a
dynamic pattern of two bytes at the end of each allocated buffer, and check
this pattern when freeing to ensure the caller hasn't written outside the
requested area. This option does not introduce a significant performance
impact, but has two drawbacks: it only catches write overflows, and catches
them only on kmem_free
().
KMEM_REDZONE
is enabled by default on
DIAGNOSTIC
.
KMEM_GUARD
option perform CPU
intensive sanity checks on kmem operations. It adds additional, very high
overhead runtime verification to kmem operations. It must be enabled with
KMEM_SIZE
.
KMEM_GUARD
tries to catch the following
types of bugs:
kmem_free
(), by using
KMEM_SIZE
's registered size. If an underflow
occurs, the size stored by KMEM_SIZE
will be
overwritten, which means that when freeing, the kernel will spot the
mismatch.To enable it, boot the system with the -d
option, which causes the debugger to be entered early during the kernel boot
process. Issue commands such as the following:
db> w kmem_guard_depth 0t30000 db> c
This instructs kmem_guard
to queue up to
60000 (30000*2) pages of unmapped KVA to catch use-after-free type errors.
When kmem_free
() is called, memory backing a freed
item is unmapped and the kernel VA space pushed onto a FIFO. The VA space
will not be reused until another 30k items have been freed. Until reused the
kernel will catch invalid accesses and panic with a page fault.
Limitations:
KMEM_GUARD
is enabled by default on
DEBUG
.
kmem_alloc
(),
kmem_asprintf
(),
kmem_intr_alloc
(),
kmem_intr_zalloc
(),
kmem_strdupsize
(), and
kmem_zalloc
() return a pointer to allocated memory.
Otherwise, NULL
is returned.
kmem
subsystem is implemented within the file
sys/kern/subr_kmem.c.
kmem_alloc
(),
kmem_asprintf
(), kmem_free
(),
kmem_strdupsize
(),
kmem_strfree
(), and
kmem_zalloc
() functions cannot be used from interrupt
context, from a soft interrupt, or from a callout. Use
pool_cache(9) in these
situations.
kmem_alloc
() is
uninitialized, it can contain security-sensitive data left by its previous
user. It is the caller's responsibility not to expose it to the world.
November 7, 2017 | NetBSD 9.2 |