xref: /illumos-gate/usr/src/common/nvpair/nvpair.c (revision b8a5bee1)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53bb79becSeschrock  * Common Development and Distribution License (the "License").
63bb79becSeschrock  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21d9638e54Smws 
227c478bd9Sstevel@tonic-gate /*
23f6e214c7SGavin Maltby  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
24843c2111SMatthew Ahrens  * Copyright (c) 2015, 2017 by Delphix. All rights reserved.
25*b8a5bee1SAndrew Stormont  * Copyright 2018 RackTop Systems.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
297c478bd9Sstevel@tonic-gate #include <sys/debug.h>
307c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h>
317c478bd9Sstevel@tonic-gate #include <sys/int_limits.h>
327c478bd9Sstevel@tonic-gate #include <sys/nvpair.h>
337c478bd9Sstevel@tonic-gate #include <sys/nvpair_impl.h>
347c478bd9Sstevel@tonic-gate #include <rpc/types.h>
357c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
387c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
39602ca9eaScth #include <sys/ddi.h>
40602ca9eaScth #include <sys/sunddi.h>
415c5f1371SRichard Lowe #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #else
437c478bd9Sstevel@tonic-gate #include <stdarg.h>
44602ca9eaScth #include <stdlib.h>
45602ca9eaScth #include <string.h>
467c478bd9Sstevel@tonic-gate #include <strings.h>
475c5f1371SRichard Lowe #include <stddef.h>
487c478bd9Sstevel@tonic-gate #endif
497c478bd9Sstevel@tonic-gate 
50602ca9eaScth #define	skip_whitespace(p)	while ((*(p) == ' ') || (*(p) == '\t')) p++
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * nvpair.c - Provides kernel & userland interfaces for manipulating
547c478bd9Sstevel@tonic-gate  *	name-value pairs.
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  * Overview Diagram
577c478bd9Sstevel@tonic-gate  *
587c478bd9Sstevel@tonic-gate  *  +--------------+
597c478bd9Sstevel@tonic-gate  *  |  nvlist_t    |
607c478bd9Sstevel@tonic-gate  *  |--------------|
617c478bd9Sstevel@tonic-gate  *  | nvl_version  |
627c478bd9Sstevel@tonic-gate  *  | nvl_nvflag   |
637c478bd9Sstevel@tonic-gate  *  | nvl_priv    -+-+
647c478bd9Sstevel@tonic-gate  *  | nvl_flag     | |
657c478bd9Sstevel@tonic-gate  *  | nvl_pad      | |
667c478bd9Sstevel@tonic-gate  *  +--------------+ |
677c478bd9Sstevel@tonic-gate  *                   V
687c478bd9Sstevel@tonic-gate  *      +--------------+      last i_nvp in list
697c478bd9Sstevel@tonic-gate  *      | nvpriv_t     |  +--------------------->
707c478bd9Sstevel@tonic-gate  *      |--------------|  |
717c478bd9Sstevel@tonic-gate  *   +--+- nvp_list    |  |   +------------+
727c478bd9Sstevel@tonic-gate  *   |  |  nvp_last   -+--+   + nv_alloc_t |
737c478bd9Sstevel@tonic-gate  *   |  |  nvp_curr    |      |------------|
747c478bd9Sstevel@tonic-gate  *   |  |  nvp_nva    -+----> | nva_ops    |
757c478bd9Sstevel@tonic-gate  *   |  |  nvp_stat    |      | nva_arg    |
767c478bd9Sstevel@tonic-gate  *   |  +--------------+      +------------+
777c478bd9Sstevel@tonic-gate  *   |
787c478bd9Sstevel@tonic-gate  *   +-------+
797c478bd9Sstevel@tonic-gate  *           V
807c478bd9Sstevel@tonic-gate  *   +---------------------+      +-------------------+
817c478bd9Sstevel@tonic-gate  *   |  i_nvp_t            |  +-->|  i_nvp_t          |  +-->
827c478bd9Sstevel@tonic-gate  *   |---------------------|  |   |-------------------|  |
837c478bd9Sstevel@tonic-gate  *   | nvi_next           -+--+   | nvi_next         -+--+
847c478bd9Sstevel@tonic-gate  *   | nvi_prev (NULL)     | <----+ nvi_prev          |
857c478bd9Sstevel@tonic-gate  *   | . . . . . . . . . . |      | . . . . . . . . . |
867c478bd9Sstevel@tonic-gate  *   | nvp (nvpair_t)      |      | nvp (nvpair_t)    |
877c478bd9Sstevel@tonic-gate  *   |  - nvp_size         |      |  - nvp_size       |
887c478bd9Sstevel@tonic-gate  *   |  - nvp_name_sz      |      |  - nvp_name_sz    |
897c478bd9Sstevel@tonic-gate  *   |  - nvp_value_elem   |      |  - nvp_value_elem |
907c478bd9Sstevel@tonic-gate  *   |  - nvp_type         |      |  - nvp_type       |
917c478bd9Sstevel@tonic-gate  *   |  - data ...         |      |  - data ...       |
927c478bd9Sstevel@tonic-gate  *   +---------------------+      +-------------------+
937c478bd9Sstevel@tonic-gate  *
947c478bd9Sstevel@tonic-gate  *
957c478bd9Sstevel@tonic-gate  *
967c478bd9Sstevel@tonic-gate  *   +---------------------+              +---------------------+
977c478bd9Sstevel@tonic-gate  *   |  i_nvp_t            |  +-->    +-->|  i_nvp_t (last)     |
987c478bd9Sstevel@tonic-gate  *   |---------------------|  |       |   |---------------------|
997c478bd9Sstevel@tonic-gate  *   |  nvi_next          -+--+ ... --+   | nvi_next (NULL)     |
1007c478bd9Sstevel@tonic-gate  * <-+- nvi_prev           |<-- ...  <----+ nvi_prev            |
1017c478bd9Sstevel@tonic-gate  *   | . . . . . . . . .   |              | . . . . . . . . .   |
1027c478bd9Sstevel@tonic-gate  *   | nvp (nvpair_t)      |              | nvp (nvpair_t)      |
1037c478bd9Sstevel@tonic-gate  *   |  - nvp_size         |              |  - nvp_size         |
1047c478bd9Sstevel@tonic-gate  *   |  - nvp_name_sz      |              |  - nvp_name_sz      |
1057c478bd9Sstevel@tonic-gate  *   |  - nvp_value_elem   |              |  - nvp_value_elem   |
1067c478bd9Sstevel@tonic-gate  *   |  - DATA_TYPE_NVLIST |              |  - nvp_type         |
1077c478bd9Sstevel@tonic-gate  *   |  - data (embedded)  |              |  - data ...         |
1087c478bd9Sstevel@tonic-gate  *   |    nvlist name      |              +---------------------+
1097c478bd9Sstevel@tonic-gate  *   |  +--------------+   |
1107c478bd9Sstevel@tonic-gate  *   |  |  nvlist_t    |   |
1117c478bd9Sstevel@tonic-gate  *   |  |--------------|   |
1127c478bd9Sstevel@tonic-gate  *   |  | nvl_version  |   |
1137c478bd9Sstevel@tonic-gate  *   |  | nvl_nvflag   |   |
1147c478bd9Sstevel@tonic-gate  *   |  | nvl_priv   --+---+---->
1157c478bd9Sstevel@tonic-gate  *   |  | nvl_flag     |   |
1167c478bd9Sstevel@tonic-gate  *   |  | nvl_pad      |   |
1177c478bd9Sstevel@tonic-gate  *   |  +--------------+   |
1187c478bd9Sstevel@tonic-gate  *   +---------------------+
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  *
1217c478bd9Sstevel@tonic-gate  * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will
1227c478bd9Sstevel@tonic-gate  * allow value to be aligned on 8 byte boundary
1237c478bd9Sstevel@tonic-gate  *
1247c478bd9Sstevel@tonic-gate  * name_len is the length of the name string including the null terminator
1257c478bd9Sstevel@tonic-gate  * so it must be >= 1
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate #define	NVP_SIZE_CALC(name_len, data_len) \
1287c478bd9Sstevel@tonic-gate 	(NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static int i_get_value_size(data_type_t type, const void *data, uint_t nelem);
1317c478bd9Sstevel@tonic-gate static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1327c478bd9Sstevel@tonic-gate     uint_t nelem, const void *data);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate #define	NV_STAT_EMBEDDED	0x1
1357c478bd9Sstevel@tonic-gate #define	EMBEDDED_NVL(nvp)	((nvlist_t *)(void *)NVP_VALUE(nvp))
1367c478bd9Sstevel@tonic-gate #define	EMBEDDED_NVL_ARRAY(nvp)	((nvlist_t **)(void *)NVP_VALUE(nvp))
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate #define	NVP_VALOFF(nvp)	(NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))
1397c478bd9Sstevel@tonic-gate #define	NVPAIR2I_NVP(nvp) \
1407c478bd9Sstevel@tonic-gate 	((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))
1417c478bd9Sstevel@tonic-gate 
1429ca527c3SMatthew Ahrens #ifdef _KERNEL
1439ca527c3SMatthew Ahrens int nvpair_max_recursion = 20;
1449ca527c3SMatthew Ahrens #else
1459ca527c3SMatthew Ahrens int nvpair_max_recursion = 100;
1469ca527c3SMatthew Ahrens #endif
1477c478bd9Sstevel@tonic-gate 
1482ec7644aSSerapheim Dimitropoulos uint64_t nvlist_hashtable_init_size = (1 << 4);
1492ec7644aSSerapheim Dimitropoulos 
1507c478bd9Sstevel@tonic-gate int
nv_alloc_init(nv_alloc_t * nva,const nv_alloc_ops_t * nvo,...)1517c478bd9Sstevel@tonic-gate nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)
1527c478bd9Sstevel@tonic-gate {
1537c478bd9Sstevel@tonic-gate 	va_list valist;
1547c478bd9Sstevel@tonic-gate 	int err = 0;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	nva->nva_ops = nvo;
1577c478bd9Sstevel@tonic-gate 	nva->nva_arg = NULL;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	va_start(valist, nvo);
1607c478bd9Sstevel@tonic-gate 	if (nva->nva_ops->nv_ao_init != NULL)
1617c478bd9Sstevel@tonic-gate 		err = nva->nva_ops->nv_ao_init(nva, valist);
1627c478bd9Sstevel@tonic-gate 	va_end(valist);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	return (err);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate void
nv_alloc_reset(nv_alloc_t * nva)1687c478bd9Sstevel@tonic-gate nv_alloc_reset(nv_alloc_t *nva)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	if (nva->nva_ops->nv_ao_reset != NULL)
1717c478bd9Sstevel@tonic-gate 		nva->nva_ops->nv_ao_reset(nva);
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate void
nv_alloc_fini(nv_alloc_t * nva)1757c478bd9Sstevel@tonic-gate nv_alloc_fini(nv_alloc_t *nva)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	if (nva->nva_ops->nv_ao_fini != NULL)
1787c478bd9Sstevel@tonic-gate 		nva->nva_ops->nv_ao_fini(nva);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate nv_alloc_t *
nvlist_lookup_nv_alloc(nvlist_t * nvl)1827c478bd9Sstevel@tonic-gate nvlist_lookup_nv_alloc(nvlist_t *nvl)
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	if (nvl == NULL ||
1877c478bd9Sstevel@tonic-gate 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1887c478bd9Sstevel@tonic-gate 		return (NULL);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	return (priv->nvp_nva);
1917c478bd9Sstevel@tonic-gate }
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate static void *
nv_mem_zalloc(nvpriv_t * nvp,size_t size)1947c478bd9Sstevel@tonic-gate nv_mem_zalloc(nvpriv_t *nvp, size_t size)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	nv_alloc_t *nva = nvp->nvp_nva;
1977c478bd9Sstevel@tonic-gate 	void *buf;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)
2007c478bd9Sstevel@tonic-gate 		bzero(buf, size);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	return (buf);
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate static void
nv_mem_free(nvpriv_t * nvp,void * buf,size_t size)2067c478bd9Sstevel@tonic-gate nv_mem_free(nvpriv_t *nvp, void *buf, size_t size)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	nv_alloc_t *nva = nvp->nvp_nva;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	nva->nva_ops->nv_ao_free(nva, buf, size);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate static void
nv_priv_init(nvpriv_t * priv,nv_alloc_t * nva,uint32_t stat)2147c478bd9Sstevel@tonic-gate nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)
2157c478bd9Sstevel@tonic-gate {
216c5904d13Seschrock 	bzero(priv, sizeof (nvpriv_t));
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	priv->nvp_nva = nva;
2197c478bd9Sstevel@tonic-gate 	priv->nvp_stat = stat;
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate static nvpriv_t *
nv_priv_alloc(nv_alloc_t * nva)2237c478bd9Sstevel@tonic-gate nv_priv_alloc(nv_alloc_t *nva)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	/*
2287c478bd9Sstevel@tonic-gate 	 * nv_mem_alloc() cannot called here because it needs the priv
2297c478bd9Sstevel@tonic-gate 	 * argument.
2307c478bd9Sstevel@tonic-gate 	 */
2317c478bd9Sstevel@tonic-gate 	if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)
2327c478bd9Sstevel@tonic-gate 		return (NULL);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	nv_priv_init(priv, nva, 0);
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	return (priv);
2377c478bd9Sstevel@tonic-gate }
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate /*
2407c478bd9Sstevel@tonic-gate  * Embedded lists need their own nvpriv_t's.  We create a new
2417c478bd9Sstevel@tonic-gate  * nvpriv_t using the parameters and allocator from the parent
2427c478bd9Sstevel@tonic-gate  * list's nvpriv_t.
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate static nvpriv_t *
nv_priv_alloc_embedded(nvpriv_t * priv)2457c478bd9Sstevel@tonic-gate nv_priv_alloc_embedded(nvpriv_t *priv)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	nvpriv_t *emb_priv;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)
2507c478bd9Sstevel@tonic-gate 		return (NULL);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	return (emb_priv);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2572ec7644aSSerapheim Dimitropoulos static int
nvt_tab_alloc(nvpriv_t * priv,uint64_t buckets)2582ec7644aSSerapheim Dimitropoulos nvt_tab_alloc(nvpriv_t *priv, uint64_t buckets)
2592ec7644aSSerapheim Dimitropoulos {
2602ec7644aSSerapheim Dimitropoulos 	ASSERT3P(priv->nvp_hashtable, ==, NULL);
2612ec7644aSSerapheim Dimitropoulos 	ASSERT0(priv->nvp_nbuckets);
2622ec7644aSSerapheim Dimitropoulos 	ASSERT0(priv->nvp_nentries);
2632ec7644aSSerapheim Dimitropoulos 
2642ec7644aSSerapheim Dimitropoulos 	i_nvp_t **tab = nv_mem_zalloc(priv, buckets * sizeof (i_nvp_t *));
2652ec7644aSSerapheim Dimitropoulos 	if (tab == NULL)
2662ec7644aSSerapheim Dimitropoulos 		return (ENOMEM);
2672ec7644aSSerapheim Dimitropoulos 
2682ec7644aSSerapheim Dimitropoulos 	priv->nvp_hashtable = tab;
2692ec7644aSSerapheim Dimitropoulos 	priv->nvp_nbuckets = buckets;
2702ec7644aSSerapheim Dimitropoulos 	return (0);
2712ec7644aSSerapheim Dimitropoulos }
2722ec7644aSSerapheim Dimitropoulos 
2732ec7644aSSerapheim Dimitropoulos static void
nvt_tab_free(nvpriv_t * priv)2742ec7644aSSerapheim Dimitropoulos nvt_tab_free(nvpriv_t *priv)
2752ec7644aSSerapheim Dimitropoulos {
2762ec7644aSSerapheim Dimitropoulos 	i_nvp_t **tab = priv->nvp_hashtable;
2772ec7644aSSerapheim Dimitropoulos 	if (tab == NULL) {
2782ec7644aSSerapheim Dimitropoulos 		ASSERT0(priv->nvp_nbuckets);
2792ec7644aSSerapheim Dimitropoulos 		ASSERT0(priv->nvp_nentries);
2802ec7644aSSerapheim Dimitropoulos 		return;
2812ec7644aSSerapheim Dimitropoulos 	}
2822ec7644aSSerapheim Dimitropoulos 
2832ec7644aSSerapheim Dimitropoulos 	nv_mem_free(priv, tab, priv->nvp_nbuckets * sizeof (i_nvp_t *));
2842ec7644aSSerapheim Dimitropoulos 
2852ec7644aSSerapheim Dimitropoulos 	priv->nvp_hashtable = NULL;
2862ec7644aSSerapheim Dimitropoulos 	priv->nvp_nbuckets = 0;
2872ec7644aSSerapheim Dimitropoulos 	priv->nvp_nentries = 0;
2882ec7644aSSerapheim Dimitropoulos }
2892ec7644aSSerapheim Dimitropoulos 
2902ec7644aSSerapheim Dimitropoulos static uint32_t
nvt_hash(const char * p)2912ec7644aSSerapheim Dimitropoulos nvt_hash(const char *p)
2922ec7644aSSerapheim Dimitropoulos {
2932ec7644aSSerapheim Dimitropoulos 	uint32_t g, hval = 0;
2942ec7644aSSerapheim Dimitropoulos 
2952ec7644aSSerapheim Dimitropoulos 	while (*p) {
2962ec7644aSSerapheim Dimitropoulos 		hval = (hval << 4) + *p++;
2972ec7644aSSerapheim Dimitropoulos 		if ((g = (hval & 0xf0000000)) != 0)
2982ec7644aSSerapheim Dimitropoulos 			hval ^= g >> 24;
2992ec7644aSSerapheim Dimitropoulos 		hval &= ~g;
3002ec7644aSSerapheim Dimitropoulos 	}
3012ec7644aSSerapheim Dimitropoulos 	return (hval);
3022ec7644aSSerapheim Dimitropoulos }
3032ec7644aSSerapheim Dimitropoulos 
3042ec7644aSSerapheim Dimitropoulos static boolean_t
nvt_nvpair_match(nvpair_t * nvp1,nvpair_t * nvp2,uint32_t nvflag)3052ec7644aSSerapheim Dimitropoulos nvt_nvpair_match(nvpair_t *nvp1, nvpair_t *nvp2, uint32_t nvflag)
3062ec7644aSSerapheim Dimitropoulos {
3072ec7644aSSerapheim Dimitropoulos 	boolean_t match = B_FALSE;
3082ec7644aSSerapheim Dimitropoulos 	if (nvflag & NV_UNIQUE_NAME_TYPE) {
3092ec7644aSSerapheim Dimitropoulos 		if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0 &&
3102ec7644aSSerapheim Dimitropoulos 		    NVP_TYPE(nvp1) == NVP_TYPE(nvp2))
3112ec7644aSSerapheim Dimitropoulos 			match = B_TRUE;
3122ec7644aSSerapheim Dimitropoulos 	} else {
3132ec7644aSSerapheim Dimitropoulos 		ASSERT(nvflag == 0 || nvflag & NV_UNIQUE_NAME);
3142ec7644aSSerapheim Dimitropoulos 		if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0)
3152ec7644aSSerapheim Dimitropoulos 			match = B_TRUE;
3162ec7644aSSerapheim Dimitropoulos 	}
3172ec7644aSSerapheim Dimitropoulos 	return (match);
3182ec7644aSSerapheim Dimitropoulos }
3192ec7644aSSerapheim Dimitropoulos 
3202ec7644aSSerapheim Dimitropoulos static nvpair_t *
nvt_lookup_name_type(nvlist_t * nvl,const char * name,data_type_t type)3212ec7644aSSerapheim Dimitropoulos nvt_lookup_name_type(nvlist_t *nvl, const char *name, data_type_t type)
3222ec7644aSSerapheim Dimitropoulos {
3232ec7644aSSerapheim Dimitropoulos 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
3242ec7644aSSerapheim Dimitropoulos 	ASSERT(priv != NULL);
3252ec7644aSSerapheim Dimitropoulos 
3262ec7644aSSerapheim Dimitropoulos 	i_nvp_t **tab = priv->nvp_hashtable;
3272ec7644aSSerapheim Dimitropoulos 
3282ec7644aSSerapheim Dimitropoulos 	if (tab == NULL) {
3292ec7644aSSerapheim Dimitropoulos 		ASSERT3P(priv->nvp_list, ==, NULL);
3302ec7644aSSerapheim Dimitropoulos 		ASSERT0(priv->nvp_nbuckets);
3312ec7644aSSerapheim Dimitropoulos 		ASSERT0(priv->nvp_nentries);
3322ec7644aSSerapheim Dimitropoulos 		return (NULL);
3332ec7644aSSerapheim Dimitropoulos 	} else {
3342ec7644aSSerapheim Dimitropoulos 		ASSERT(priv->nvp_nbuckets != 0);
3352ec7644aSSerapheim Dimitropoulos 	}
3362ec7644aSSerapheim Dimitropoulos 
3372ec7644aSSerapheim Dimitropoulos 	uint64_t hash = nvt_hash(name);
3382ec7644aSSerapheim Dimitropoulos 	uint64_t index = hash & (priv->nvp_nbuckets - 1);
3392ec7644aSSerapheim Dimitropoulos 
3402ec7644aSSerapheim Dimitropoulos 	ASSERT3U(index, <, priv->nvp_nbuckets);
3412ec7644aSSerapheim Dimitropoulos 	i_nvp_t *entry = tab[index];
3422ec7644aSSerapheim Dimitropoulos 
3432ec7644aSSerapheim Dimitropoulos 	for (i_nvp_t *e = entry; e != NULL; e = e->nvi_hashtable_next) {
3442ec7644aSSerapheim Dimitropoulos 		if (strcmp(NVP_NAME(&e->nvi_nvp), name) == 0 &&
3452ec7644aSSerapheim Dimitropoulos 		    (type == DATA_TYPE_DONTCARE ||
3462ec7644aSSerapheim Dimitropoulos 		    NVP_TYPE(&e->nvi_nvp) == type))
3472ec7644aSSerapheim Dimitropoulos 			return (&e->nvi_nvp);
3482ec7644aSSerapheim Dimitropoulos 	}
3492ec7644aSSerapheim Dimitropoulos 	return (NULL);
3502ec7644aSSerapheim Dimitropoulos }
3512ec7644aSSerapheim Dimitropoulos 
3522ec7644aSSerapheim Dimitropoulos static nvpair_t *
nvt_lookup_name(nvlist_t * nvl,const char * name)3532ec7644aSSerapheim Dimitropoulos nvt_lookup_name(nvlist_t *nvl, const char *name)
3542ec7644aSSerapheim Dimitropoulos {
3552ec7644aSSerapheim Dimitropoulos 	return (nvt_lookup_name_type(nvl, name, DATA_TYPE_DONTCARE));
3562ec7644aSSerapheim Dimitropoulos }
3572ec7644aSSerapheim Dimitropoulos 
3582ec7644aSSerapheim Dimitropoulos static int
nvt_resize(nvpriv_t * priv,uint32_t new_size)3592ec7644aSSerapheim Dimitropoulos nvt_resize(nvpriv_t *priv, uint32_t new_size)
3602ec7644aSSerapheim Dimitropoulos {
3612ec7644aSSerapheim Dimitropoulos 	i_nvp_t **tab = priv->nvp_hashtable;
3622ec7644aSSerapheim Dimitropoulos 
3632ec7644aSSerapheim Dimitropoulos 	/*
3642ec7644aSSerapheim Dimitropoulos 	 * Migrate all the entries from the current table
3652ec7644aSSerapheim Dimitropoulos 	 * to a newly-allocated table with the new size by
3662ec7644aSSerapheim Dimitropoulos 	 * re-adjusting the pointers of their entries.
3672ec7644aSSerapheim Dimitropoulos 	 */
3682ec7644aSSerapheim Dimitropoulos 	uint32_t size = priv->nvp_nbuckets;
3692ec7644aSSerapheim Dimitropoulos 	uint32_t new_mask = new_size - 1;
3702ec7644aSSerapheim Dimitropoulos 	ASSERT(ISP2(new_size));
3712ec7644aSSerapheim Dimitropoulos 
3722ec7644aSSerapheim Dimitropoulos 	i_nvp_t **new_tab = nv_mem_zalloc(priv, new_size * sizeof (i_nvp_t *));
3732ec7644aSSerapheim Dimitropoulos 	if (new_tab == NULL)
3742ec7644aSSerapheim Dimitropoulos 		return (ENOMEM);
3752ec7644aSSerapheim Dimitropoulos 
3762ec7644aSSerapheim Dimitropoulos 	uint32_t nentries = 0;
3772ec7644aSSerapheim Dimitropoulos 	for (uint32_t i = 0; i < size; i++) {
3782ec7644aSSerapheim Dimitropoulos 		i_nvp_t *next, *e = tab[i];
3792ec7644aSSerapheim Dimitropoulos 
3802ec7644aSSerapheim Dimitropoulos 		while (e != NULL) {
3812ec7644aSSerapheim Dimitropoulos 			next = e->nvi_hashtable_next;
3822ec7644aSSerapheim Dimitropoulos 
3832ec7644aSSerapheim Dimitropoulos 			uint32_t hash = nvt_hash(NVP_NAME(&e->nvi_nvp));
3842ec7644aSSerapheim Dimitropoulos 			uint32_t index = hash & new_mask;
3852ec7644aSSerapheim Dimitropoulos 
3862ec7644aSSerapheim Dimitropoulos 			e->nvi_hashtable_next = new_tab[index];
3872ec7644aSSerapheim Dimitropoulos 			new_tab[index] = e;
3882ec7644aSSerapheim Dimitropoulos 			nentries++;
3892ec7644aSSerapheim Dimitropoulos 
3902ec7644aSSerapheim Dimitropoulos 			e = next;
3912ec7644aSSerapheim Dimitropoulos 		}
3922ec7644aSSerapheim Dimitropoulos 		tab[i] = NULL;
3932ec7644aSSerapheim Dimitropoulos 	}
3942ec7644aSSerapheim Dimitropoulos 	ASSERT3U(nentries, ==, priv->nvp_nentries);
3952ec7644aSSerapheim Dimitropoulos 
3962ec7644aSSerapheim Dimitropoulos 	nvt_tab_free(priv);
3972ec7644aSSerapheim Dimitropoulos 
3982ec7644aSSerapheim Dimitropoulos 	priv->nvp_hashtable = new_tab;
3992ec7644aSSerapheim Dimitropoulos 	priv->nvp_nbuckets = new_size;
4002ec7644aSSerapheim Dimitropoulos 	priv->nvp_nentries = nentries;
4012ec7644aSSerapheim Dimitropoulos 
4022ec7644aSSerapheim Dimitropoulos 	return (0);
4032ec7644aSSerapheim Dimitropoulos }
4042ec7644aSSerapheim Dimitropoulos 
4052ec7644aSSerapheim Dimitropoulos static boolean_t
nvt_needs_togrow(nvpriv_t * priv)4062ec7644aSSerapheim Dimitropoulos nvt_needs_togrow(nvpriv_t *priv)
4072ec7644aSSerapheim Dimitropoulos {
4082ec7644aSSerapheim Dimitropoulos 	/*
4092ec7644aSSerapheim Dimitropoulos 	 * Grow only when we have more elements than buckets
4102ec7644aSSerapheim Dimitropoulos 	 * and the # of buckets doesn't overflow.
4112ec7644aSSerapheim Dimitropoulos 	 */
4122ec7644aSSerapheim Dimitropoulos 	return (priv->nvp_nentries > priv->nvp_nbuckets &&
4132ec7644aSSerapheim Dimitropoulos 	    (UINT32_MAX >> 1) >= priv->nvp_nbuckets);
4142ec7644aSSerapheim Dimitropoulos }
4152ec7644aSSerapheim Dimitropoulos 
4162ec7644aSSerapheim Dimitropoulos /*
4172ec7644aSSerapheim Dimitropoulos  * Allocate a new table that's twice the size of the old one,
4182ec7644aSSerapheim Dimitropoulos  * and migrate all the entries from the old one to the new
4192ec7644aSSerapheim Dimitropoulos  * one by re-adjusting their pointers.
4202ec7644aSSerapheim Dimitropoulos  */
4212ec7644aSSerapheim Dimitropoulos static int
nvt_grow(nvpriv_t * priv)4222ec7644aSSerapheim Dimitropoulos nvt_grow(nvpriv_t *priv)
4232ec7644aSSerapheim Dimitropoulos {
4242ec7644aSSerapheim Dimitropoulos 	uint32_t current_size = priv->nvp_nbuckets;
4252ec7644aSSerapheim Dimitropoulos 	/* ensure we won't overflow */
4262ec7644aSSerapheim Dimitropoulos 	ASSERT3U(UINT32_MAX >> 1, >=, current_size);
4272ec7644aSSerapheim Dimitropoulos 	return (nvt_resize(priv, current_size << 1));
4282ec7644aSSerapheim Dimitropoulos }
4292ec7644aSSerapheim Dimitropoulos 
4302ec7644aSSerapheim Dimitropoulos static boolean_t
nvt_needs_toshrink(nvpriv_t * priv)4312ec7644aSSerapheim Dimitropoulos nvt_needs_toshrink(nvpriv_t *priv)
4322ec7644aSSerapheim Dimitropoulos {
4332ec7644aSSerapheim Dimitropoulos 	/*
4342ec7644aSSerapheim Dimitropoulos 	 * Shrink only when the # of elements is less than or
4352ec7644aSSerapheim Dimitropoulos 	 * equal to 1/4 the # of buckets. Never shrink less than
4362ec7644aSSerapheim Dimitropoulos 	 * nvlist_hashtable_init_size.
4372ec7644aSSerapheim Dimitropoulos 	 */
4382ec7644aSSerapheim Dimitropoulos 	ASSERT3U(priv->nvp_nbuckets, >=, nvlist_hashtable_init_size);
4392ec7644aSSerapheim Dimitropoulos 	if (priv->nvp_nbuckets == nvlist_hashtable_init_size)
4402ec7644aSSerapheim Dimitropoulos 		return (B_FALSE);
4412ec7644aSSerapheim Dimitropoulos 	return (priv->nvp_nentries <= (priv->nvp_nbuckets >> 2));
4422ec7644aSSerapheim Dimitropoulos }
4432ec7644aSSerapheim Dimitropoulos 
4442ec7644aSSerapheim Dimitropoulos /*
4452ec7644aSSerapheim Dimitropoulos  * Allocate a new table that's half the size of the old one,
4462ec7644aSSerapheim Dimitropoulos  * and migrate all the entries from the old one to the new
4472ec7644aSSerapheim Dimitropoulos  * one by re-adjusting their pointers.
4482ec7644aSSerapheim Dimitropoulos  */
4492ec7644aSSerapheim Dimitropoulos static int
nvt_shrink(nvpriv_t * priv)4502ec7644aSSerapheim Dimitropoulos nvt_shrink(nvpriv_t *priv)
4512ec7644aSSerapheim Dimitropoulos {
4522ec7644aSSerapheim Dimitropoulos 	uint32_t current_size = priv->nvp_nbuckets;
4532ec7644aSSerapheim Dimitropoulos 	/* ensure we won't overflow */
4542ec7644aSSerapheim Dimitropoulos 	ASSERT3U(current_size, >=, nvlist_hashtable_init_size);
4552ec7644aSSerapheim Dimitropoulos 	return (nvt_resize(priv, current_size >> 1));
4562ec7644aSSerapheim Dimitropoulos }
4572ec7644aSSerapheim Dimitropoulos 
4582ec7644aSSerapheim Dimitropoulos static int
nvt_remove_nvpair(nvlist_t * nvl,nvpair_t * nvp)4592ec7644aSSerapheim Dimitropoulos nvt_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
4602ec7644aSSerapheim Dimitropoulos {
4612ec7644aSSerapheim Dimitropoulos 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
4622ec7644aSSerapheim Dimitropoulos 
4632ec7644aSSerapheim Dimitropoulos 	if (nvt_needs_toshrink(priv)) {
4642ec7644aSSerapheim Dimitropoulos 		int err = nvt_shrink(priv);
4652ec7644aSSerapheim Dimitropoulos 		if (err != 0)
4662ec7644aSSerapheim Dimitropoulos 			return (err);
4672ec7644aSSerapheim Dimitropoulos 	}
4682ec7644aSSerapheim Dimitropoulos 	i_nvp_t **tab = priv->nvp_hashtable;
4692ec7644aSSerapheim Dimitropoulos 
4702ec7644aSSerapheim Dimitropoulos 	char *name = NVP_NAME(nvp);
4712ec7644aSSerapheim Dimitropoulos 	uint64_t hash = nvt_hash(name);
4722ec7644aSSerapheim Dimitropoulos 	uint64_t index = hash & (priv->nvp_nbuckets - 1);
4732ec7644aSSerapheim Dimitropoulos 
4742ec7644aSSerapheim Dimitropoulos 	ASSERT3U(index, <, priv->nvp_nbuckets);
4752ec7644aSSerapheim Dimitropoulos 	i_nvp_t *bucket = tab[index];
4762ec7644aSSerapheim Dimitropoulos 
4772ec7644aSSerapheim Dimitropoulos 	for (i_nvp_t *prev = NULL, *e = bucket;
4782ec7644aSSerapheim Dimitropoulos 	    e != NULL; prev = e, e = e->nvi_hashtable_next) {
479*b8a5bee1SAndrew Stormont 		if (nvt_nvpair_match(&e->nvi_nvp, nvp, nvl->nvl_nvflag)) {
4802ec7644aSSerapheim Dimitropoulos 			if (prev != NULL) {
4812ec7644aSSerapheim Dimitropoulos 				prev->nvi_hashtable_next =
4822ec7644aSSerapheim Dimitropoulos 				    e->nvi_hashtable_next;
4832ec7644aSSerapheim Dimitropoulos 			} else {
4842ec7644aSSerapheim Dimitropoulos 				ASSERT3P(e, ==, bucket);
4852ec7644aSSerapheim Dimitropoulos 				tab[index] = e->nvi_hashtable_next;
4862ec7644aSSerapheim Dimitropoulos 			}
4872ec7644aSSerapheim Dimitropoulos 			e->nvi_hashtable_next = NULL;
4882ec7644aSSerapheim Dimitropoulos 			priv->nvp_nentries--;
4892ec7644aSSerapheim Dimitropoulos 			break;
4902ec7644aSSerapheim Dimitropoulos 		}
4912ec7644aSSerapheim Dimitropoulos 	}
4922ec7644aSSerapheim Dimitropoulos 
4932ec7644aSSerapheim Dimitropoulos 	return (0);
4942ec7644aSSerapheim Dimitropoulos }
4952ec7644aSSerapheim Dimitropoulos 
4962ec7644aSSerapheim Dimitropoulos static int
nvt_add_nvpair(nvlist_t * nvl,nvpair_t * nvp)4972ec7644aSSerapheim Dimitropoulos nvt_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
4982ec7644aSSerapheim Dimitropoulos {
4992ec7644aSSerapheim Dimitropoulos 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
5002ec7644aSSerapheim Dimitropoulos 
5012ec7644aSSerapheim Dimitropoulos 	/* initialize nvpair table now if it doesn't exist. */
5022ec7644aSSerapheim Dimitropoulos 	if (priv->nvp_hashtable == NULL) {
5032ec7644aSSerapheim Dimitropoulos 		int err = nvt_tab_alloc(priv, nvlist_hashtable_init_size);
5042ec7644aSSerapheim Dimitropoulos 		if (err != 0)
5052ec7644aSSerapheim Dimitropoulos 			return (err);
5062ec7644aSSerapheim Dimitropoulos 	}
5072ec7644aSSerapheim Dimitropoulos 
5082ec7644aSSerapheim Dimitropoulos 	/*
5092ec7644aSSerapheim Dimitropoulos 	 * if we don't allow duplicate entries, make sure to
5102ec7644aSSerapheim Dimitropoulos 	 * unlink any existing entries from the table.
5112ec7644aSSerapheim Dimitropoulos 	 */
5122ec7644aSSerapheim Dimitropoulos 	if (nvl->nvl_nvflag != 0) {
5132ec7644aSSerapheim Dimitropoulos 		int err = nvt_remove_nvpair(nvl, nvp);
5142ec7644aSSerapheim Dimitropoulos 		if (err != 0)
5152ec7644aSSerapheim Dimitropoulos 			return (err);
5162ec7644aSSerapheim Dimitropoulos 	}
5172ec7644aSSerapheim Dimitropoulos 
5182ec7644aSSerapheim Dimitropoulos 	if (nvt_needs_togrow(priv)) {
5192ec7644aSSerapheim Dimitropoulos 		int err = nvt_grow(priv);
5202ec7644aSSerapheim Dimitropoulos 		if (err != 0)
5212ec7644aSSerapheim Dimitropoulos 			return (err);
5222ec7644aSSerapheim Dimitropoulos 	}
5232ec7644aSSerapheim Dimitropoulos 	i_nvp_t **tab = priv->nvp_hashtable;
5242ec7644aSSerapheim Dimitropoulos 
5252ec7644aSSerapheim Dimitropoulos 	char *name = NVP_NAME(nvp);
5262ec7644aSSerapheim Dimitropoulos 	uint64_t hash = nvt_hash(name);
5272ec7644aSSerapheim Dimitropoulos 	uint64_t index = hash & (priv->nvp_nbuckets - 1);
5282ec7644aSSerapheim Dimitropoulos 
5292ec7644aSSerapheim Dimitropoulos 	ASSERT3U(index, <, priv->nvp_nbuckets);
5302ec7644aSSerapheim Dimitropoulos 	i_nvp_t *bucket = tab[index];
5312ec7644aSSerapheim Dimitropoulos 
5322ec7644aSSerapheim Dimitropoulos 	/* insert link at the beginning of the bucket */
5332ec7644aSSerapheim Dimitropoulos 	i_nvp_t *new_entry = NVPAIR2I_NVP(nvp);
5342ec7644aSSerapheim Dimitropoulos 	ASSERT3P(new_entry->nvi_hashtable_next, ==, NULL);
5352ec7644aSSerapheim Dimitropoulos 	new_entry->nvi_hashtable_next = bucket;
5362ec7644aSSerapheim Dimitropoulos 	tab[index] = new_entry;
5372ec7644aSSerapheim Dimitropoulos 
5382ec7644aSSerapheim Dimitropoulos 	priv->nvp_nentries++;
5392ec7644aSSerapheim Dimitropoulos 	return (0);
5402ec7644aSSerapheim Dimitropoulos }
5412ec7644aSSerapheim Dimitropoulos 
5427c478bd9Sstevel@tonic-gate static void
nvlist_init(nvlist_t * nvl,uint32_t nvflag,nvpriv_t * priv)5437c478bd9Sstevel@tonic-gate nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate 	nvl->nvl_version = NV_VERSION;
5467c478bd9Sstevel@tonic-gate 	nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);
5477c478bd9Sstevel@tonic-gate 	nvl->nvl_priv = (uint64_t)(uintptr_t)priv;
5487c478bd9Sstevel@tonic-gate 	nvl->nvl_flag = 0;
5497c478bd9Sstevel@tonic-gate 	nvl->nvl_pad = 0;
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
552f6e214c7SGavin Maltby uint_t
nvlist_nvflag(nvlist_t * nvl)553f6e214c7SGavin Maltby nvlist_nvflag(nvlist_t *nvl)
554f6e214c7SGavin Maltby {
555f6e214c7SGavin Maltby 	return (nvl->nvl_nvflag);
556f6e214c7SGavin Maltby }
557f6e214c7SGavin Maltby 
5587c478bd9Sstevel@tonic-gate /*
5597c478bd9Sstevel@tonic-gate  * nvlist_alloc - Allocate nvlist.
5607c478bd9Sstevel@tonic-gate  */
5617c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
5627c478bd9Sstevel@tonic-gate int
nvlist_alloc(nvlist_t ** nvlp,uint_t nvflag,int kmflag)5637c478bd9Sstevel@tonic-gate nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
5667c478bd9Sstevel@tonic-gate 	return (nvlist_xalloc(nvlp, nvflag,
5677c478bd9Sstevel@tonic-gate 	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
5687c478bd9Sstevel@tonic-gate #else
5697c478bd9Sstevel@tonic-gate 	return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep));
5707c478bd9Sstevel@tonic-gate #endif
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate int
nvlist_xalloc(nvlist_t ** nvlp,uint_t nvflag,nv_alloc_t * nva)5747c478bd9Sstevel@tonic-gate nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	if (nvlp == NULL || nva == NULL)
5797c478bd9Sstevel@tonic-gate 		return (EINVAL);
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	if ((priv = nv_priv_alloc(nva)) == NULL)
5827c478bd9Sstevel@tonic-gate 		return (ENOMEM);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	if ((*nvlp = nv_mem_zalloc(priv,
5857c478bd9Sstevel@tonic-gate 	    NV_ALIGN(sizeof (nvlist_t)))) == NULL) {
5867c478bd9Sstevel@tonic-gate 		nv_mem_free(priv, priv, sizeof (nvpriv_t));
5877c478bd9Sstevel@tonic-gate 		return (ENOMEM);
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	nvlist_init(*nvlp, nvflag, priv);
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	return (0);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate  * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
5977c478bd9Sstevel@tonic-gate  */
5987c478bd9Sstevel@tonic-gate static nvpair_t *
nvp_buf_alloc(nvlist_t * nvl,size_t len)5997c478bd9Sstevel@tonic-gate nvp_buf_alloc(nvlist_t *nvl, size_t len)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6027c478bd9Sstevel@tonic-gate 	i_nvp_t *buf;
6037c478bd9Sstevel@tonic-gate 	nvpair_t *nvp;
6047c478bd9Sstevel@tonic-gate 	size_t nvsize;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	/*
6077c478bd9Sstevel@tonic-gate 	 * Allocate the buffer
6087c478bd9Sstevel@tonic-gate 	 */
6097c478bd9Sstevel@tonic-gate 	nvsize = len + offsetof(i_nvp_t, nvi_nvp);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)
6127c478bd9Sstevel@tonic-gate 		return (NULL);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	nvp = &buf->nvi_nvp;
6157c478bd9Sstevel@tonic-gate 	nvp->nvp_size = len;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	return (nvp);
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate /*
6217c478bd9Sstevel@tonic-gate  * nvp_buf_free - de-Allocate an i_nvp_t.
6227c478bd9Sstevel@tonic-gate  */
6237c478bd9Sstevel@tonic-gate static void
nvp_buf_free(nvlist_t * nvl,nvpair_t * nvp)6247c478bd9Sstevel@tonic-gate nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)
6257c478bd9Sstevel@tonic-gate {
6267c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6277c478bd9Sstevel@tonic-gate 	size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate /*
6337c478bd9Sstevel@tonic-gate  * nvp_buf_link - link a new nv pair into the nvlist.
6347c478bd9Sstevel@tonic-gate  */
6357c478bd9Sstevel@tonic-gate static void
nvp_buf_link(nvlist_t * nvl,nvpair_t * nvp)6367c478bd9Sstevel@tonic-gate nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6397c478bd9Sstevel@tonic-gate 	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	/* Put element at end of nvlist */
6427c478bd9Sstevel@tonic-gate 	if (priv->nvp_list == NULL) {
6437c478bd9Sstevel@tonic-gate 		priv->nvp_list = priv->nvp_last = curr;
6447c478bd9Sstevel@tonic-gate 	} else {
6457c478bd9Sstevel@tonic-gate 		curr->nvi_prev = priv->nvp_last;
6467c478bd9Sstevel@tonic-gate 		priv->nvp_last->nvi_next = curr;
6477c478bd9Sstevel@tonic-gate 		priv->nvp_last = curr;
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate  * nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
6537c478bd9Sstevel@tonic-gate  */
6547c478bd9Sstevel@tonic-gate static void
nvp_buf_unlink(nvlist_t * nvl,nvpair_t * nvp)6557c478bd9Sstevel@tonic-gate nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6587c478bd9Sstevel@tonic-gate 	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	/*
6617c478bd9Sstevel@tonic-gate 	 * protect nvlist_next_nvpair() against walking on freed memory.
6627c478bd9Sstevel@tonic-gate 	 */
6637c478bd9Sstevel@tonic-gate 	if (priv->nvp_curr == curr)
6647c478bd9Sstevel@tonic-gate 		priv->nvp_curr = curr->nvi_next;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if (curr == priv->nvp_list)
6677c478bd9Sstevel@tonic-gate 		priv->nvp_list = curr->nvi_next;
6687c478bd9Sstevel@tonic-gate 	else
6697c478bd9Sstevel@tonic-gate 		curr->nvi_prev->nvi_next = curr->nvi_next;
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	if (curr == priv->nvp_last)
6727c478bd9Sstevel@tonic-gate 		priv->nvp_last = curr->nvi_prev;
6737c478bd9Sstevel@tonic-gate 	else
6747c478bd9Sstevel@tonic-gate 		curr->nvi_next->nvi_prev = curr->nvi_prev;
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate /*
6787c478bd9Sstevel@tonic-gate  * take a nvpair type and number of elements and make sure the are valid
6797c478bd9Sstevel@tonic-gate  */
6807c478bd9Sstevel@tonic-gate static int
i_validate_type_nelem(data_type_t type,uint_t nelem)6817c478bd9Sstevel@tonic-gate i_validate_type_nelem(data_type_t type, uint_t nelem)
6827c478bd9Sstevel@tonic-gate {
6837c478bd9Sstevel@tonic-gate 	switch (type) {
6847c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN:
6857c478bd9Sstevel@tonic-gate 		if (nelem != 0)
6867c478bd9Sstevel@tonic-gate 			return (EINVAL);
6877c478bd9Sstevel@tonic-gate 		break;
6887c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_VALUE:
6897c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE:
6907c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8:
6917c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8:
6927c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16:
6937c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16:
6947c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32:
6957c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32:
6967c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64:
6977c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64:
6987c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING:
6997c478bd9Sstevel@tonic-gate 	case DATA_TYPE_HRTIME:
7007c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
701825ba0f2Srobj #if !defined(_KERNEL)
702825ba0f2Srobj 	case DATA_TYPE_DOUBLE:
703825ba0f2Srobj #endif
7047c478bd9Sstevel@tonic-gate 		if (nelem != 1)
7057c478bd9Sstevel@tonic-gate 			return (EINVAL);
7067c478bd9Sstevel@tonic-gate 		break;
7077c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_ARRAY:
7087c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY:
7097c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT8_ARRAY:
7107c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT8_ARRAY:
7117c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16_ARRAY:
7127c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16_ARRAY:
7137c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32_ARRAY:
7147c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32_ARRAY:
7157c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64_ARRAY:
7167c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64_ARRAY:
7177c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING_ARRAY:
7187c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY:
7197c478bd9Sstevel@tonic-gate 		/* we allow arrays with 0 elements */
7207c478bd9Sstevel@tonic-gate 		break;
7217c478bd9Sstevel@tonic-gate 	default:
7227c478bd9Sstevel@tonic-gate 		return (EINVAL);
7237c478bd9Sstevel@tonic-gate 	}
7247c478bd9Sstevel@tonic-gate 	return (0);
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate  * Verify nvp_name_sz and check the name string length.
7297c478bd9Sstevel@tonic-gate  */
7307c478bd9Sstevel@tonic-gate static int
i_validate_nvpair_name(nvpair_t * nvp)7317c478bd9Sstevel@tonic-gate i_validate_nvpair_name(nvpair_t *nvp)
7327c478bd9Sstevel@tonic-gate {
7337c478bd9Sstevel@tonic-gate 	if ((nvp->nvp_name_sz <= 0) ||
7347c478bd9Sstevel@tonic-gate 	    (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))
7357c478bd9Sstevel@tonic-gate 		return (EFAULT);
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	/* verify the name string, make sure its terminated */
7387c478bd9Sstevel@tonic-gate 	if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')
7397c478bd9Sstevel@tonic-gate 		return (EFAULT);
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate static int
i_validate_nvpair_value(data_type_t type,uint_t nelem,const void * data)7457c478bd9Sstevel@tonic-gate i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)
7467c478bd9Sstevel@tonic-gate {
7477c478bd9Sstevel@tonic-gate 	switch (type) {
7487c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_VALUE:
7497c478bd9Sstevel@tonic-gate 		if (*(boolean_t *)data != B_TRUE &&
7507c478bd9Sstevel@tonic-gate 		    *(boolean_t *)data != B_FALSE)
7517c478bd9Sstevel@tonic-gate 			return (EINVAL);
7527c478bd9Sstevel@tonic-gate 		break;
7537c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BOOLEAN_ARRAY: {
7547c478bd9Sstevel@tonic-gate 		int i;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		for (i = 0; i < nelem; i++)
7577c478bd9Sstevel@tonic-gate 			if (((boolean_t *)data)[i] != B_TRUE &&
7587c478bd9Sstevel@tonic-gate 			    ((boolean_t *)data)[i] != B_FALSE)
7597c478bd9Sstevel@tonic-gate 				return (EINVAL);
7607c478bd9Sstevel@tonic-gate 		break;
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 	default:
7637c478bd9Sstevel@tonic-gate 		break;
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	return (0);
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate /*
7707c478bd9Sstevel@tonic-gate  * This function takes a pointer to what should be a nvpair and it's size
7717c478bd9Sstevel@tonic-gate  * and then verifies that all the nvpair fields make sense and can be
7727c478bd9Sstevel@tonic-gate  * trusted.  This function is used when decoding packed nvpairs.
7737c478bd9Sstevel@tonic-gate  */
7747c478bd9Sstevel@tonic-gate static int
i_validate_nvpair(nvpair_t * nvp)7757c478bd9Sstevel@tonic-gate i_validate_nvpair(nvpair_t *nvp)
7767c478bd9Sstevel@tonic-gate {
7777c478bd9Sstevel@tonic-gate 	data_type_t type = NVP_TYPE(nvp);
7787c478bd9Sstevel@tonic-gate 	int size1, size2;
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	/* verify nvp_name_sz, check the name string length */
7817c478bd9Sstevel@tonic-gate 	if (i_validate_nvpair_name(nvp) != 0)
7827c478bd9Sstevel@tonic-gate 		return (EFAULT);
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)
7857c478bd9Sstevel@tonic-gate 		return (EFAULT);
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	/*
7887c478bd9Sstevel@tonic-gate 	 * verify nvp_type, nvp_value_elem, and also possibly
7897c478bd9Sstevel@tonic-gate 	 * verify string values and get the value size.
7907c478bd9Sstevel@tonic-gate 	 */
7917c478bd9Sstevel@tonic-gate 	size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));
7927c478bd9Sstevel@tonic-gate 	size1 = nvp->nvp_size - NVP_VALOFF(nvp);
7937c478bd9Sstevel@tonic-gate 	if (size2 < 0 || size1 != NV_ALIGN(size2))
7947c478bd9Sstevel@tonic-gate 		return (EFAULT);
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	return (0);
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate static int
nvlist_copy_pairs(nvlist_t * snvl,nvlist_t * dnvl)8007c478bd9Sstevel@tonic-gate nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl)
8017c478bd9Sstevel@tonic-gate {
8027c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
8037c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)
8067c478bd9Sstevel@tonic-gate 		return (EINVAL);
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
8097c478bd9Sstevel@tonic-gate 		nvpair_t *nvp = &curr->nvi_nvp;
8107c478bd9Sstevel@tonic-gate 		int err;
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 		if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),
8137c478bd9Sstevel@tonic-gate 		    NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)
8147c478bd9Sstevel@tonic-gate 			return (err);
8157c478bd9Sstevel@tonic-gate 	}
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	return (0);
8187c478bd9Sstevel@tonic-gate }
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate /*
8217c478bd9Sstevel@tonic-gate  * Frees all memory allocated for an nvpair (like embedded lists) with
8227c478bd9Sstevel@tonic-gate  * the exception of the nvpair buffer itself.
8237c478bd9Sstevel@tonic-gate  */
8247c478bd9Sstevel@tonic-gate static void
nvpair_free(nvpair_t * nvp)8257c478bd9Sstevel@tonic-gate nvpair_free(nvpair_t *nvp)
8267c478bd9Sstevel@tonic-gate {
8277c478bd9Sstevel@tonic-gate 	switch (NVP_TYPE(nvp)) {
8287c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST:
8297c478bd9Sstevel@tonic-gate 		nvlist_free(EMBEDDED_NVL(nvp));
8307c478bd9Sstevel@tonic-gate 		break;
8317c478bd9Sstevel@tonic-gate 	case DATA_TYPE_NVLIST_ARRAY: {
8327c478bd9Sstevel@tonic-gate 		nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
8337c478bd9Sstevel@tonic-gate 		int i;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 		for (i = 0; i < NVP_NELEM(nvp); i++)
836aab83bb8SJosef 'Jeff' Sipek 			nvlist_free(nvlp[i]);
8377c478bd9Sstevel@tonic-gate 		break;
8387c478bd9Sstevel@tonic-gate 	}
8397c478bd9Sstevel@tonic-gate 	default:
8407c478bd9Sstevel@tonic-gate 		break;
8417c478bd9Sstevel@tonic-gate 	}
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate /*
8457c478bd9Sstevel@tonic-gate  * nvlist_free - free an unpacked nvlist
8467c478bd9Sstevel@tonic-gate  */
8477c478bd9Sstevel@tonic-gate void
nvlist_free(nvlist_t * nvl)8487c478bd9Sstevel@tonic-gate nvlist_free(nvlist_t *nvl)
8497c478bd9Sstevel@tonic-gate {
8507c478bd9Sstevel@tonic-gate 	nvpriv_t *priv;
8517c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	if (nvl == NULL ||
8547c478bd9Sstevel@tonic-gate 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
8557c478bd9Sstevel@tonic-gate 		return;
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	/*
8587c478bd9Sstevel@tonic-gate 	 * Unpacked nvlist are linked through i_nvp_t
8597c478bd9Sstevel@tonic-gate 	 */
8607c478bd9Sstevel@tonic-gate 	curr = priv->nvp_list;
8617c478bd9Sstevel@tonic-gate 	while (curr != NULL) {
8627c478bd9Sstevel@tonic-gate 		nvpair_t *nvp = &curr->nvi_nvp;
8637c478bd9Sstevel@tonic-gate 		curr = curr->nvi_next;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 		nvpair_free(nvp);
8667c478bd9Sstevel@tonic-gate 		nvp_buf_free(nvl, nvp);
8677c478bd9Sstevel@tonic-gate 	}
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	if (!(priv->nvp_stat & NV_STAT_EMBEDDED))
8707c478bd9Sstevel@tonic-gate 		nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));
8717c478bd9Sstevel@tonic-gate 	else
8725ad82045Snd 		nvl->nvl_priv = 0;
8737c478bd9Sstevel@tonic-gate 
8742ec7644aSSerapheim Dimitropoulos 	nvt_tab_free(priv);
8757c478bd9Sstevel@tonic-gate 	nv_mem_free(priv, priv, sizeof (nvpriv_t));
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate static int
nvlist_contains_nvp(nvlist_t * nvl,nvpair_t * nvp)8797c478bd9Sstevel@tonic-gate nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
8827c478bd9Sstevel@tonic-gate 	i_nvp_t *curr;
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	if (nvp == NULL)
8857c478bd9Sstevel@tonic-gate 		return (0);
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
8887c478bd9Sstevel@tonic-gate 		if (&curr->nvi_nvp == nvp)
8897c478bd9Sstevel@tonic-gate 			return (1);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	return (0);
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate /*
8957c478bd9Sstevel@tonic-gate  * Make a copy of nvlist
8967c478bd9Sstevel@tonic-gate  */
8977c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
8987c478bd9Sstevel@tonic-gate int
nvlist_dup(nvlist_t * nvl,nvlist_t ** nvlp,int kmflag)8997c478bd9Sstevel@tonic-gate nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag)
9007c478bd9Sstevel@tonic-gate {
9017c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && !defined(_BOOT)
9027c478bd9Sstevel@tonic-gate 	return (nvlist_xdup(nvl, nvlp,
9037c478bd9Sstevel@tonic-gate 	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
9047c478bd9Sstevel@tonic-gate #else
9057c478bd9Sstevel@tonic-gate 	return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep));
9067c478bd9Sstevel@tonic-gate #endif
9077c478bd9Sstevel@tonic-gate }
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate int
nvlist_xdup(nvlist_t * nvl,nvlist_t ** nvlp,nv_alloc_t * nva)9107c478bd9Sstevel@tonic-gate nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)
9117c478bd9Sstevel@tonic-gate {
9127c478bd9Sstevel@tonic-gate 	int err;
9133bb79becSeschrock 	nvlist_t *ret;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	if (nvl == NULL || nvlp == NULL)
9167c478bd9Sstevel@tonic-gate 		return (EINVAL);
9177c478bd9Sstevel@tonic-gate 
9183bb79becSeschrock 	if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0)
9197c478bd9Sstevel@tonic-gate 		return (err);
9207c478bd9Sstevel@tonic-gate 
9213bb79becSeschrock 	if ((err = nvlist_copy_pairs(nvl, ret)) != 0)
9223bb79becSeschrock 		nvlist_free(ret);
9233bb79becSeschrock 	else
9243bb79becSeschrock 		*nvlp = ret;
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 	return (err);
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate /*
9307c478bd9Sstevel@tonic-gate  * Remove all with matching name
9317c478bd9Sstevel@tonic-gate  */
9327c478bd9Sstevel@tonic-gate int
nvlist_remove_all(nvlist_t * nvl,const char * name)933