NVLIST_ALLOC(9F) Kernel Functions for Drivers NVLIST_ALLOC(9F) NNAAMMEE 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 SSYYNNOOPPSSIISS #include List Manipulation: iinntt nnvvlliisstt__aalllloocc(nnvvlliisstt__tt ****_n_v_l_p, uuiinntt__tt _n_v_f_l_a_g, iinntt _k_m_f_l_a_g); iinntt nnvvlliisstt__xxaalllloocc(nnvvlliisstt__tt ****_n_v_l_p, uuiinntt__tt _n_v_f_l_a_g, nnvv__aalllloocc__tt **_n_v_a); vvooiidd nnvvlliisstt__ffrreeee(nnvvlliisstt__tt **_n_v_l); iinntt nnvvlliisstt__ssiizzee(nnvvlliisstt__tt **_n_v_l, ssiizzee__tt **_s_i_z_e, iinntt _e_n_c_o_d_i_n_g); iinntt nnvvlliisstt__ppaacckk(nnvvlliisstt__tt **_n_v_l, cchhaarr ****_b_u_f_p, ssiizzee__tt **_b_u_f_l_e_n, iinntt _e_n_c_o_d_i_n_g, iinntt _f_l_a_g); iinntt nnvvlliisstt__xxppaacckk(nnvvlliisstt__tt **_n_v_l, cchhaarr ****_b_u_f_p, ssiizzee__tt **_b_u_f_l_e_n, iinntt _e_n_c_o_d_i_n_g, nnvv__aalllloocc__tt **_n_v_a); iinntt nnvvlliisstt__uunnppaacckk(cchhaarr **_b_u_f, ssiizzee__tt _b_u_f_l_e_n, nnvvlliisstt__tt ****_n_v_l_p, iinntt _f_l_a_g); iinntt nnvvlliisstt__xxuunnppaacckk(cchhaarr **_b_u_f, ssiizzee__tt _b_u_f_l_e_n, nnvvlliisstt__tt ****_n_v_l_p, nnvv__aalllloocc__tt **_n_v_a); iinntt nnvvlliisstt__dduupp(nnvvlliisstt__tt **_n_v_l, nnvvlliisstt__tt ****_n_v_l_p, iinntt _f_l_a_g); iinntt nnvvlliisstt__xxdduupp(nnvvlliisstt__tt **_n_v_l, nnvvlliisstt__tt ****_n_v_l_p, nnvv__aalllloocc__tt **_n_v_a); iinntt nnvvlliisstt__mmeerrggee(nnvvlliisstt__tt **_d_s_t, nnvvlliisstt__tt **_n_v_l, iinntt _f_l_a_g); Pluggable Allocator Configuration: nnvv__aalllloocc__tt **nnvvlliisstt__llooookkuupp__nnvv__aalllloocc(nnvvlliisstt__tt **));; iinntt nnvv__aalllloocc__iinniitt(nnvv__aalllloocc__tt **_n_v_a, ccoonnsstt nnvv__aalllloocc__ooppss__tt ** _n_v_o_,/* args */ ...); vvooiidd nnvv__aalllloocc__rreesseett(nnvv__aalllloocc__tt **_n_v_a); vvooiidd nnvv__aalllloocc__ffiinnii(nnvv__aalllloocc__tt **_n_v_a); Pluggable Allocation Initialization with Fixed Allocator: iinntt nnvv__aalllloocc__iinniitt(nnvv__aalllloocc__tt **_n_v_a, nnvv__ffiixxeedd__ooppss, vvooiidd ** _b_u_f_p_t_r, ssiizzee__tt sz); IINNTTEERRFFAACCEE LLEEVVEELL Solaris DDI specific (Solaris DDI) PPAARRAAMMEETTEERRSS _n_v_l_p Address of a pointer to list of name-value pairs (nnvvlliisstt__tt). _n_v_f_l_a_g Specify bit fields defining nnvvlliisstt__tt properties: NNVV__UUNNIIQQUUEE__NNAAMMEE nnvvppaaiirr names are unique. NNVV__UUNNIIQQUUEE__NNAAMMEE__TTYYPPEE Name-data type combination is unique _k_m_f_l_a_g Kernel memory allocation policy, either KKMM__SSLLEEEEPP or KKMM__NNOOSSLLEEEEPP. _n_v_l nnvvlliisstt__tt to be processed. _d_s_t Destination nnvvlliisstt__tt. _s_i_z_e Pointer to buffer to contain the encoded size. _b_u_f_p Address of buffer to pack nnvvlliisstt into. Must be 8-byte aligned. If NULL, library will allocate memory. _b_u_f Buffer containing packed nnvvlliisstt__tt. _b_u_f_l_e_n Size of buffer _b_u_f_p or _b_u_f points to. _e_n_c_o_d_i_n_g Encoding method for packing. _n_v_o Pluggable allocator operations pointer (nv_alloc_ops_t). _n_v_a Points to a nv_alloc_t structure to be used for the specified nnvvlliisstt__tt. DDEESSCCRRIIPPTTIIOONN List Manipulation: The nnvvlliisstt__aalllloocc(()) function allocates a new name-value pair list and updates _n_v_l_p to point to the handle. The argument _n_v_f_l_a_g specifies nnvvlliisstt__tt properties to remain persistent across packing, unpacking, and duplication. If NNVV__UUNNIIQQUUEE__NNAAMMEE is specified for nvflag, existing nvpairs with matching names are removed before the new nvpair is added. If NNVV__UUNNIIQQUUEE__NNAAMMEE__TTYYPPEE is specified for nvflag, existing nvpairs with matching names and data types are removed before the new nvpair is added. See nnvvlliisstt__aadddd__bbyyttee(9F) for more details. The nnvvlliisstt__xxaalllloocc(()) function differs from nnvvlliisstt__aalllloocc(()) in that nnvvlliisstt__xxaalllloocc(()) can use a different allocator, as described in the Pluggable Allocators section. The nnvvlliisstt__ffrreeee(()) function frees a name-value pair list. If _n_v_l is a null pointer, no action occurs. The nnvvlliisstt__ssiizzee(()) function returns the minimum size of a contiguous buffer large enough to pack _n_v_l. The _e_n_c_o_d_i_n_g parameter specifies the method of encoding when packing _n_v_l. Supported encoding methods are: NNVV__EENNCCOODDEE__NNAATTIIVVEE Straight bbccooppyy(()) as described in bbccooppyy(9F). NNVV__EENNCCOODDEE__XXDDRR Use XDR encoding, suitable for sending to another host. The nnvvlliisstt__ppaacckk(()) function packs _n_v_l into contiguous memory starting at *_b_u_f_p. The _e_n_c_o_d_i_n_g parameter specifies the method of encoding (see above). o If *_b_u_f_p is not NULL, *_b_u_f_p is expected to be a caller- allocated buffer of size *_b_u_f_l_e_n. The _k_m_f_l_a_g argument is ignored. o If *_b_u_f_p is NULL, the library allocates memory and updates *_b_u_f_p to point to the memory and updates *_b_u_f_l_e_n to contain the size of the allocated memory. The value of _k_m_f_l_a_g indicates the memory allocation policy The nnvvlliisstt__xxppaacckk(()) function differs from nnvvlliisstt__ppaacckk(()) in that nnvvlliisstt__xxppaacckk(()) can use a different allocator. The nnvvlliisstt__uunnppaacckk(()) function takes a buffer with a packed nnvvlliisstt__tt and unpacks it into a searchable nnvvlliisstt__tt. The library allocates memory for nnvvlliisstt__tt. The caller is responsible for freeing the memory by calling nnvvlliisstt__ffrreeee(()). The nnvvlliisstt__xxuunnppaacckk(()) function differs from nnvvlliisstt__uunnppaacckk(()) in that nnvvlliisstt__xxuunnppaacckk(()) can use a different allocator. The nnvvlliisstt__dduupp(()) function makes a copy of _n_v_l and updates _n_v_l_p to point to the copy. The nnvvlliisstt__xxdduupp(()) function differs from nnvvlliisstt__dduupp(()) in that nnvvlliisstt__xxdduupp(()) can use a different allocator. The nnvvlliisstt__mmeerrggee(()) function adds copies of all name-value pairs from nnvvlliisstt__tt _n_v_l to nnvvlliisstt__tt ddsstt. Name-value pairs in dst are replaced with name-value pairs from nnvvll which have identical names (if dst has the type NNVV__UUNNIIQQUUEE__NNAAMMEE), or identical names and types (if dst has the type NNVV__UUNNIIQQUUEE__NNAAMMEE__TTYYPPEE). The nnvvlliisstt__llooookkuupp__nnvv__aalllloocc(()) function retrieves the pointer to the allocator used when manipulating a name-value pair list. PPLLUUGGGGAABBLLEE AALLLLOOCCAATTOORRSS Using Pluggable Allocators: The nnvv__aalllloocc__iinniitt(()), nnvv__aalllloocc__rreesseett(()) and nnvv__aalllloocc__ffiinnii(()) functions provide an interface that specifies the allocator to be used when manipulating a name-value pair list. The nnvv__aalllloocc__iinniitt(()) determines allocator properties and puts them into the _n_v_a argument. You need to specify the _n_v___a_r_g argument, the _n_v_o argument and an optional variable argument list. The optional arguments are passed to the (*nnvv__aaoo__iinniitt(())) function. The _n_v_a argument must be passed to nnvvlliisstt__xxaalllloocc(()), nnvvlliisstt__xxppaacckk(()), nnvvlliisstt__xxuunnppaacckk(()) and nnvvlliisstt__xxdduupp(()). The nnvv__aalllloocc__rreesseett(()) function resets the allocator properties to the data specified by nnvv__aalllloocc__iinniitt(()). When no (*nnvv__aaoo__rreesseett(())) function is specified, nnvv__aalllloocc__rreesseett(()) is without effect. The nnvv__aalllloocc__ffiinnii(()) destroys the allocator properties determined by nnvv__aalllloocc__iinniitt(()). When a (*nnvv__aaoo__ffiinnii(())) routine is specified, it is called from nnvv__aalllloocc__ffiinnii(()). 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. o nv_alloc_nosleep o nv_alloc_sleep The nvpair framework provides a fixed-buffer allocator, accessible via nv_fixed_ops. o nv_fixed_ops Given a buffer size and address, the fixed-buffer allocator allows for the creation of nvlists in contexts where malloc or kmem_alloc services may not be available. The fixed-buffer allocator is designed primarily to support the creation of nvlists. Memory freed using nnvvlliisstt__ffrreeee(()), pair-removal, or similar routines is not reclaimed. When used to initialize the fixed-buffer allocator, nv_alloc_init should be called as follows: int nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, void *bufptr, size_t sz); When invoked on a fixed-buffer, the nnvv__aalllloocc__rreesseett(()) function resets the fixed buffer and prepares it for re-use. The framework consumer is responsible for freeing the buffer passed to nnvv__aalllloocc__iinniitt(()). CCRREEAATTIINNGG PPLLUUGGGGAABBLLEE AALLLLOOCCAATTOORRSS Any producer of name-value pairs may possibily 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 _n_v_a argument of the allocator implementation is always the first argument. The optional (*nnvv__aaoo__iinniitt(()) ) function is responsible for filling the data specified by nnvv__aalllloocc__iinniitt(()) into the nnvvaa__aarrgg(()) argument. The (*nnvv__aaoo__iinniitt(())) function is called only when nnvv__aalllloocc__iinniitt(()) is executed. The optional (*nnvv__aaoo__ffiinnii(())) function is responsible for the cleanup of the allocator implementation. It is called by nnvv__aalllloocc__ffiinnii(()). The required (*nnvv__aaoo__aalllloocc(())) function is used in the nvpair allocation framework for memory allocation. The sz argument specifies the size of the requested buffer. The optional (*nnvv__aaoo__rreesseett(())) function is responsible for resetting the nva_arg argument to the data specified by nnvv__aalllloocc__iinniitt(()). The required (*nnvv__aaoo__ffrreeee(())) function is used in the nvpair allocator framework for memory de-allocation. The argument buf is a pointer to a block previously allocated by (*nnvv__aaoo__aalllloocc(())) 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. RREETTUURRNN VVAALLUUEESS For nnvvlliisstt__aalllloocc(()), nnvvlliisstt__dduupp(()), nnvvlliisstt__xxaalllloocc(()), and nnvvlliisstt__xxdduupp(()): 00 success EEIINNVVAALL invalid argument EENNOOMMEEMM insufficient memory For nnvvlliisstt__ppaacckk(()), nnvvlliisstt__uunnppaacckk(()), nnvvlliisstt__xxppaacckk(()), and nnvvlliisstt__xxuunnppaacckk(()): 00 success EEIINNVVAALL invalid argument EENNOOMMEEMM insufficient memory EEFFAAUULLTT encode/decode error EENNOOTTSSUUPP encode/decode method not supported For nnvvlliisstt__ssiizzee(()): 00 success EEIINNVVAALL invalid argument For nnvvlliisstt__llooookkuupp__nnvv__aalllloocc(()): pointer to the allocator UUSSAAGGEE 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. EEXXAAMMPPLLEESS /* * using the fixed-buffer allocator. */ #include /* 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); } CCOONNTTEEXXTT The nnvvlliisstt__aalllloocc(()), nnvvlliisstt__ppaacckk(()), nnvvlliisstt__uunnppaacckk(()), and nnvvlliisstt__dduupp(()) functions can be called from interrupt context only if the KKMM__NNOOSSLLEEEEPP flag is set. They can be called from user context with any valid flag. The nnvvlliisstt__xxaalllloocc(()), nnvvlliisstt__xxppaacckk(()), nnvvlliisstt__xxuunnppaacckk(()), and nnvvlliisstt__xxdduupp(()) functions can be called from interrupt context only if (1) the default allocator is used and the KKMM__NNOOSSLLEEEEPP 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. February 15, 2016 NVLIST_ALLOC(9F)