NVLIST_ALLOC(9F) Kernel Functions for Drivers NVLIST_ALLOC(9F)

NAME


nvlist_alloc, nvlist_free, nvlist_size, nvlist_pack, nvlist_unpack,
nvlist_dup, nv_alloc_init, nv_alloc_fini, nvlist_xalloc, nvlist_xpack,
nvlist_xunpack, nvlist_xdup, nvlist_merge - Manage a name-value pair list

SYNOPSIS


#include <sys/nvpair.h>

List Manipulation


int
nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag);

int
nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva);

void
nvlist_free(nvlist_t *nvl);

int
nvlist_size(nvlist_t *nvl, size_t *size, int encoding);

int
nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
int flag);

int
nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
nv_alloc_t *nva);

int
nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag);

int
nvlist_xunpack(char *buf, size_t, buflen", nvlist_t, **nvlp", nv_alloc_t,
*nva");

int
nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag);

int
nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva);

int
nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int kmflag);

Pluggable Allocator Configuration


nv_alloc_t *
nvlist_lookup_nv_alloc(nvlist_t *nvl);

int
nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, ...);

void
nv_alloc_reset(nv_alloc_t *nva);

void
nv_alloc_fini(nv_alloc_t *nva);

Pluggable Allocation Initialization with Fixed Allocator


int
nv_alloc_init(nv_alloc_t *nva, nv_fixed_ops, void *bufptr, sz);

INTERFACE LEVEL


illumos DDI specific (illumos DDI)

PARAMETERS


nvlp Address of a pointer to list of name-value pairs (nvlist_t).

nvflag Specify bit fields defining nvlist_t properties:

NV_UNIQUE_NAME
nvpair names are unique.

NV_UNIQUE_NAME_TYPE
Name-data type combination is unique

kmflag Kernel memory allocation policy, either KM_SLEEP or
KM_NOSLEEP.

nvl nvlist_t to be processed.

dst Destination nvlist_t.

size Pointer to buffer to contain the encoded size.

bufp Address of buffer to pack nvlist into. Must be 8-byte
aligned. If NULL, library will allocate memory.

buf Buffer containing packed nvlist_t.

buflen buflen
Size of buffer bufp or buf points to.

encoding Encoding method for packing.

nvo Pluggable allocator operations pointer (nv_alloc_ops_t).

nva Points to a nv_alloc_t structure to be used for the specified
nvlist_t.

DESCRIPTION


List Manipulation


The nvlist_alloc() function allocates a new name-value pair list and
updates nvlp to point to the handle. The argument nvflag specifies
nvlist_t properties to remain persistent across packing, unpacking, and
duplication.

If NV_UNIQUE_NAME is specified for nvflag, existing nvpairs with matching
names are removed before the new nvpair is added. If NV_UNIQUE_NAME_TYPE
is specified for nvflag, existing nvpairs with matching names and data
types are removed before the new nvpair is added. See nvlist_add_byte(9F)
for more details.

The nvlist_xalloc() function differs from nvlist_alloc() in that
nvlist_xalloc() can use a different allocator, as described in the
Pluggable Allocators section.

The nvlist_free() function frees a name-value pair list. If nvl is a null
pointer, no action occurs.

The nvlist_size() function returns the minimum size of a contiguous buffer
large enough to pack nvl. The encoding parameter specifies the method of
encoding when packing nvl Supported encoding methods are:

NV_ENCODE_NATIVE
Straight bcopy() as described in bcopy(9F).

NV_ENCODE_XDR
Use XDR encoding, suitable for sending to another host.

The nvlist_pack() function packs nvl into contiguous memory starting at
*bufp. The encoding parameter specifies the method of encoding (see
above).

+o If *bufp is not NULL, *bufp is expected to be a caller-allocated
buffer of size *buflen. The kmflag argument is ignored.

+o If *bufp is NULL, the library allocates memory and updates *bufp
to point to the memory and updates *buflen to contain the size of
the allocated memory. The value of kmflag indicates the memory
allocation policy

The nvlist_xpack() function differs from nvlist_pack() in that
nvlist_xpack() can use a different allocator.

The nvlist_unpack() function takes a buffer with a packed nvlist_t and
unpacks it into a searchable nvlist_t. The library allocates memory for
nvlist_t. The caller is responsible for freeing the memory by calling
nvlist_free()

The nvlist_xunpack() function differs from nvlist_unpack() in that
nvlist_xunpack() can use a different allocator.

The nvlist_dup() function makes a copy of nvl and updates nvlp to point to
the copy.

The nvlist_xdup() function differs from nvlist_dup() in that nvlist_xdup()
can use a different allocator.

The nvlist_merge() function adds copies of all name-value pairs from
nvlist_t nvl to nvlist_t dst. Name-value pairs in dst are replaced with
name-value pairs from nvl which have identical names (if dst has the type
NV_UNIQUE_NAME) or identical names and types (if dst has the type
NV_UNIQUE_NAME_TYPE).

The nvlist_lookup_nv_alloc() function retrieves the pointer to the
allocator used when manipulating a name-value pair list.

Pluggable Allocators


The nv_alloc_init(), nv_alloc_reset(), and nv_alloc_fini() functions
provide an interface that specifies the allocator to be used when
manipulating a name-value pair list.

The nv_alloc_init() determines allocator properties and puts them into the
nva argument. You need to specify the nv_arg argument, the nvo argument
and an optional variable argument list. The optional arguments are passed
to the *nv_ao_init() function.

The nva argument must be passed to nvlist_xalloc(), nvlist_xpack(),
nvlist_xunpack(), and nvlist_xdup().

The nv_alloc_reset() function resets the allocator properties to the data
specified by nv_alloc_init(). When no *nv_ao_reset() function is
specified, nv_alloc_reset() is without effect.

The nv_alloc_fini() destroys the allocator properties determined by
nv_alloc_init(). When a *nv_ao_fini() routine is specified, it is called
from nv_alloc_fini().

The disposition of the allocated objects and the memory used to store them
is left to the allocator implementation.

The nv_alloc_sleep and nv_alloc_nosleep nv_alloc_t pointers may be used
with nvlist_xalloc() to mimic the behavior of nvlist_alloc() with KM_SLEEP
and KM_NOSLEEP, respectively.

The nvpair framework provides a fixed-buffer allocator, accessible via

Given a buffer size and address, the fixed-buffer allocator allows for the
creation of nvlists in contexts where malloc(3C) or kmem_alloc(9F) services
may not be available. The fixed-buffer allocator is designed primarily to
support the creation of nvlists.

Memory freed using nvlist_free(), pair-removal, or similar routines is not
reclaimed.

When used to initialize the fixed-buffer allocator, nv_alloc_init() should
be called as follows:

nv_alloc_init(nv_alloc_t *nva, nv_fixed_ops, void *bufptr, size_t sz).

When invoked on a fixed-buffer, the nv_alloc_reset() function resets the
fixed buffer and prepares it for re-use. The framework consumer is
responsible for freeing the buffer passed to nv_alloc_init().

Creating Pluggable Allocators


Any producer of name-value pairs may possibly specify his own allocator
routines. You must provide the following pluggable allocator operations in
the allocator implementation.

int (*nv_ao_init)(nv_alloc_t *nva, va_list nv_valist);
void (*nv_ao_fini)(nv_alloc_t *nva);
void *(*nv_ao_alloc)(nv_alloc_t *nva, size_t sz);
void (*nv_ao_reset)(nv_alloc_t *nva);
void (*nv_ao_free)(nv_alloc_t *nva, void *buf, size_t sz);

The nva argument of the allocator implementation is always the first
argument.

The optional *nv_ao_init() function is responsible for filling the data
specified by nv_alloc_init() into the nva_arg member.
The *nv_ao_init() function is called only when nv_alloc_init() is
executed.

The optional *nv_ao_fini() function is responsible for the cleanup of the
allocator implementation. It is called by nv_alloc_fini().

The required *nv_ao_alloc() function is used in the nvpair allocation
framework for memory allocation. The sz argument specifies the size of the
requested buffer.

The optional *nv_ao_reset() function is responsible for resetting the
nva_arg member to the data specified by nv_alloc_init().

The required *nv_ao_free() function is used in the nvpair allocator
framework for memory de-allocation. The argument buf is a pointer to a
block previously allocated by *nv_ao_alloc() function. The size argument
sz must exactly match the original allocation.

The disposition of the allocated objects and the memory used to store them
is left to the allocator implementation.

CONTEXT


The nvlist_alloc(), nvlist_pack(), nvlist_unpack(), and nvlist_dup()
functions can be called from interrupt context only if the KM_NOSLEEP flag
is set. They can be called from user context with any valid flag.

The nvlist_xalloc(), nvlist_xpack(), nvlist_xunpack(), and nvlist_xdup()
functions can be called from interrupt context only if (1) the default
allocator is used and the KM_NOSLEEP flag is set or (2) the specified
allocator did not sleep for free memory (for example, it uses a
pre-allocated buffer for memory allocations).

These functions can be called from user or kernel context with any valid
flag.

RETURN VALUES


For nvlist_alloc(), nvlist_dup(), nvlist_xalloc(), and nvlist_xdup():

0 success

EINVAL invalid argument

ENOMEM insufficient memory

For nvlist_pack(), nvlist_unpack(), nvlist_xpack(), and nvlist_xunpack():

0 success

EINVAL invalid argument

ENOMEM insufficient memory

EFAULT encode/decode error

ENOTSUP encode/decode method not supported

For nvlist_size():

0 success

EINVAL

The nvlist_lookup_nv_alloc() function returns a pointer to the allocator or
NULL if there is no allocator.

USAGE


The fixed-buffer allocator is very simple allocator. It uses a pre-
allocated buffer for memory allocations and it can be used in interrupt
context. You are responsible for allocation and de-allocation for the pre-
allocated buffer.

EXAMPLES


Example 1 Using the fixed-buffer allocator

#include <sys/nvpair.h>

/* initialize the nvpair allocator framework */
static nv_alloc_t *
init(char *buf, size_t size)
{
nv_alloc_t *nvap;

if ((nvap = kmem_alloc(sizeof(nv_alloc_t), KM_SLEEP)) == NULL)
return (NULL);

if (nv_alloc_init(nvap, nv_fixed_ops, buf, size) == 0)
return (nvap);

return (NULL);
}

static void
fini(nv_alloc_t *nvap)
{
nv_alloc_fini(nvap);
kmem_free(nvap, sizeof(nv_alloc_t));
}

static int
interrupt_context(nv_alloc_t *nva)
{
nvlist_t *nvl;
int error;

if ((error = nvlist_xalloc(&nvl, NV_UNIQUE_NAME, nva)) != 0)
return (-1);

if ((error = nvlist_add_int32(nvl, "name", 1234)) == 0)
error = send_nvl(nvl);

nvlist_free(nvl);
return (error);
}

SEE ALSO


bcopy(9F), kmem_alloc(9F), nvlist_add_byte(9F)

illumos June 12, 2021 illumos