17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
53bb79beeschrock * Common Development and Distribution License (the "License").
63bb79beeschrock * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
21d9638e5mws
227c478bdstevel@tonic-gate/*
23f6e214cGavin Maltby * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
24843c211Matthew Ahrens * Copyright (c) 2015, 2017 by Delphix. All rights reserved.
25b8a5beeAndrew Stormont * Copyright 2018 RackTop Systems.
267c478bdstevel@tonic-gate */
277c478bdstevel@tonic-gate
287c478bdstevel@tonic-gate#include <sys/stropts.h>
297c478bdstevel@tonic-gate#include <sys/debug.h>
307c478bdstevel@tonic-gate#include <sys/isa_defs.h>
317c478bdstevel@tonic-gate#include <sys/int_limits.h>
327c478bdstevel@tonic-gate#include <sys/nvpair.h>
337c478bdstevel@tonic-gate#include <sys/nvpair_impl.h>
347c478bdstevel@tonic-gate#include <rpc/types.h>
357c478bdstevel@tonic-gate#include <rpc/xdr.h>
367c478bdstevel@tonic-gate
377c478bdstevel@tonic-gate#if defined(_KERNEL) && !defined(_BOOT)
387c478bdstevel@tonic-gate#include <sys/varargs.h>
39602ca9ecth#include <sys/ddi.h>
40602ca9ecth#include <sys/sunddi.h>
415c5f137Richard Lowe#include <sys/sysmacros.h>
427c478bdstevel@tonic-gate#else
437c478bdstevel@tonic-gate#include <stdarg.h>
44602ca9ecth#include <stdlib.h>
45602ca9ecth#include <string.h>
467c478bdstevel@tonic-gate#include <strings.h>
475c5f137Richard Lowe#include <stddef.h>
487c478bdstevel@tonic-gate#endif
497c478bdstevel@tonic-gate
50602ca9ecth#define	skip_whitespace(p)	while ((*(p) == ' ') || (*(p) == '\t')) p++
517c478bdstevel@tonic-gate
527c478bdstevel@tonic-gate/*
537c478bdstevel@tonic-gate * nvpair.c - Provides kernel & userland interfaces for manipulating
547c478bdstevel@tonic-gate *	name-value pairs.
557c478bdstevel@tonic-gate *
567c478bdstevel@tonic-gate * Overview Diagram
577c478bdstevel@tonic-gate *
587c478bdstevel@tonic-gate *  +--------------+
597c478bdstevel@tonic-gate *  |  nvlist_t    |
607c478bdstevel@tonic-gate *  |--------------|
617c478bdstevel@tonic-gate *  | nvl_version  |
627c478bdstevel@tonic-gate *  | nvl_nvflag   |
637c478bdstevel@tonic-gate *  | nvl_priv    -+-+
647c478bdstevel@tonic-gate *  | nvl_flag     | |
657c478bdstevel@tonic-gate *  | nvl_pad      | |
667c478bdstevel@tonic-gate *  +--------------+ |
677c478bdstevel@tonic-gate *                   V
687c478bdstevel@tonic-gate *      +--------------+      last i_nvp in list
697c478bdstevel@tonic-gate *      | nvpriv_t     |  +--------------------->
707c478bdstevel@tonic-gate *      |--------------|  |
717c478bdstevel@tonic-gate *   +--+- nvp_list    |  |   +------------+
727c478bdstevel@tonic-gate *   |  |  nvp_last   -+--+   + nv_alloc_t |
737c478bdstevel@tonic-gate *   |  |  nvp_curr    |      |------------|
747c478bdstevel@tonic-gate *   |  |  nvp_nva    -+----> | nva_ops    |
757c478bdstevel@tonic-gate *   |  |  nvp_stat    |      | nva_arg    |
767c478bdstevel@tonic-gate *   |  +--------------+      +------------+
777c478bdstevel@tonic-gate *   |
787c478bdstevel@tonic-gate *   +-------+
797c478bdstevel@tonic-gate *           V
807c478bdstevel@tonic-gate *   +---------------------+      +-------------------+
817c478bdstevel@tonic-gate *   |  i_nvp_t            |  +-->|  i_nvp_t          |  +-->
827c478bdstevel@tonic-gate *   |---------------------|  |   |-------------------|  |
837c478bdstevel@tonic-gate *   | nvi_next           -+--+   | nvi_next         -+--+
847c478bdstevel@tonic-gate *   | nvi_prev (NULL)     | <----+ nvi_prev          |
857c478bdstevel@tonic-gate *   | . . . . . . . . . . |      | . . . . . . . . . |
867c478bdstevel@tonic-gate *   | nvp (nvpair_t)      |      | nvp (nvpair_t)    |
877c478bdstevel@tonic-gate *   |  - nvp_size         |      |  - nvp_size       |
887c478bdstevel@tonic-gate *   |  - nvp_name_sz      |      |  - nvp_name_sz    |
897c478bdstevel@tonic-gate *   |  - nvp_value_elem   |      |  - nvp_value_elem |
907c478bdstevel@tonic-gate *   |  - nvp_type         |      |  - nvp_type       |
917c478bdstevel@tonic-gate *   |  - data ...         |      |  - data ...       |
927c478bdstevel@tonic-gate *   +---------------------+      +-------------------+
937c478bdstevel@tonic-gate *
947c478bdstevel@tonic-gate *
957c478bdstevel@tonic-gate *
967c478bdstevel@tonic-gate *   +---------------------+              +---------------------+
977c478bdstevel@tonic-gate *   |  i_nvp_t            |  +-->    +-->|  i_nvp_t (last)     |
987c478bdstevel@tonic-gate *   |---------------------|  |       |   |---------------------|
997c478bdstevel@tonic-gate *   |  nvi_next          -+--+ ... --+   | nvi_next (NULL)     |
1007c478bdstevel@tonic-gate * <-+- nvi_prev           |<-- ...  <----+ nvi_prev            |
1017c478bdstevel@tonic-gate *   | . . . . . . . . .   |              | . . . . . . . . .   |
1027c478bdstevel@tonic-gate *   | nvp (nvpair_t)      |              | nvp (nvpair_t)      |
1037c478bdstevel@tonic-gate *   |  - nvp_size         |              |  - nvp_size         |
1047c478bdstevel@tonic-gate *   |  - nvp_name_sz      |              |  - nvp_name_sz      |
1057c478bdstevel@tonic-gate *   |  - nvp_value_elem   |              |  - nvp_value_elem   |
1067c478bdstevel@tonic-gate *   |  - DATA_TYPE_NVLIST |              |  - nvp_type         |
1077c478bdstevel@tonic-gate *   |  - data (embedded)  |              |  - data ...         |
1087c478bdstevel@tonic-gate *   |    nvlist name      |              +---------------------+
1097c478bdstevel@tonic-gate *   |  +--------------+   |
1107c478bdstevel@tonic-gate *   |  |  nvlist_t    |   |
1117c478bdstevel@tonic-gate *   |  |--------------|   |
1127c478bdstevel@tonic-gate *   |  | nvl_version  |   |
1137c478bdstevel@tonic-gate *   |  | nvl_nvflag   |   |
1147c478bdstevel@tonic-gate *   |  | nvl_priv   --+---+---->
1157c478bdstevel@tonic-gate *   |  | nvl_flag     |   |
1167c478bdstevel@tonic-gate *   |  | nvl_pad      |   |
1177c478bdstevel@tonic-gate *   |  +--------------+   |
1187c478bdstevel@tonic-gate *   +---------------------+
1197c478bdstevel@tonic-gate *
1207c478bdstevel@tonic-gate *
1217c478bdstevel@tonic-gate * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will
1227c478bdstevel@tonic-gate * allow value to be aligned on 8 byte boundary
1237c478bdstevel@tonic-gate *
1247c478bdstevel@tonic-gate * name_len is the length of the name string including the null terminator
1257c478bdstevel@tonic-gate * so it must be >= 1
1267c478bdstevel@tonic-gate */
1277c478bdstevel@tonic-gate#define	NVP_SIZE_CALC(name_len, data_len) \
1287c478bdstevel@tonic-gate	(NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))
1297c478bdstevel@tonic-gate
1307c478bdstevel@tonic-gatestatic int i_get_value_size(data_type_t type, const void *data, uint_t nelem);
1317c478bdstevel@tonic-gatestatic int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1327c478bdstevel@tonic-gate    uint_t nelem, const void *data);
1337c478bdstevel@tonic-gate
1347c478bdstevel@tonic-gate#define	NV_STAT_EMBEDDED	0x1
1357c478bdstevel@tonic-gate#define	EMBEDDED_NVL(nvp)	((nvlist_t *)(void *)NVP_VALUE(nvp))
1367c478bdstevel@tonic-gate#define	EMBEDDED_NVL_ARRAY(nvp)	((nvlist_t **)(void *)NVP_VALUE(nvp))
1377c478bdstevel@tonic-gate
1387c478bdstevel@tonic-gate#define	NVP_VALOFF(nvp)	(NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))
1397c478bdstevel@tonic-gate#define	NVPAIR2I_NVP(nvp) \
1407c478bdstevel@tonic-gate	((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))
1417c478bdstevel@tonic-gate
1429ca527cMatthew Ahrens#ifdef _KERNEL
1439ca527cMatthew Ahrensint nvpair_max_recursion = 20;
1449ca527cMatthew Ahrens#else
1459ca527cMatthew Ahrensint nvpair_max_recursion = 100;
1469ca527cMatthew Ahrens#endif
1477c478bdstevel@tonic-gate
1482ec7644Serapheim Dimitropoulosuint64_t nvlist_hashtable_init_size = (1 << 4);
1492ec7644Serapheim Dimitropoulos
1507c478bdstevel@tonic-gateint
1517c478bdstevel@tonic-gatenv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)
1527c478bdstevel@tonic-gate{
1537c478bdstevel@tonic-gate	va_list valist;
1547c478bdstevel@tonic-gate	int err = 0;
1557c478bdstevel@tonic-gate
1567c478bdstevel@tonic-gate	nva->nva_ops = nvo;
1577c478bdstevel@tonic-gate	nva->nva_arg = NULL;
1587c478bdstevel@tonic-gate
1597c478bdstevel@tonic-gate	va_start(valist, nvo);
1607c478bdstevel@tonic-gate	if (nva->nva_ops->nv_ao_init != NULL)
1617c478bdstevel@tonic-gate		err = nva->nva_ops->nv_ao_init(nva, valist);
1627c478bdstevel@tonic-gate	va_end(valist);
1637c478bdstevel@tonic-gate
1647c478bdstevel@tonic-gate	return (err);
1657c478bdstevel@tonic-gate}
1667c478bdstevel@tonic-gate
1677c478bdstevel@tonic-gatevoid
1687c478bdstevel@tonic-gatenv_alloc_reset(nv_alloc_t *nva)
1697c478bdstevel@tonic-gate{
1707c478bdstevel@tonic-gate	if (nva->nva_ops->nv_ao_reset != NULL)
1717c478bdstevel@tonic-gate		nva->nva_ops->nv_ao_reset(nva);
1727c478bdstevel@tonic-gate}
1737c478bdstevel@tonic-gate
1747c478bdstevel@tonic-gatevoid
1757c478bdstevel@tonic-gatenv_alloc_fini(nv_alloc_t *nva)
1767c478bdstevel@tonic-gate{
1777c478bdstevel@tonic-gate	if (nva->nva_ops->nv_ao_fini != NULL)
1787c478bdstevel@tonic-gate		nva->nva_ops->nv_ao_fini(nva);
1797c478bdstevel@tonic-gate}
1807c478bdstevel@tonic-gate
1817c478bdstevel@tonic-gatenv_alloc_t *
1827c478bdstevel@tonic-gatenvlist_lookup_nv_alloc(nvlist_t *nvl)
1837c478bdstevel@tonic-gate{
1847c478bdstevel@tonic-gate	nvpriv_t *priv;
1857c478bdstevel@tonic-gate
1867c478bdstevel@tonic-gate	if (nvl == NULL ||
1877c478bdstevel@tonic-gate	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1887c478bdstevel@tonic-gate		return (NULL);
1897c478bdstevel@tonic-gate
1907c478bdstevel@tonic-gate	return (priv->nvp_nva);
1917c478bdstevel@tonic-gate}
1927c478bdstevel@tonic-gate
1937c478bdstevel@tonic-gatestatic void *
1947c478bdstevel@tonic-gatenv_mem_zalloc(nvpriv_t *nvp, size_t size)
1957c478bdstevel@tonic-gate{
1967c478bdstevel@tonic-gate	nv_alloc_t *nva = nvp->nvp_nva;
1977c478bdstevel@tonic-gate	void *buf;
1987c478bdstevel@tonic-gate
1997c478bdstevel@tonic-gate	if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)
2007c478bdstevel@tonic-gate		bzero(buf, size);
2017c478bdstevel@tonic-gate
2027c478bdstevel@tonic-gate	return (buf);
2037c478bdstevel@tonic-gate}
2047c478bdstevel@tonic-gate
2057c478bdstevel@tonic-gatestatic void
2067c478bdstevel@tonic-gatenv_mem_free(nvpriv_t *nvp, void *buf, size_t size)
2077c478bdstevel@tonic-gate{
2087c478bdstevel@tonic-gate	nv_alloc_t *nva = nvp->nvp_nva;
2097c478bdstevel@tonic-gate
2107c478bdstevel@tonic-gate	nva->nva_ops->nv_ao_free(nva, buf, size);
2117c478bdstevel@tonic-gate}
2127c478bdstevel@tonic-gate
2137c478bdstevel@tonic-gatestatic void
2147c478bdstevel@tonic-gatenv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)
2157c478bdstevel@tonic-gate{
216c5904d1eschrock	bzero(priv, sizeof (nvpriv_t));
2177c478bdstevel@tonic-gate
2187c478bdstevel@tonic-gate	priv->nvp_nva = nva;
2197c478bdstevel@tonic-gate	priv->nvp_stat = stat;
2207c478bdstevel@tonic-gate}
2217c478bdstevel@tonic-gate
2227c478bdstevel@tonic-gatestatic nvpriv_t *
2237c478bdstevel@tonic-gatenv_priv_alloc(nv_alloc_t *nva)
2247c478bdstevel@tonic-gate{
2257c478bdstevel@tonic-gate	nvpriv_t *priv;
2267c478bdstevel@tonic-gate
2277c478bdstevel@tonic-gate	/*
2287c478bdstevel@tonic-gate	 * nv_mem_alloc() cannot called here because it needs the priv
2297c478bdstevel@tonic-gate	 * argument.
2307c478bdstevel@tonic-gate	 */
2317c478bdstevel@tonic-gate	if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)
2327c478bdstevel@tonic-gate		return (NULL);
2337c478bdstevel@tonic-gate
2347c478bdstevel@tonic-gate	nv_priv_init(priv, nva, 0);
2357c478bdstevel@tonic-gate
2367c478bdstevel@tonic-gate	return (priv);
2377c478bdstevel@tonic-gate}
2387c478bdstevel@tonic-gate
2397c478bdstevel@tonic-gate/*
2407c478bdstevel@tonic-gate * Embedded lists need their own nvpriv_t's.  We create a new
2417c478bdstevel@tonic-gate * nvpriv_t using the parameters and allocator from the parent
2427c478bdstevel@tonic-gate * list's nvpriv_t.
2437c478bdstevel@tonic-gate */
2447c478bdstevel@tonic-gatestatic nvpriv_t *
2457c478bdstevel@tonic-gatenv_priv_alloc_embedded(nvpriv_t *priv)
2467c478bdstevel@tonic-gate{
2477c478bdstevel@tonic-gate	nvpriv_t *emb_priv;
2487c478bdstevel@tonic-gate
2497c478bdstevel@tonic-gate	if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)
2507c478bdstevel@tonic-gate		return (NULL);
2517c478bdstevel@tonic-gate
2527c478bdstevel@tonic-gate	nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);
2537c478bdstevel@tonic-gate
2547c478bdstevel@tonic-gate	return (emb_priv);
2557c478bdstevel@tonic-gate}
2567c478bdstevel@tonic-gate
2572ec7644Serapheim Dimitropoulosstatic int
2582ec7644Serapheim Dimitropoulosnvt_tab_alloc(nvpriv_t *priv, uint64_t buckets)
2592ec7644Serapheim Dimitropoulos{
2602ec7644Serapheim Dimitropoulos	ASSERT3P(priv->nvp_hashtable, ==, NULL);
2612ec7644Serapheim Dimitropoulos	ASSERT0(priv->nvp_nbuckets);
2622ec7644Serapheim Dimitropoulos	ASSERT0(priv->nvp_nentries);
2632ec7644Serapheim Dimitropoulos
2642ec7644Serapheim Dimitropoulos	i_nvp_t **tab = nv_mem_zalloc(priv, buckets * sizeof (i_nvp_t *));
2652ec7644Serapheim Dimitropoulos	if (tab == NULL)
2662ec7644Serapheim Dimitropoulos		return (ENOMEM);
2672ec7644Serapheim Dimitropoulos
2682ec7644Serapheim Dimitropoulos	priv->nvp_hashtable = tab;
2692ec7644Serapheim Dimitropoulos	priv->nvp_nbuckets = buckets;
2702ec7644Serapheim Dimitropoulos	return (0);
2712ec7644Serapheim Dimitropoulos}
2722ec7644Serapheim Dimitropoulos
2732ec7644Serapheim Dimitropoulosstatic void
2742ec7644Serapheim Dimitropoulosnvt_tab_free(nvpriv_t *priv)
2752ec7644Serapheim Dimitropoulos{
2762ec7644Serapheim Dimitropoulos	i_nvp_t **tab = priv->nvp_hashtable;
2772ec7644Serapheim Dimitropoulos	if (tab == NULL) {
2782ec7644Serapheim Dimitropoulos		ASSERT0(priv->nvp_nbuckets);
2792ec7644Serapheim Dimitropoulos		ASSERT0(priv->nvp_nentries);
2802ec7644Serapheim Dimitropoulos		return;
2812ec7644Serapheim Dimitropoulos	}
2822ec7644Serapheim Dimitropoulos
2832ec7644Serapheim Dimitropoulos	nv_mem_free(priv, tab, priv->nvp_nbuckets * sizeof (i_nvp_t *));
2842ec7644Serapheim Dimitropoulos
2852ec7644Serapheim Dimitropoulos	priv->nvp_hashtable = NULL;
2862ec7644Serapheim Dimitropoulos	priv->nvp_nbuckets = 0;
2872ec7644Serapheim Dimitropoulos	priv->nvp_nentries = 0;
2882ec7644Serapheim Dimitropoulos}
2892ec7644Serapheim Dimitropoulos
2902ec7644Serapheim Dimitropoulosstatic uint32_t
2912ec7644Serapheim Dimitropoulosnvt_hash(const char *p)
2922ec7644Serapheim Dimitropoulos{
2932ec7644Serapheim Dimitropoulos	uint32_t g, hval = 0;
2942ec7644Serapheim Dimitropoulos
2952ec7644Serapheim Dimitropoulos	while (*p) {
2962ec7644Serapheim Dimitropoulos		hval = (hval << 4) + *p++;
2972ec7644Serapheim Dimitropoulos		if ((g = (hval & 0xf0000000)) != 0)
2982ec7644Serapheim Dimitropoulos			hval ^= g >> 24;
2992ec7644Serapheim Dimitropoulos		hval &= ~g;
3002ec7644Serapheim Dimitropoulos	}
3012ec7644Serapheim Dimitropoulos	return (hval);
3022ec7644Serapheim Dimitropoulos}
3032ec7644Serapheim Dimitropoulos
3042ec7644Serapheim Dimitropoulosstatic boolean_t
3052ec7644Serapheim Dimitropoulosnvt_nvpair_match(nvpair_t *nvp1, nvpair_t *nvp2, uint32_t nvflag)
3062ec7644Serapheim Dimitropoulos{
3072ec7644Serapheim Dimitropoulos	boolean_t match = B_FALSE;
3082ec7644Serapheim Dimitropoulos	if (nvflag & NV_UNIQUE_NAME_TYPE) {
3092ec7644Serapheim Dimitropoulos		if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0 &&
3102ec7644Serapheim Dimitropoulos		    NVP_TYPE(nvp1) == NVP_TYPE(nvp2))
3112ec7644Serapheim Dimitropoulos			match = B_TRUE;
3122ec7644Serapheim Dimitropoulos	} else {
3132ec7644Serapheim Dimitropoulos		ASSERT(nvflag == 0 || nvflag & NV_UNIQUE_NAME);
3142ec7644Serapheim Dimitropoulos		if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0)
3152ec7644Serapheim Dimitropoulos			match = B_TRUE;
3162ec7644Serapheim Dimitropoulos	}
3172ec7644Serapheim Dimitropoulos	return (match);
3182ec7644Serapheim Dimitropoulos}
3192ec7644Serapheim Dimitropoulos
3202ec7644Serapheim Dimitropoulosstatic nvpair_t *
3212ec7644Serapheim Dimitropoulosnvt_lookup_name_type(nvlist_t *nvl, const char *name, data_type_t type)
3222ec7644Serapheim Dimitropoulos{
3232ec7644Serapheim Dimitropoulos	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
3242ec7644Serapheim Dimitropoulos	ASSERT(priv != NULL);
3252ec7644Serapheim Dimitropoulos
3262ec7644Serapheim Dimitropoulos	i_nvp_t **tab = priv->nvp_hashtable;
3272ec7644Serapheim Dimitropoulos
3282ec7644Serapheim Dimitropoulos	if (tab == NULL) {
3292ec7644Serapheim Dimitropoulos		ASSERT3P(priv->nvp_list, ==, NULL);
3302ec7644Serapheim Dimitropoulos		ASSERT0(priv->nvp_nbuckets);
3312ec7644Serapheim Dimitropoulos		ASSERT0(priv->nvp_nentries);
3322ec7644Serapheim Dimitropoulos		return (NULL);
3332ec7644Serapheim Dimitropoulos	} else {
3342ec7644Serapheim Dimitropoulos		ASSERT(priv->nvp_nbuckets != 0);
3352ec7644Serapheim Dimitropoulos	}
3362ec7644Serapheim Dimitropoulos
3372ec7644Serapheim Dimitropoulos	uint64_t hash = nvt_hash(name);
3382ec7644Serapheim Dimitropoulos	uint64_t index = hash & (priv->nvp_nbuckets - 1);
3392ec7644Serapheim Dimitropoulos
3402ec7644Serapheim Dimitropoulos	ASSERT3U(index, <, priv->nvp_nbuckets);
3412ec7644Serapheim Dimitropoulos	i_nvp_t *entry = tab[index];
3422ec7644Serapheim Dimitropoulos
3432ec7644Serapheim Dimitropoulos	for (i_nvp_t *e = entry; e != NULL; e = e->nvi_hashtable_next) {
3442ec7644Serapheim Dimitropoulos		if (strcmp(NVP_NAME(&e->nvi_nvp), name) == 0 &&
3452ec7644Serapheim Dimitropoulos		    (type == DATA_TYPE_DONTCARE ||
3462ec7644Serapheim Dimitropoulos		    NVP_TYPE(&e->nvi_nvp) == type))
3472ec7644Serapheim Dimitropoulos			return (&e->nvi_nvp);
3482ec7644Serapheim Dimitropoulos	}
3492ec7644Serapheim Dimitropoulos	return (NULL);
3502ec7644Serapheim Dimitropoulos}
3512ec7644Serapheim Dimitropoulos
3522ec7644Serapheim Dimitropoulosstatic nvpair_t *
3532ec7644Serapheim Dimitropoulosnvt_lookup_name(nvlist_t *nvl, const char *name)
3542ec7644Serapheim Dimitropoulos{
3552ec7644Serapheim Dimitropoulos	return (nvt_lookup_name_type(nvl, name, DATA_TYPE_DONTCARE));
3562ec7644Serapheim Dimitropoulos}
3572ec7644Serapheim Dimitropoulos
3582ec7644Serapheim Dimitropoulosstatic int
3592ec7644Serapheim Dimitropoulosnvt_resize(nvpriv_t *priv, uint32_t new_size)
3602ec7644Serapheim Dimitropoulos{
3612ec7644Serapheim Dimitropoulos	i_nvp_t **tab = priv->nvp_hashtable;
3622ec7644Serapheim Dimitropoulos
3632ec7644Serapheim Dimitropoulos	/*
3642ec7644Serapheim Dimitropoulos	 * Migrate all the entries from the current table
3652ec7644Serapheim Dimitropoulos	 * to a newly-allocated table with the new size by
3662ec7644Serapheim Dimitropoulos	 * re-adjusting the pointers of their entries.
3672ec7644Serapheim Dimitropoulos	 */
3682ec7644Serapheim Dimitropoulos	uint32_t size = priv->nvp_nbuckets;
3692ec7644Serapheim Dimitropoulos	uint32_t new_mask = new_size - 1;
3702ec7644Serapheim Dimitropoulos	ASSERT(ISP2(new_size));
3712ec7644Serapheim Dimitropoulos
3722ec7644Serapheim Dimitropoulos	i_nvp_t **new_tab = nv_mem_zalloc(priv, new_size * sizeof (i_nvp_t *));
3732ec7644Serapheim Dimitropoulos	if (new_tab == NULL)
3742ec7644Serapheim Dimitropoulos		return (ENOMEM);
3752ec7644Serapheim Dimitropoulos
3762ec7644Serapheim Dimitropoulos	uint32_t nentries = 0;
3772ec7644Serapheim Dimitropoulos	for (uint32_t i = 0; i < size; i++) {
3782ec7644Serapheim Dimitropoulos		i_nvp_t *next, *e = tab[i];
3792ec7644Serapheim Dimitropoulos
3802ec7644Serapheim Dimitropoulos		while (e != NULL) {
3812ec7644Serapheim Dimitropoulos			next = e->nvi_hashtable_next;
3822ec7644Serapheim Dimitropoulos
3832ec7644Serapheim Dimitropoulos			uint32_t hash = nvt_hash(NVP_NAME(&e->nvi_nvp));
3842ec7644Serapheim Dimitropoulos			uint32_t index = hash & new_mask;
3852ec7644Serapheim Dimitropoulos
3862ec7644Serapheim Dimitropoulos			e->nvi_hashtable_next = new_tab[index];
3872ec7644Serapheim Dimitropoulos			new_tab[index] = e;
3882ec7644Serapheim Dimitropoulos			nentries++;
3892ec7644Serapheim Dimitropoulos
3902ec7644Serapheim Dimitropoulos			e = next;
3912ec7644Serapheim Dimitropoulos		}
3922ec7644Serapheim Dimitropoulos		tab[i] = NULL;
3932ec7644Serapheim Dimitropoulos	}
3942ec7644Serapheim Dimitropoulos	ASSERT3U(nentries, ==, priv->nvp_nentries);
3952ec7644Serapheim Dimitropoulos
3962ec7644Serapheim Dimitropoulos	nvt_tab_free(priv);
3972ec7644Serapheim Dimitropoulos
3982ec7644Serapheim Dimitropoulos	priv->nvp_hashtable = new_tab;
3992ec7644Serapheim Dimitropoulos	priv->nvp_nbuckets = new_size;
4002ec7644Serapheim Dimitropoulos	priv->nvp_nentries = nentries;
4012ec7644Serapheim Dimitropoulos
4022ec7644Serapheim Dimitropoulos	return (0);
4032ec7644Serapheim Dimitropoulos}
4042ec7644Serapheim Dimitropoulos
4052ec7644Serapheim Dimitropoulosstatic boolean_t
4062ec7644Serapheim Dimitropoulosnvt_needs_togrow(nvpriv_t *priv)
4072ec7644Serapheim Dimitropoulos{
4082ec7644Serapheim Dimitropoulos	/*
4092ec7644Serapheim Dimitropoulos	 * Grow only when we have more elements than buckets
4102ec7644Serapheim Dimitropoulos	 * and the # of buckets doesn't overflow.
4112ec7644Serapheim Dimitropoulos	 */
4122ec7644Serapheim Dimitropoulos	return (priv->nvp_nentries > priv->nvp_nbuckets &&
4132ec7644Serapheim Dimitropoulos	    (UINT32_MAX >> 1) >= priv->nvp_nbuckets);
4142ec7644Serapheim Dimitropoulos}
4152ec7644Serapheim Dimitropoulos
4162ec7644Serapheim Dimitropoulos/*
4172ec7644Serapheim Dimitropoulos * Allocate a new table that's twice the size of the old one,
4182ec7644Serapheim Dimitropoulos * and migrate all the entries from the old one to the new
4192ec7644Serapheim Dimitropoulos * one by re-adjusting their pointers.
4202ec7644Serapheim Dimitropoulos */
4212ec7644Serapheim Dimitropoulosstatic int
4222ec7644Serapheim Dimitropoulosnvt_grow(nvpriv_t *priv)
4232ec7644Serapheim Dimitropoulos{
4242ec7644Serapheim Dimitropoulos	uint32_t current_size = priv->nvp_nbuckets;
4252ec7644Serapheim Dimitropoulos	/* ensure we won't overflow */
4262ec7644Serapheim Dimitropoulos	ASSERT3U(UINT32_MAX >> 1, >=, current_size);
4272ec7644Serapheim Dimitropoulos	return (nvt_resize(priv, current_size << 1));
4282ec7644Serapheim Dimitropoulos}
4292ec7644Serapheim Dimitropoulos
4302ec7644Serapheim Dimitropoulosstatic boolean_t
4312ec7644Serapheim Dimitropoulosnvt_needs_toshrink(nvpriv_t *priv)
4322ec7644Serapheim Dimitropoulos{
4332ec7644Serapheim Dimitropoulos	/*
4342ec7644Serapheim Dimitropoulos	 * Shrink only when the # of elements is less than or
4352ec7644Serapheim Dimitropoulos	 * equal to 1/4 the # of buckets. Never shrink less than
4362ec7644Serapheim Dimitropoulos	 * nvlist_hashtable_init_size.
4372ec7644Serapheim Dimitropoulos	 */
4382ec7644Serapheim Dimitropoulos	ASSERT3U(priv->nvp_nbuckets, >=, nvlist_hashtable_init_size);
4392ec7644Serapheim Dimitropoulos	if (priv->nvp_nbuckets == nvlist_hashtable_init_size)
4402ec7644Serapheim Dimitropoulos		return (B_FALSE);
4412ec7644Serapheim Dimitropoulos	return (priv->nvp_nentries <= (priv->nvp_nbuckets >> 2));
4422ec7644Serapheim Dimitropoulos}
4432ec7644Serapheim Dimitropoulos
4442ec7644Serapheim Dimitropoulos/*
4452ec7644Serapheim Dimitropoulos * Allocate a new table that's half the size of the old one,
4462ec7644Serapheim Dimitropoulos * and migrate all the entries from the old one to the new
4472ec7644Serapheim Dimitropoulos * one by re-adjusting their pointers.
4482ec7644Serapheim Dimitropoulos */
4492ec7644Serapheim Dimitropoulosstatic int
4502ec7644Serapheim Dimitropoulosnvt_shrink(nvpriv_t *priv)
4512ec7644Serapheim Dimitropoulos{
4522ec7644Serapheim Dimitropoulos	uint32_t current_size = priv->nvp_nbuckets;
4532ec7644Serapheim Dimitropoulos	/* ensure we won't overflow */
4542ec7644Serapheim Dimitropoulos	ASSERT3U(current_size, >=, nvlist_hashtable_init_size);
4552ec7644Serapheim Dimitropoulos	return (nvt_resize(priv, current_size >> 1));
4562ec7644Serapheim Dimitropoulos}
4572ec7644Serapheim Dimitropoulos
4582ec7644Serapheim Dimitropoulosstatic int
4592ec7644Serapheim Dimitropoulosnvt_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
4602ec7644Serapheim Dimitropoulos{
4612ec7644Serapheim Dimitropoulos	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
4622ec7644Serapheim Dimitropoulos
4632ec7644Serapheim Dimitropoulos	if (nvt_needs_toshrink(priv)) {
4642ec7644Serapheim Dimitropoulos		int err = nvt_shrink(priv);
4652ec7644Serapheim Dimitropoulos		if (err != 0)
4662ec7644Serapheim Dimitropoulos			return (err);
4672ec7644Serapheim Dimitropoulos	}
4682ec7644Serapheim Dimitropoulos	i_nvp_t **tab = priv->nvp_hashtable;
4692ec7644Serapheim Dimitropoulos
4702ec7644Serapheim Dimitropoulos	char *name = NVP_NAME(nvp);
4712ec7644Serapheim Dimitropoulos	uint64_t hash = nvt_hash(name);
4722ec7644Serapheim Dimitropoulos	uint64_t index = hash & (priv->nvp_nbuckets - 1);
4732ec7644Serapheim Dimitropoulos
4742ec7644Serapheim Dimitropoulos	ASSERT3U(index, <, priv->nvp_nbuckets);
4752ec7644Serapheim Dimitropoulos	i_nvp_t *bucket = tab[index];
4762ec7644Serapheim Dimitropoulos
4772ec7644Serapheim Dimitropoulos	for (i_nvp_t *prev = NULL, *e = bucket;
4782ec7644Serapheim Dimitropoulos	    e != NULL; prev = e, e = e->nvi_hashtable_next) {
479b8a5beeAndrew Stormont		if (nvt_nvpair_match(&e->nvi_nvp, nvp, nvl->nvl_nvflag)) {
4802ec7644Serapheim Dimitropoulos			if (prev != NULL) {
4812ec7644Serapheim Dimitropoulos				prev->nvi_hashtable_next =
4822ec7644Serapheim Dimitropoulos				    e->nvi_hashtable_next;
4832ec7644Serapheim Dimitropoulos			} else {
4842ec7644Serapheim Dimitropoulos				ASSERT3P(e, ==, bucket);
4852ec7644Serapheim Dimitropoulos				tab[index] = e->nvi_hashtable_next;
4862ec7644Serapheim Dimitropoulos			}
4872ec7644Serapheim Dimitropoulos			e->nvi_hashtable_next = NULL;
4882ec7644Serapheim Dimitropoulos			priv->nvp_nentries--;
4892ec7644Serapheim Dimitropoulos			break;
4902ec7644Serapheim Dimitropoulos		}
4912ec7644Serapheim Dimitropoulos	}
4922ec7644Serapheim Dimitropoulos
4932ec7644Serapheim Dimitropoulos	return (0);
4942ec7644Serapheim Dimitropoulos}
4952ec7644Serapheim Dimitropoulos
4962ec7644Serapheim Dimitropoulosstatic int
4972ec7644Serapheim Dimitropoulosnvt_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
4982ec7644Serapheim Dimitropoulos{
4992ec7644Serapheim Dimitropoulos	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
5002ec7644Serapheim Dimitropoulos
5012ec7644Serapheim Dimitropoulos	/* initialize nvpair table now if it doesn't exist. */
5022ec7644Serapheim Dimitropoulos	if (priv->nvp_hashtable == NULL) {
5032ec7644Serapheim Dimitropoulos		int err = nvt_tab_alloc(priv, nvlist_hashtable_init_size);
5042ec7644Serapheim Dimitropoulos		if (err != 0)
5052ec7644Serapheim Dimitropoulos			return (err);
5062ec7644Serapheim Dimitropoulos	}
5072ec7644Serapheim Dimitropoulos
5082ec7644Serapheim Dimitropoulos	/*
5092ec7644Serapheim Dimitropoulos	 * if we don't allow duplicate entries, make sure to
5102ec7644Serapheim Dimitropoulos	 * unlink any existing entries from the table.
5112ec7644Serapheim Dimitropoulos	 */
5122ec7644Serapheim Dimitropoulos	if (nvl->nvl_nvflag != 0) {
5132ec7644Serapheim Dimitropoulos		int err = nvt_remove_nvpair(nvl, nvp);
5142ec7644Serapheim Dimitropoulos		if (err != 0)
5152ec7644Serapheim Dimitropoulos			return (err);
5162ec7644Serapheim Dimitropoulos	}
5172ec7644Serapheim Dimitropoulos
5182ec7644Serapheim Dimitropoulos	if (nvt_needs_togrow(priv)) {
5192ec7644Serapheim Dimitropoulos		int err = nvt_grow(priv);
5202ec7644Serapheim Dimitropoulos		if (err != 0)
5212ec7644Serapheim Dimitropoulos			return (err);
5222ec7644Serapheim Dimitropoulos	}
5232ec7644Serapheim Dimitropoulos	i_nvp_t **tab = priv->nvp_hashtable;
5242ec7644Serapheim Dimitropoulos
5252ec7644Serapheim Dimitropoulos	char *name = NVP_NAME(nvp);
5262ec7644Serapheim Dimitropoulos	uint64_t hash = nvt_hash(name);
5272ec7644Serapheim Dimitropoulos	uint64_t index = hash & (priv->nvp_nbuckets - 1);
5282ec7644Serapheim Dimitropoulos
5292ec7644Serapheim Dimitropoulos	ASSERT3U(index, <, priv->nvp_nbuckets);
5302ec7644Serapheim Dimitropoulos	i_nvp_t *bucket = tab[index];
5312ec7644Serapheim Dimitropoulos
5322ec7644Serapheim Dimitropoulos	/* insert link at the beginning of the bucket */
5332ec7644Serapheim Dimitropoulos	i_nvp_t *new_entry = NVPAIR2I_NVP(nvp);
5342ec7644Serapheim Dimitropoulos	ASSERT3P(new_entry->nvi_hashtable_next, ==, NULL);
5352ec7644Serapheim Dimitropoulos	new_entry->nvi_hashtable_next = bucket;
5362ec7644Serapheim Dimitropoulos	tab[index] = new_entry;
5372ec7644Serapheim Dimitropoulos
5382ec7644Serapheim Dimitropoulos	priv->nvp_nentries++;
5392ec7644Serapheim Dimitropoulos	return (0);
5402ec7644Serapheim Dimitropoulos}
5412ec7644Serapheim Dimitropoulos
5427c478bdstevel@tonic-gatestatic void
5437c478bdstevel@tonic-gatenvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)
5447c478bdstevel@tonic-gate{
5457c478bdstevel@tonic-gate	nvl->nvl_version = NV_VERSION;
5467c478bdstevel@tonic-gate	nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);
5477c478bdstevel@tonic-gate	nvl->nvl_priv = (uint64_t)(uintptr_t)priv;
5487c478bdstevel@tonic-gate	nvl->nvl_flag = 0;
5497c478bdstevel@tonic-gate	nvl->nvl_pad = 0;
5507c478bdstevel@tonic-gate}
5517c478bdstevel@tonic-gate
552f6e214cGavin Maltbyuint_t
553f6e214cGavin Maltbynvlist_nvflag(nvlist_t *nvl)
554f6e214cGavin Maltby{
555f6e214cGavin Maltby	return (nvl->nvl_nvflag);
556f6e214cGavin Maltby}
557f6e214cGavin Maltby
5587c478bdstevel@tonic-gate/*
5597c478bdstevel@tonic-gate * nvlist_alloc - Allocate nvlist.
5607c478bdstevel@tonic-gate */
5617c478bdstevel@tonic-gate/*ARGSUSED1*/
5627c478bdstevel@tonic-gateint
5637c478bdstevel@tonic-gatenvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)
5647c478bdstevel@tonic-gate{
5657c478bdstevel@tonic-gate#if defined(_KERNEL) && !defined(_BOOT)
5667c478bdstevel@tonic-gate	return (nvlist_xalloc(nvlp, nvflag,
5677c478bdstevel@tonic-gate	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
5687c478bdstevel@tonic-gate#else
5697c478bdstevel@tonic-gate	return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep));
5707c478bdstevel@tonic-gate#endif
5717c478bdstevel@tonic-gate}
5727c478bdstevel@tonic-gate
5737c478bdstevel@tonic-gateint
5747c478bdstevel@tonic-gatenvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)
5757c478bdstevel@tonic-gate{
5767c478bdstevel@tonic-gate	nvpriv_t *priv;
5777c478bdstevel@tonic-gate
5787c478bdstevel@tonic-gate	if (nvlp == NULL || nva == NULL)
5797c478bdstevel@tonic-gate		return (EINVAL);
5807c478bdstevel@tonic-gate
5817c478bdstevel@tonic-gate	if ((priv = nv_priv_alloc(nva)) == NULL)
5827c478bdstevel@tonic-gate		return (ENOMEM);
5837c478bdstevel@tonic-gate
5847c478bdstevel@tonic-gate	if ((*nvlp = nv_mem_zalloc(priv,
5857c478bdstevel@tonic-gate	    NV_ALIGN(sizeof (nvlist_t)))) == NULL) {
5867c478bdstevel@tonic-gate		nv_mem_free(priv, priv, sizeof (nvpriv_t));
5877c478bdstevel@tonic-gate		return (ENOMEM);
5887c478bdstevel@tonic-gate	}
5897c478bdstevel@tonic-gate
5907c478bdstevel@tonic-gate	nvlist_init(*nvlp, nvflag, priv);
5917c478bdstevel@tonic-gate
5927c478bdstevel@tonic-gate	return (0);
5937c478bdstevel@tonic-gate}
5947c478bdstevel@tonic-gate
5957c478bdstevel@tonic-gate/*
5967c478bdstevel@tonic-gate * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
5977c478bdstevel@tonic-gate */
5987c478bdstevel@tonic-gatestatic nvpair_t *
5997c478bdstevel@tonic-gatenvp_buf_alloc(nvlist_t *nvl, size_t len)
6007c478bdstevel@tonic-gate{
6017c478bdstevel@tonic-gate	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6027c478bdstevel@tonic-gate	i_nvp_t *buf;
6037c478bdstevel@tonic-gate	nvpair_t *nvp;
6047c478bdstevel@tonic-gate	size_t nvsize;
6057c478bdstevel@tonic-gate
6067c478bdstevel@tonic-gate	/*
6077c478bdstevel@tonic-gate	 * Allocate the buffer
6087c478bdstevel@tonic-gate	 */
6097c478bdstevel@tonic-gate	nvsize = len + offsetof(i_nvp_t, nvi_nvp);
6107c478bdstevel@tonic-gate
6117c478bdstevel@tonic-gate	if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)
6127c478bdstevel@tonic-gate		return (NULL);
6137c478bdstevel@tonic-gate
6147c478bdstevel@tonic-gate	nvp = &buf->nvi_nvp;
6157c478bdstevel@tonic-gate	nvp->nvp_size = len;
6167c478bdstevel@tonic-gate
6177c478bdstevel@tonic-gate	return (nvp);
6187c478bdstevel@tonic-gate}
6197c478bdstevel@tonic-gate
6207c478bdstevel@tonic-gate/*
6217c478bdstevel@tonic-gate * nvp_buf_free - de-Allocate an i_nvp_t.
6227c478bdstevel@tonic-gate */
6237c478bdstevel@tonic-gatestatic void
6247c478bdstevel@tonic-gatenvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)
6257c478bdstevel@tonic-gate{
6267c478bdstevel@tonic-gate	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6277c478bdstevel@tonic-gate	size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);
6287c478bdstevel@tonic-gate
6297c478bdstevel@tonic-gate	nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);
6307c478bdstevel@tonic-gate}
6317c478bdstevel@tonic-gate
6327c478bdstevel@tonic-gate/*
6337c478bdstevel@tonic-gate * nvp_buf_link - link a new nv pair into the nvlist.
6347c478bdstevel@tonic-gate */
6357c478bdstevel@tonic-gatestatic void
6367c478bdstevel@tonic-gatenvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)
6377c478bdstevel@tonic-gate{
6387c478bdstevel@tonic-gate	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6397c478bdstevel@tonic-gate	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
6407c478bdstevel@tonic-gate
6417c478bdstevel@tonic-gate	/* Put element at end of nvlist */
6427c478bdstevel@tonic-gate	if (priv->nvp_list == NULL) {
6437c478bdstevel@tonic-gate		priv->nvp_list = priv->nvp_last = curr;
6447c478bdstevel@tonic-gate	} else {
6457c478bdstevel@tonic-gate		curr->nvi_prev = priv->nvp_last;
6467c478bdstevel@tonic-gate		priv->nvp_last->nvi_next = curr;
6477c478bdstevel@tonic-gate		priv->nvp_last = curr;
6487c478bdstevel@tonic-gate	}
6497c478bdstevel@tonic-gate}
6507c478bdstevel@tonic-gate
6517c478bdstevel@tonic-gate/*
6527c478bdstevel@tonic-gate * nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
6537c478bdstevel@tonic-gate */
6547c478bdstevel@tonic-gatestatic void
6557c478bdstevel@tonic-gatenvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)
6567c478bdstevel@tonic-gate{
6577c478bdstevel@tonic-gate	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
6587c478bdstevel@tonic-gate	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
6597c478bdstevel@tonic-gate
6607c478bdstevel@tonic-gate	/*
6617c478bdstevel@tonic-gate	 * protect nvlist_next_nvpair() against walking on freed memory.
6627c478bdstevel@tonic-gate	 */
6637c478bdstevel@tonic-gate	if (priv->nvp_curr == curr)
6647c478bdstevel@tonic-gate		priv->nvp_curr = curr->nvi_next;
6657c478bdstevel@tonic-gate
6667c478bdstevel@tonic-gate	if (curr == priv->nvp_list)
6677c478bdstevel@tonic-gate		priv->nvp_list = curr->nvi_next;
6687c478bdstevel@tonic-gate	else
6697c478bdstevel@tonic-gate		curr->nvi_prev->nvi_next = curr->nvi_next;
6707c478bdstevel@tonic-gate
6717c478bdstevel@tonic-gate	if (curr == priv->nvp_last)
6727c478bdstevel@tonic-gate		priv->nvp_last = curr->nvi_prev;
6737c478bdstevel@tonic-gate	else
6747c478bdstevel@tonic-gate		curr->nvi_next->nvi_prev = curr->nvi_prev;
6757c478bdstevel@tonic-gate}
6767c478bdstevel@tonic-gate
6777c478bdstevel@tonic-gate/*
6787c478bdstevel@tonic-gate * take a nvpair type and number of elements and make sure the are valid
6797c478bdstevel@tonic-gate */
6807c478bdstevel@tonic-gatestatic int
6817c478bdstevel@tonic-gatei_validate_type_nelem(data_type_t type, uint_t nelem)
6827c478bdstevel@tonic-gate{
6837c478bdstevel@tonic-gate	switch (type) {
6847c478bdstevel@tonic-gate	case DATA_TYPE_BOOLEAN:
6857c478bdstevel@tonic-gate		if (nelem != 0)
6867c478bdstevel@tonic-gate			return (EINVAL);
6877c478bdstevel@tonic-gate		break;
6887c478bdstevel@tonic-gate	case DATA_TYPE_BOOLEAN_VALUE:
6897c478bdstevel@tonic-gate	case DATA_TYPE_BYTE:
6907c478bdstevel@tonic-gate	case DATA_TYPE_INT8:
6917c478bdstevel@tonic-gate	case DATA_TYPE_UINT8:
6927c478bdstevel@tonic-gate	case DATA_TYPE_INT16:
6937c478bdstevel@tonic-gate	case DATA_TYPE_UINT16:
6947c478bdstevel@tonic-gate	case DATA_TYPE_INT32:
6957c478bdstevel@tonic-gate	case DATA_TYPE_UINT32:
6967c478bdstevel@tonic-gate	case DATA_TYPE_INT64:
6977c478bdstevel@tonic-gate	case DATA_TYPE_UINT64:
6987c478bdstevel@tonic-gate	case DATA_TYPE_STRING:
6997c478bdstevel@tonic-gate	case DATA_TYPE_HRTIME:
7007c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST:
701825ba0frobj#if !defined(_KERNEL)
702825ba0frobj	case DATA_TYPE_DOUBLE:
703825ba0frobj#endif
7047c478bdstevel@tonic-gate		if (nelem != 1)
7057c478bdstevel@tonic-gate			return (EINVAL);
7067c478bdstevel@tonic-gate		break;
7077c478bdstevel@tonic-gate	case DATA_TYPE_BOOLEAN_ARRAY:
7087c478bdstevel@tonic-gate	case DATA_TYPE_BYTE_ARRAY:
7097c478bdstevel@tonic-gate	case DATA_TYPE_INT8_ARRAY:
7107c478bdstevel@tonic-gate	case DATA_TYPE_UINT8_ARRAY:
7117c478bdstevel@tonic-gate	case DATA_TYPE_INT16_ARRAY:
7127c478bdstevel@tonic-gate	case DATA_TYPE_UINT16_ARRAY:
7137c478bdstevel@tonic-gate	case DATA_TYPE_INT32_ARRAY:
7147c478bdstevel@tonic-gate	case DATA_TYPE_UINT32_ARRAY:
7157c478bdstevel@tonic-gate	case DATA_TYPE_INT64_ARRAY:
7167c478bdstevel@tonic-gate	case DATA_TYPE_UINT64_ARRAY:
7177c478bdstevel@tonic-gate	case DATA_TYPE_STRING_ARRAY:
7187c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST_ARRAY:
7197c478bdstevel@tonic-gate		/* we allow arrays with 0 elements */
7207c478bdstevel@tonic-gate		break;
7217c478bdstevel@tonic-gate	default:
7227c478bdstevel@tonic-gate		return (EINVAL);
7237c478bdstevel@tonic-gate	}
7247c478bdstevel@tonic-gate	return (0);
7257c478bdstevel@tonic-gate}
7267c478bdstevel@tonic-gate
7277c478bdstevel@tonic-gate/*
7287c478bdstevel@tonic-gate * Verify nvp_name_sz and check the name string length.
7297c478bdstevel@tonic-gate */
7307c478bdstevel@tonic-gatestatic int
7317c478bdstevel@tonic-gatei_validate_nvpair_name(nvpair_t *nvp)
7327c478bdstevel@tonic-gate{
7337c478bdstevel@tonic-gate	if ((nvp->nvp_name_sz <= 0) ||
7347c478bdstevel@tonic-gate	    (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))
7357c478bdstevel@tonic-gate		return (EFAULT);
7367c478bdstevel@tonic-gate
7377c478bdstevel@tonic-gate	/* verify the name string, make sure its terminated */
7387c478bdstevel@tonic-gate	if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')
7397c478bdstevel@tonic-gate		return (EFAULT);
7407c478bdstevel@tonic-gate
7417c478bdstevel@tonic-gate	return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);
7427c478bdstevel@tonic-gate}
7437c478bdstevel@tonic-gate
7447c478bdstevel@tonic-gatestatic int
7457c478bdstevel@tonic-gatei_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)
7467c478bdstevel@tonic-gate{
7477c478bdstevel@tonic-gate	switch (type) {
7487c478bdstevel@tonic-gate	case DATA_TYPE_BOOLEAN_VALUE:
7497c478bdstevel@tonic-gate		if (*(boolean_t *)data != B_TRUE &&
7507c478bdstevel@tonic-gate		    *(boolean_t *)data != B_FALSE)
7517c478bdstevel@tonic-gate			return (EINVAL);
7527c478bdstevel@tonic-gate		break;
7537c478bdstevel@tonic-gate	case DATA_TYPE_BOOLEAN_ARRAY: {
7547c478bdstevel@tonic-gate		int i;
7557c478bdstevel@tonic-gate
7567c478bdstevel@tonic-gate		for (i = 0; i < nelem; i++)
7577c478bdstevel@tonic-gate			if (((boolean_t *)data)[i] != B_TRUE &&
7587c478bdstevel@tonic-gate			    ((boolean_t *)data)[i] != B_FALSE)
7597c478bdstevel@tonic-gate				return (EINVAL);
7607c478bdstevel@tonic-gate		break;
7617c478bdstevel@tonic-gate	}
7627c478bdstevel@tonic-gate	default:
7637c478bdstevel@tonic-gate		break;
7647c478bdstevel@tonic-gate	}
7657c478bdstevel@tonic-gate
7667c478bdstevel@tonic-gate	return (0);
7677c478bdstevel@tonic-gate}
7687c478bdstevel@tonic-gate
7697c478bdstevel@tonic-gate/*
7707c478bdstevel@tonic-gate * This function takes a pointer to what should be a nvpair and it's size
7717c478bdstevel@tonic-gate * and then verifies that all the nvpair fields make sense and can be
7727c478bdstevel@tonic-gate * trusted.  This function is used when decoding packed nvpairs.
7737c478bdstevel@tonic-gate */
7747c478bdstevel@tonic-gatestatic int
7757c478bdstevel@tonic-gatei_validate_nvpair(nvpair_t *nvp)
7767c478bdstevel@tonic-gate{
7777c478bdstevel@tonic-gate	data_type_t type = NVP_TYPE(nvp);
7787c478bdstevel@tonic-gate	int size1, size2;
7797c478bdstevel@tonic-gate
7807c478bdstevel@tonic-gate	/* verify nvp_name_sz, check the name string length */
7817c478bdstevel@tonic-gate	if (i_validate_nvpair_name(nvp) != 0)
7827c478bdstevel@tonic-gate		return (EFAULT);
7837c478bdstevel@tonic-gate
7847c478bdstevel@tonic-gate	if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)
7857c478bdstevel@tonic-gate		return (EFAULT);
7867c478bdstevel@tonic-gate
7877c478bdstevel@tonic-gate	/*
7887c478bdstevel@tonic-gate	 * verify nvp_type, nvp_value_elem, and also possibly
7897c478bdstevel@tonic-gate	 * verify string values and get the value size.
7907c478bdstevel@tonic-gate	 */
7917c478bdstevel@tonic-gate	size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));
7927c478bdstevel@tonic-gate	size1 = nvp->nvp_size - NVP_VALOFF(nvp);
7937c478bdstevel@tonic-gate	if (size2 < 0 || size1 != NV_ALIGN(size2))
7947c478bdstevel@tonic-gate		return (EFAULT);
7957c478bdstevel@tonic-gate
7967c478bdstevel@tonic-gate	return (0);
7977c478bdstevel@tonic-gate}
7987c478bdstevel@tonic-gate
7997c478bdstevel@tonic-gatestatic int
8007c478bdstevel@tonic-gatenvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl)
8017c478bdstevel@tonic-gate{
8027c478bdstevel@tonic-gate	nvpriv_t *priv;
8037c478bdstevel@tonic-gate	i_nvp_t *curr;
8047c478bdstevel@tonic-gate
8057c478bdstevel@tonic-gate	if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)
8067c478bdstevel@tonic-gate		return (EINVAL);
8077c478bdstevel@tonic-gate
8087c478bdstevel@tonic-gate	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
8097c478bdstevel@tonic-gate		nvpair_t *nvp = &curr->nvi_nvp;
8107c478bdstevel@tonic-gate		int err;
8117c478bdstevel@tonic-gate
8127c478bdstevel@tonic-gate		if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),
8137c478bdstevel@tonic-gate		    NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)
8147c478bdstevel@tonic-gate			return (err);
8157c478bdstevel@tonic-gate	}
8167c478bdstevel@tonic-gate
8177c478bdstevel@tonic-gate	return (0);
8187c478bdstevel@tonic-gate}
8197c478bdstevel@tonic-gate
8207c478bdstevel@tonic-gate/*
8217c478bdstevel@tonic-gate * Frees all memory allocated for an nvpair (like embedded lists) with
8227c478bdstevel@tonic-gate * the exception of the nvpair buffer itself.
8237c478bdstevel@tonic-gate */
8247c478bdstevel@tonic-gatestatic void
8257c478bdstevel@tonic-gatenvpair_free(nvpair_t *nvp)
8267c478bdstevel@tonic-gate{
8277c478bdstevel@tonic-gate	switch (NVP_TYPE(nvp)) {
8287c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST:
8297c478bdstevel@tonic-gate		nvlist_free(EMBEDDED_NVL(nvp));
8307c478bdstevel@tonic-gate		break;
8317c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST_ARRAY: {
8327c478bdstevel@tonic-gate		nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
8337c478bdstevel@tonic-gate		int i;
8347c478bdstevel@tonic-gate
8357c478bdstevel@tonic-gate		for (i = 0; i < NVP_NELEM(nvp); i++)
836aab83bbJosef 'Jeff' Sipek			nvlist_free(nvlp[i]);
8377c478bdstevel@tonic-gate		break;
8387c478bdstevel@tonic-gate	}
8397c478bdstevel@tonic-gate	default:
8407c478bdstevel@tonic-gate		break;
8417c478bdstevel@tonic-gate	}
8427c478bdstevel@tonic-gate}
8437c478bdstevel@tonic-gate
8447c478bdstevel@tonic-gate/*
8457c478bdstevel@tonic-gate * nvlist_free - free an unpacked nvlist
8467c478bdstevel@tonic-gate */
8477c478bdstevel@tonic-gatevoid
8487c478bdstevel@tonic-gatenvlist_free(nvlist_t *nvl)
8497c478bdstevel@tonic-gate{
8507c478bdstevel@tonic-gate	nvpriv_t *priv;
8517c478bdstevel@tonic-gate	i_nvp_t *curr;
8527c478bdstevel@tonic-gate
8537c478bdstevel@tonic-gate	if (nvl == NULL ||
8547c478bdstevel@tonic-gate	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
8557c478bdstevel@tonic-gate		return;
8567c478bdstevel@tonic-gate
8577c478bdstevel@tonic-gate	/*
8587c478bdstevel@tonic-gate	 * Unpacked nvlist are linked through i_nvp_t
8597c478bdstevel@tonic-gate	 */
8607c478bdstevel@tonic-gate	curr = priv->nvp_list;
8617c478bdstevel@tonic-gate	while (curr != NULL) {
8627c478bdstevel@tonic-gate		nvpair_t *nvp = &curr->nvi_nvp;
8637c478bdstevel@tonic-gate		curr = curr->nvi_next;
8647c478bdstevel@tonic-gate
8657c478bdstevel@tonic-gate		nvpair_free(nvp);
8667c478bdstevel@tonic-gate		nvp_buf_free(nvl, nvp);
8677c478bdstevel@tonic-gate	}
8687c478bdstevel@tonic-gate
8697c478bdstevel@tonic-gate	if (!(priv->nvp_stat & NV_STAT_EMBEDDED))
8707c478bdstevel@tonic-gate		nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));
8717c478bdstevel@tonic-gate	else
8725ad8204nd		nvl->nvl_priv = 0;
8737c478bdstevel@tonic-gate
8742ec7644Serapheim Dimitropoulos	nvt_tab_free(priv);
8757c478bdstevel@tonic-gate	nv_mem_free(priv, priv, sizeof (nvpriv_t));
8767c478bdstevel@tonic-gate}
8777c478bdstevel@tonic-gate
8787c478bdstevel@tonic-gatestatic int
8797c478bdstevel@tonic-gatenvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp)
8807c478bdstevel@tonic-gate{
8817c478bdstevel@tonic-gate	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
8827c478bdstevel@tonic-gate	i_nvp_t *curr;
8837c478bdstevel@tonic-gate
8847c478bdstevel@tonic-gate	if (nvp == NULL)
8857c478bdstevel@tonic-gate		return (0);
8867c478bdstevel@tonic-gate
8877c478bdstevel@tonic-gate	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
8887c478bdstevel@tonic-gate		if (&curr->nvi_nvp == nvp)
8897c478bdstevel@tonic-gate			return (1);
8907c478bdstevel@tonic-gate
8917c478bdstevel@tonic-gate	return (0);
8927c478bdstevel@tonic-gate}
8937c478bdstevel@tonic-gate
8947c478bdstevel@tonic-gate/*
8957c478bdstevel@tonic-gate * Make a copy of nvlist
8967c478bdstevel@tonic-gate */
8977c478bdstevel@tonic-gate/*ARGSUSED1*/
8987c478bdstevel@tonic-gateint
8997c478bdstevel@tonic-gatenvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag)
9007c478bdstevel@tonic-gate{
9017c478bdstevel@tonic-gate#if defined(_KERNEL) && !defined(_BOOT)
9027c478bdstevel@tonic-gate	return (nvlist_xdup(nvl, nvlp,
9037c478bdstevel@tonic-gate	    (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
9047c478bdstevel@tonic-gate#else
9057c478bdstevel@tonic-gate	return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep));
9067c478bdstevel@tonic-gate#endif
9077c478bdstevel@tonic-gate}
9087c478bdstevel@tonic-gate
9097c478bdstevel@tonic-gateint
9107c478bdstevel@tonic-gatenvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)
9117c478bdstevel@tonic-gate{
9127c478bdstevel@tonic-gate	int err;
9133bb79beeschrock	nvlist_t *ret;
9147c478bdstevel@tonic-gate
9157c478bdstevel@tonic-gate	if (nvl == NULL || nvlp == NULL)
9167c478bdstevel@tonic-gate		return (EINVAL);
9177c478bdstevel@tonic-gate
9183bb79beeschrock	if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0)
9197c478bdstevel@tonic-gate		return (err);
9207c478bdstevel@tonic-gate
9213bb79beeschrock	if ((err = nvlist_copy_pairs(nvl, ret)) != 0)
9223bb79beeschrock		nvlist_free(ret);
9233bb79beeschrock	else
9243bb79beeschrock		*nvlp = ret;
9257c478bdstevel@tonic-gate
9267c478bdstevel@tonic-gate	return (err);
9277c478bdstevel@tonic-gate}
9287c478bdstevel@tonic-gate
9297c478bdstevel@tonic-gate/*
9307c478bdstevel@tonic-gate * Remove all with matching name
9317c478bdstevel@tonic-gate */
9327c478bdstevel@tonic-gateint
9337c478bdstevel@tonic-gatenvlist_remove_all(nvlist_t *nvl, const char *name)
9347c478bdstevel@tonic-gate{
9357c478bdstevel@tonic-gate	int error = ENOENT;
9367c478bdstevel@tonic-gate
9372ec7644Serapheim Dimitropoulos	if (nvl == NULL || name == NULL || nvl->nvl_priv == 0)
9387c478bdstevel@tonic-gate		return (EINVAL);
9397c478bdstevel@tonic-gate
9402ec7644Serapheim Dimitropoulos	nvpair_t *nvp;
9412ec7644Serapheim Dimitropoulos	while ((nvp = nvt_lookup_name(nvl, name)) != NULL) {
9422ec7644Serapheim Dimitropoulos		VERIFY0(nvlist_remove_nvpair(nvl, nvp));
9437c478bdstevel@tonic-gate		error = 0;
9447c478bdstevel@tonic-gate	}
9457c478bdstevel@tonic-gate
9467c478bdstevel@tonic-gate	return (error);
9477c478bdstevel@tonic-gate}
9487c478bdstevel@tonic-gate
9497c478bdstevel@tonic-gate/*
9507c478bdstevel@tonic-gate * Remove first one with matching name and type
9517c478bdstevel@tonic-gate */
9527c478bdstevel@tonic-gateint
9537c478bdstevel@tonic-gatenvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
9547c478bdstevel@tonic-gate{
9552ec7644Serapheim Dimitropoulos	if (nvl == NULL || name == NULL || nvl->nvl_priv == 0)
9567c478bdstevel@tonic-gate		return (EINVAL);
9577c478bdstevel@tonic-gate
9582ec7644Serapheim Dimitropoulos	nvpair_t *nvp = nvt_lookup_name_type(nvl, name, type);
9592ec7644Serapheim Dimitropoulos	if (nvp == NULL)
9602ec7644Serapheim Dimitropoulos		return (ENOENT);
9617c478bdstevel@tonic-gate
9622ec7644Serapheim Dimitropoulos	return (nvlist_remove_nvpair(nvl, nvp));
9637c478bdstevel@tonic-gate}
9647c478bdstevel@tonic-gate
96592241e0Tom Ericksonint
96692241e0Tom Ericksonnvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
96792241e0Tom Erickson{
96892241e0Tom Erickson	if (nvl == NULL || nvp == NULL)
96992241e0Tom Erickson		return (EINVAL);
97092241e0Tom Erickson
9712ec7644Serapheim Dimitropoulos	int err = nvt_remove_nvpair(nvl, nvp);
9722ec7644Serapheim Dimitropoulos	if (err != 0)
9732ec7644Serapheim Dimitropoulos		return (err);
9742ec7644Serapheim Dimitropoulos
97592241e0Tom Erickson	nvp_buf_unlink(nvl, nvp);
97692241e0Tom Erickson	nvpair_free(nvp);
97792241e0Tom Erickson	nvp_buf_free(nvl, nvp);
97892241e0Tom Erickson	return (0);
97992241e0Tom Erickson}
98092241e0Tom Erickson
9817c478bdstevel@tonic-gate/*
9827c478bdstevel@tonic-gate * This function calculates the size of an nvpair value.
9837c478bdstevel@tonic-gate *
9847c478bdstevel@tonic-gate * The data argument controls the behavior in case of the data types
9857c478bdstevel@tonic-gate * 	DATA_TYPE_STRING    	and
9867c478bdstevel@tonic-gate *	DATA_TYPE_STRING_ARRAY
9877c478bdstevel@tonic-gate * Is data == NULL then the size of the string(s) is excluded.
9887c478bdstevel@tonic-gate */
9897c478bdstevel@tonic-gatestatic int
9907c478bdstevel@tonic-gatei_get_value_size(data_type_t type, const void *data, uint_t nelem)
9917c478bdstevel@tonic-gate{
9927c478bdstevel@tonic-gate	uint64_t value_sz;
9937c478bdstevel@tonic-gate
9947c478bdstevel@tonic-gate	if (i_validate_type_nelem(type, nelem) != 0)
9957c478bdstevel@tonic-gate		return (-1);
9967c478bdstevel@tonic-gate
9977c478bdstevel@tonic-gate	/* Calculate required size for holding value */
9987c478bdstevel@tonic-gate	switch (type) {
9997c478bdstevel@tonic-gate	case DATA_TYPE_BOOLEAN:
10007c478bdstevel@tonic-gate		value_sz = 0;
10017c478bdstevel@tonic-gate		break;
10027c478bdstevel@tonic-gate	case DATA_TYPE_BOOLEAN_VALUE:
10037c478bdstevel@tonic-gate		value_sz = sizeof (boolean_t);
10047c478bdstevel@tonic-gate		break;
10057c478bdstevel@tonic-gate	case DATA_TYPE_BYTE:
10067c478bdstevel@tonic-gate		value_sz = sizeof (uchar_t);
10077c478bdstevel@tonic-gate		break;
10087c478bdstevel@tonic-gate	case DATA_TYPE_INT8:
10097c478bdstevel@tonic-gate		value_sz = sizeof (int8_t);
10107c478bdstevel@tonic-gate		break;
10117c478bdstevel@tonic-gate	case DATA_TYPE_UINT8:
10127c478bdstevel@tonic-gate		value_sz = sizeof (uint8_t);
10137c478bdstevel@tonic-gate		break;
10147c478bdstevel@tonic-gate	case DATA_TYPE_INT16:
10157c478bdstevel@tonic-gate		value_sz = sizeof (int16_t);
10167c478bdstevel@tonic-gate		break;
10177c478bdstevel@tonic-gate	case DATA_TYPE_UINT16:
10187c478bdstevel@tonic-gate		value_sz = sizeof (uint16_t);
10197c478bdstevel@tonic-gate		break;
10207c478bdstevel@tonic-gate	case DATA_TYPE_INT32:
10217c478bdstevel@tonic-gate		value_sz = sizeof (int32_t);
10227c478bdstevel@tonic-gate		break;
10237c478bdstevel@tonic-gate	case DATA_TYPE_UINT32:
10247c478bdstevel@tonic-gate		value_sz = sizeof (uint32_t);
10257c478bdstevel@tonic-gate		break;
10267c478bdstevel@tonic-gate	case DATA_TYPE_INT64:
10277c478bdstevel@tonic-gate		value_sz = sizeof (int64_t);
10287c478bdstevel@tonic-gate		break;
10297c478bdstevel@tonic-gate	case DATA_TYPE_UINT64:
10307c478bdstevel@tonic-gate		value_sz = sizeof (uint64_t);
10317c478bdstevel@tonic-gate		break;
1032825ba0frobj#if !defined(_KERNEL)
1033825ba0frobj	case DATA_TYPE_DOUBLE:
1034825ba0frobj		value_sz = sizeof (double);
1035825ba0frobj		break;
1036825ba0frobj#endif
10377c478bdstevel@tonic-gate	case DATA_TYPE_STRING:
10387c478bdstevel@tonic-gate		if (data == NULL)
10397c478bdstevel@tonic-gate			value_sz = 0;
10407c478bdstevel@tonic-gate		else
10417c478bdstevel@tonic-gate			value_sz = strlen(data) + 1;
10427c478bdstevel@tonic-gate		break;
10437c478bdstevel@tonic-gate	case DATA_TYPE_BOOLEAN_ARRAY:
10447c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (boolean_t);
10457c478bdstevel@tonic-gate		break;
10467c478bdstevel@tonic-gate	case DATA_TYPE_BYTE_ARRAY:
10477c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (uchar_t);
10487c478bdstevel@tonic-gate		break;
10497c478bdstevel@tonic-gate	case DATA_TYPE_INT8_ARRAY:
10507c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (int8_t);
10517c478bdstevel@tonic-gate		break;
10527c478bdstevel@tonic-gate	case DATA_TYPE_UINT8_ARRAY:
10537c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (uint8_t);
10547c478bdstevel@tonic-gate		break;
10557c478bdstevel@tonic-gate	case DATA_TYPE_INT16_ARRAY:
10567c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (int16_t);
10577c478bdstevel@tonic-gate		break;
10587c478bdstevel@tonic-gate	case DATA_TYPE_UINT16_ARRAY:
10597c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (uint16_t);
10607c478bdstevel@tonic-gate		break;
10617c478bdstevel@tonic-gate	case DATA_TYPE_INT32_ARRAY:
10627c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (int32_t);
10637c478bdstevel@tonic-gate		break;
10647c478bdstevel@tonic-gate	case DATA_TYPE_UINT32_ARRAY:
10657c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (uint32_t);
10667c478bdstevel@tonic-gate		break;
10677c478bdstevel@tonic-gate	case DATA_TYPE_INT64_ARRAY:
10687c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (int64_t);
10697c478bdstevel@tonic-gate		break;
10707c478bdstevel@tonic-gate	case DATA_TYPE_UINT64_ARRAY:
10717c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (uint64_t);
10727c478bdstevel@tonic-gate		break;
10737c478bdstevel@tonic-gate	case DATA_TYPE_STRING_ARRAY:
10747c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (uint64_t);
10757c478bdstevel@tonic-gate
10767c478bdstevel@tonic-gate		if (data != NULL) {
10777c478bdstevel@tonic-gate			char *const *strs = data;
10787c478bdstevel@tonic-gate			uint_t i;
10797c478bdstevel@tonic-gate
10807c478bdstevel@tonic-gate			/* no alignment requirement for strings */
10817c478bdstevel@tonic-gate			for (i = 0; i < nelem; i++) {
10827c478bdstevel@tonic-gate				if (strs[i] == NULL)
10837c478bdstevel@tonic-gate					return (-1);
10847c478bdstevel@tonic-gate				value_sz += strlen(strs[i]) + 1;
10857c478bdstevel@tonic-gate			}
10867c478bdstevel@tonic-gate		}
10877c478bdstevel@tonic-gate		break;
10887c478bdstevel@tonic-gate	case DATA_TYPE_HRTIME:
10897c478bdstevel@tonic-gate		value_sz = sizeof (hrtime_t);
10907c478bdstevel@tonic-gate		break;
10917c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST:
10927c478bdstevel@tonic-gate		value_sz = NV_ALIGN(sizeof (nvlist_t));
10937c478bdstevel@tonic-gate		break;
10947c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST_ARRAY:
10957c478bdstevel@tonic-gate		value_sz = (uint64_t)nelem * sizeof (uint64_t) +
10967c478bdstevel@tonic-gate		    (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
10977c478bdstevel@tonic-gate		break;
10987c478bdstevel@tonic-gate	default:
10997c478bdstevel@tonic-gate		return (-1);
11007c478bdstevel@tonic-gate	}
11017c478bdstevel@tonic-gate
11027c478bdstevel@tonic-gate	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
11037c478bdstevel@tonic-gate}
11047c478bdstevel@tonic-gate
11057c478bdstevel@tonic-gatestatic int
11067c478bdstevel@tonic-gatenvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl)
11077c478bdstevel@tonic-gate{
11087c478bdstevel@tonic-gate	nvpriv_t *priv;
11097c478bdstevel@tonic-gate	int err;
11107c478bdstevel@tonic-gate
11117c478bdstevel@tonic-gate	if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t)
11127c478bdstevel@tonic-gate	    nvl->nvl_priv)) == NULL)
11137c478bdstevel@tonic-gate		return (ENOMEM);
11147c478bdstevel@tonic-gate
11157c478bdstevel@tonic-gate	nvlist_init(emb_nvl, onvl->nvl_nvflag, priv);
11167c478bdstevel@tonic-gate
11177c478bdstevel@tonic-gate	if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) {
11187c478bdstevel@tonic-gate		nvlist_free(emb_nvl);
11197c478bdstevel@tonic-gate		emb_nvl->nvl_priv = 0;
11207c478bdstevel@tonic-gate	}
11217c478bdstevel@tonic-gate
11227c478bdstevel@tonic-gate	return (err);
11237c478bdstevel@tonic-gate}
11247c478bdstevel@tonic-gate
11257c478bdstevel@tonic-gate/*
11267c478bdstevel@tonic-gate * nvlist_add_common - Add new <name,value> pair to nvlist
11277c478bdstevel@tonic-gate */
11287c478bdstevel@tonic-gatestatic int
11297c478bdstevel@tonic-gatenvlist_add_common(nvlist_t *nvl, const char *name,
11307c478bdstevel@tonic-gate    data_type_t type, uint_t nelem, const void *data)
11317c478bdstevel@tonic-gate{
11327c478bdstevel@tonic-gate	nvpair_t *nvp;
1133d9638e5mws	uint_t i;
1134d9638e5mws
11357c478bdstevel@tonic-gate	int nvp_sz, name_sz, value_sz;
11367c478bdstevel@tonic-gate	int err = 0;
11377c478bdstevel@tonic-gate
11387c478bdstevel@tonic-gate	if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
11397c478bdstevel@tonic-gate		return (EINVAL);
11407c478bdstevel@tonic-gate
11417c478bdstevel@tonic-gate	if (nelem != 0 && data == NULL)
11427c478bdstevel@tonic-gate		return (EINVAL);
11437c478bdstevel@tonic-gate
11447c478bdstevel@tonic-gate	/*
11457c478bdstevel@tonic-gate	 * Verify type and nelem and get the value size.
11467c478bdstevel@tonic-gate	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
11477c478bdstevel@tonic-gate	 * is the size of the string(s) included.
11487c478bdstevel@tonic-gate	 */
11497c478bdstevel@tonic-gate	if ((value_sz = i_get_value_size(type, data, nelem)) < 0)
11507c478bdstevel@tonic-gate		return (EINVAL);
11517c478bdstevel@tonic-gate
11527c478bdstevel@tonic-gate	if (i_validate_nvpair_value(type, nelem, data) != 0)
11537c478bdstevel@tonic-gate		return (EINVAL);
11547c478bdstevel@tonic-gate
1155d9638e5mws	/*
1156d9638e5mws	 * If we're adding an nvlist or nvlist array, ensure that we are not
1157d9638e5mws	 * adding the input nvlist to itself, which would cause recursion,
1158d9638e5mws	 * and ensure that no NULL nvlist pointers are present.
1159d9638e5mws	 */
11607c478bdstevel@tonic-gate	switch (type) {
11617c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST:
1162d9638e5mws		if (data == nvl || data == NULL)
11637c478bdstevel@tonic-gate			return (EINVAL);
11647c478bdstevel@tonic-gate		break;
11657c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST_ARRAY: {
1166d9638e5mws		nvlist_t **onvlp = (nvlist_t **)data;
1167d9638e5mws		for (i = 0; i < nelem; i++) {
1168d9638e5mws			if (onvlp[i] == nvl || onvlp[i] == NULL)
11697c478bdstevel@tonic-gate				return (EINVAL);
11707c478bdstevel@tonic-gate		}
11717c478bdstevel@tonic-gate		break;
1172d9638e5mws	}
11735ad8204nd	default:
11745ad8204nd		break;
11757c478bdstevel@tonic-gate	}
11767c478bdstevel@tonic-gate
11777c478bdstevel@tonic-gate	/* calculate sizes of the nvpair elements and the nvpair itself */
11787c478bdstevel@tonic-gate	name_sz = strlen(name) + 1;
117948dd5e6Matthew Ahrens	if (name_sz >= 1ULL << (sizeof (nvp->nvp_name_sz) * NBBY - 1))
118048dd5e6Matthew Ahrens		return (EINVAL);
11817c478bdstevel@tonic-gate
11827c478bdstevel@tonic-gate	nvp_sz = NVP_SIZE_CALC(name_sz, value_sz);
11837c478bdstevel@tonic-gate
11847c478bdstevel@tonic-gate	if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL)
11857c478bdstevel@tonic-gate		return (ENOMEM);
11867c478bdstevel@tonic-gate
11877c478bdstevel@tonic-gate	ASSERT(nvp->nvp_size == nvp_sz);
11887c478bdstevel@tonic-gate	nvp->nvp_name_sz = name_sz;
11897c478bdstevel@tonic-gate	nvp->nvp_value_elem = nelem;
11907c478bdstevel@tonic-gate	nvp->nvp_type = type;
11917c478bdstevel@tonic-gate	bcopy(name, NVP_NAME(nvp), name_sz);
11927c478bdstevel@tonic-gate
11937c478bdstevel@tonic-gate	switch (type) {
11947c478bdstevel@tonic-gate	case DATA_TYPE_BOOLEAN:
11957c478bdstevel@tonic-gate		break;
11967c478bdstevel@tonic-gate	case DATA_TYPE_STRING_ARRAY: {
11977c478bdstevel@tonic-gate		char *const *strs = data;
11987c478bdstevel@tonic-gate		char *buf = NVP_VALUE(nvp);
11997c478bdstevel@tonic-gate		char **cstrs = (void *)buf;
12007c478bdstevel@tonic-gate
12017c478bdstevel@tonic-gate		/* skip pre-allocated space for pointer array */
12027c478bdstevel@tonic-gate		buf += nelem * sizeof (uint64_t);
12037c478bdstevel@tonic-gate		for (i = 0; i < nelem; i++) {
12047c478bdstevel@tonic-gate			int slen = strlen(strs[i]) + 1;
12057c478bdstevel@tonic-gate			bcopy(strs[i], buf, slen);
12067c478bdstevel@tonic-gate			cstrs[i] = buf;
12077c478bdstevel@tonic-gate			buf += slen;
12087c478bdstevel@tonic-gate		}
12097c478bdstevel@tonic-gate		break;
12107c478bdstevel@tonic-gate	}
12117c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST: {
12127c478bdstevel@tonic-gate		nvlist_t *nnvl = EMBEDDED_NVL(nvp);
12137c478bdstevel@tonic-gate		nvlist_t *onvl = (nvlist_t *)data;
12147c478bdstevel@tonic-gate
12157c478bdstevel@tonic-gate		if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) {
12167c478bdstevel@tonic-gate			nvp_buf_free(nvl, nvp);
12177c478bdstevel@tonic-gate			return (err);
12187c478bdstevel@tonic-gate		}
12197c478bdstevel@tonic-gate		break;
12207c478bdstevel@tonic-gate	}
12217c478bdstevel@tonic-gate	case DATA_TYPE_NVLIST_ARRAY: {
12227c478bdstevel@tonic-gate		nvlist_t **onvlp = (nvlist_t **)data;
12237c478bdstevel@tonic-gate		nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
12247c478bdstevel@tonic-gate		nvlist_t *embedded = (nvlist_t *)
12257c478bdstevel@tonic-gate		    ((uintptr_t)nvlp + nelem * sizeof (uint64_t));
12267c478bdstevel@tonic-gate
12277c478bdstevel@tonic-gate		for (i = 0; i < nelem; i++) {
12287c478bdstevel@tonic-gate			if ((err = nvlist_copy_embedded(nvl,
12297c478bdstevel@tonic-gate			    onvlp[i], embedded)) != 0) {
12307c478bdstevel@tonic-gate				/*
12317c478bdstevel@tonic-gate				 * Free any successfully created lists
12327c478bdstevel@tonic-gate				 */
12337c478bdstevel@tonic-gate				nvpair_free(nvp);
12347c478bdstevel@tonic-gate				nvp_buf_free(nvl, nvp);
12357c478bdstevel@tonic-gate				return (err);
12367c478bdstevel@tonic-gate			}
12377c478bdstevel@tonic-gate
12387c478bdstevel@tonic-gate			nvlp[i] = embedded++;
12397c478bdstevel@tonic-gate		}
12407c478bdstevel@tonic-gate		break;
12417c478bdstevel@tonic-gate	}
12427c478bdstevel@tonic-gate	default:
12437c478bdstevel@tonic-gate		bcopy(data, NVP_VALUE(nvp), value_sz);
12447c478bdstevel@tonic-gate	}
12457c478bdstevel@tonic-gate
12467c478bdstevel@tonic-gate	/* if unique name, remove before add */
12477c478bdstevel@tonic-gate	if (nvl->nvl_nvflag & NV_UNIQUE_NAME)
12487c478bdstevel@tonic-gate		(void) nvlist_remove_all(nvl, name);
12497c478bdstevel@tonic-gate	else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE)
12507c478bdstevel@tonic-gate		(void) nvlist_remove(nvl, name, type);
12517c478bdstevel@tonic-gate
12522ec7644Serapheim Dimitropoulos	err = nvt_add_nvpair(nvl, nvp);
12532ec7644Serapheim Dimitropoulos	if (err != 0) {
12542ec7644Serapheim Dimitropoulos		nvpair_free(nvp);
12552ec7644Serapheim Dimitropoulos		nvp_buf_free(nvl, nvp);
12562ec7644Serapheim Dimitropoulos		return (err);
12572ec7644Serapheim Dimitropoulos	}
12587c478bdstevel@tonic-gate	nvp_buf_link(nvl, nvp);
12597c478bdstevel@tonic-gate
12607c478bdstevel@tonic-gate	return (0);
12617c478bdstevel@tonic-gate}
12627c478bdstevel@tonic-gate
12637c478bdstevel@tonic-gateint
12647c478bdstevel@tonic-gatenvlist_add_boolean(nvlist_t *nvl, const char *name)
12657c478bdstevel@tonic-gate{
12667c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL));
12677c478bdstevel@tonic-gate}
12687c478bdstevel@tonic-gate
12697c478bdstevel@tonic-gateint
12707c478bdstevel@tonic-gatenvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
12717c478bdstevel@tonic-gate{
12727c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val));
12737c478bdstevel@tonic-gate}
12747c478bdstevel@tonic-gate
12757c478bdstevel@tonic-gateint
12767c478bdstevel@tonic-gatenvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
12777c478bdstevel@tonic-gate{
12787c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val));
12797c478bdstevel@tonic-gate}
12807c478bdstevel@tonic-gate
12817c478bdstevel@tonic-gateint
12827c478bdstevel@tonic-gatenvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
12837c478bdstevel@tonic-gate{
12847c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val));
12857c478bdstevel@tonic-gate}
12867c478bdstevel@tonic-gate
12877c478bdstevel@tonic-gateint
12887c478bdstevel@tonic-gatenvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
12897c478bdstevel@tonic-gate{
12907c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val));
12917c478bdstevel@tonic-gate}
12927c478bdstevel@tonic-gate
12937c478bdstevel@tonic-gateint
12947c478bdstevel@tonic-gatenvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
12957c478bdstevel@tonic-gate{
12967c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val));
12977c478bdstevel@tonic-gate}
12987c478bdstevel@tonic-gate
12997c478bdstevel@tonic-gateint
13007c478bdstevel@tonic-gatenvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
13017c478bdstevel@tonic-gate{
13027c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val));
13037c478bdstevel@tonic-gate}
13047c478bdstevel@tonic-gate
13057c478bdstevel@tonic-gateint
13067c478bdstevel@tonic-gatenvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
13077c478bdstevel@tonic-gate{
13087c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val));
13097c478bdstevel@tonic-gate}
13107c478bdstevel@tonic-gate
13117c478bdstevel@tonic-gateint
13127c478bdstevel@tonic-gatenvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
13137c478bdstevel@tonic-gate{
13147c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val));
13157c478bdstevel@tonic-gate}
13167c478bdstevel@tonic-gate
13177c478bdstevel@tonic-gateint
13187c478bdstevel@tonic-gatenvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
13197c478bdstevel@tonic-gate{
13207c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val));
13217c478bdstevel@tonic-gate}
13227c478bdstevel@tonic-gate
13237c478bdstevel@tonic-gateint
13247c478bdstevel@tonic-gatenvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
13257c478bdstevel@tonic-gate{
13267c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val));
13277c478bdstevel@tonic-gate}
13287c478bdstevel@tonic-gate
1329825ba0frobj#if !defined(_KERNEL)
1330825ba0frobjint
1331825ba0frobjnvlist_add_double(nvlist_t *nvl, const char *name, double val)
1332825ba0frobj{
1333825ba0frobj	return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val));
1334825ba0frobj}
1335825ba0frobj#endif
1336825ba0frobj
13377c478bdstevel@tonic-gateint
13387c478bdstevel@tonic-gatenvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
13397c478bdstevel@tonic-gate{
13407c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val));
13417c478bdstevel@tonic-gate}
13427c478bdstevel@tonic-gate
13437c478bdstevel@tonic-gateint
13447c478bdstevel@tonic-gatenvlist_add_boolean_array(nvlist_t *nvl, const char *name,
13457c478bdstevel@tonic-gate    boolean_t *a, uint_t n)
13467c478bdstevel@tonic-gate{
13477c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
13487c478bdstevel@tonic-gate}
13497c478bdstevel@tonic-gate
13507c478bdstevel@tonic-gateint
13517c478bdstevel@tonic-gatenvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *a, uint_t n)
13527c478bdstevel@tonic-gate{
13537c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
13547c478bdstevel@tonic-gate}
13557c478bdstevel@tonic-gate
13567c478bdstevel@tonic-gateint
13577c478bdstevel@tonic-gatenvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint_t n)
13587c478bdstevel@tonic-gate{
13597c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
13607c478bdstevel@tonic-gate}
13617c478bdstevel@tonic-gate
13627c478bdstevel@tonic-gateint
13637c478bdstevel@tonic-gatenvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint_t n)
13647c478bdstevel@tonic-gate{
13657c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
13667c478bdstevel@tonic-gate}
13677c478bdstevel@tonic-gate
13687c478bdstevel@tonic-gateint
13697c478bdstevel@tonic-gatenvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint_t n)
13707c478bdstevel@tonic-gate{
13717c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
13727c478bdstevel@tonic-gate}
13737c478bdstevel@tonic-gate
13747c478bdstevel@tonic-gateint
13757c478bdstevel@tonic-gatenvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, uint_t n)
13767c478bdstevel@tonic-gate{
13777c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
13787c478bdstevel@tonic-gate}
13797c478bdstevel@tonic-gate
13807c478bdstevel@tonic-gateint
13817c478bdstevel@tonic-gatenvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint_t n)
13827c478bdstevel@tonic-gate{
13837c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
13847c478bdstevel@tonic-gate}
13857c478bdstevel@tonic-gate
13867c478bdstevel@tonic-gateint
13877c478bdstevel@tonic-gatenvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, uint_t n)
13887c478bdstevel@tonic-gate{
13897c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
13907c478bdstevel@tonic-gate}
13917c478bdstevel@tonic-gate
13927c478bdstevel@tonic-gateint
13937c478bdstevel@tonic-gatenvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint_t n)
13947c478bdstevel@tonic-gate{
13957c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
13967c478bdstevel@tonic-gate}
13977c478bdstevel@tonic-gate
13987c478bdstevel@tonic-gateint
13997c478bdstevel@tonic-gatenvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, uint_t n)
14007c478bdstevel@tonic-gate{
14017c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
14027c478bdstevel@tonic-gate}
14037c478bdstevel@tonic-gate
14047c478bdstevel@tonic-gateint
14057c478bdstevel@tonic-gatenvlist_add_string_array(nvlist_t *nvl, const char *name,
14067c478bdstevel@tonic-gate    char *const *a, uint_t n)
14077c478bdstevel@tonic-gate{
14087c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
14097c478bdstevel@tonic-gate}
14107c478bdstevel@tonic-gate
14117c478bdstevel@tonic-gateint
14127c478bdstevel@tonic-gatenvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val)
14137c478bdstevel@tonic-gate{
14147c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val));
14157c478bdstevel@tonic-gate}
14167c478bdstevel@tonic-gate
14177c478bdstevel@tonic-gateint
14187c478bdstevel@tonic-gatenvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
14197c478bdstevel@tonic-gate{
14207c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
14217c478bdstevel@tonic-gate}
14227c478bdstevel@tonic-gate
14237c478bdstevel@tonic-gateint
14247c478bdstevel@tonic-gatenvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, uint_t n)
14257c478bdstevel@tonic-gate{
14267c478bdstevel@tonic-gate	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
14277c478bdstevel@tonic-gate}
14287c478bdstevel@tonic-gate
14297c478bdstevel@tonic-gate/* reading name-value pairs */
14307c478bdstevel@tonic-gatenvpair_t *
14317c478bdstevel@tonic-gatenvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp)
14327c478bdstevel@tonic-gate{
14337c478bdstevel@tonic-gate	nvpriv_t *priv;
14347c478bdstevel@tonic-gate	i_nvp_t *curr;
14357c478bdstevel@tonic-gate
14367c478bdstevel@tonic-gate	if (nvl == NULL ||
14377c478bdstevel@tonic-gate	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
14387c478bdstevel@tonic-gate		return (NULL);
14397c478bdstevel@tonic-gate
14407c478bdstevel@tonic-gate	curr = NVPAIR2I_NVP(nvp);
14417c478bdstevel@tonic-gate
14427c478bdstevel@tonic-gate	/*
14433cb34c6ahrens	 * Ensure that nvp is a valid nvpair on this nvlist.
14443cb34c6ahrens	 * NB: nvp_curr is used only as a hint so that we don't always
14453cb34c6ahrens	 * have to walk the list to determine if nvp is still on the list.
14467c478bdstevel@tonic-gate	 */
14477c478bdstevel@tonic-gate	if (nvp == NULL)
14487c478bdstevel@tonic-gate		curr = priv->nvp_list;
14493cb34c6ahrens	else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
14507c478bdstevel@tonic-gate		curr = curr->nvi_next;
14513cb34c6ahrens	else
14527c478bdstevel@tonic-gate		curr = NULL;
14537c478bdstevel@tonic-gate
14547c478bdstevel@tonic-gate	priv->nvp_curr = curr;
14557c478bdstevel@tonic-gate
14567c478bdstevel@tonic-gate	return (curr != NULL ? &curr->nvi_nvp : NULL);
14577c478bdstevel@tonic-gate}
14587c478bdstevel@tonic-gate
145992241e0Tom Ericksonnvpair_t *
146092241e0Tom Ericksonnvlist_prev_nvpair(nvlist_t *nvl, nvpair_t *nvp)
146192241e0Tom Erickson{
146292241e0Tom Erickson	nvpriv_t *priv;
146392241e0Tom Erickson	i_nvp_t *curr;
146492241e0Tom Erickson
146592241e0Tom Erickson	if (nvl == NULL ||
146692241e0Tom Erickson	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
146792241e0Tom Erickson		return (NULL);
146892241e0Tom Erickson
146992241e0Tom Erickson	curr = NVPAIR2I_NVP(nvp);
147092241e0Tom Erickson
147192241e0Tom Erickson	if (nvp == NULL)
147292241e0Tom Erickson		curr = priv->nvp_last;
147392241e0Tom Erickson	else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
147492241e0Tom Erickson		curr = curr->nvi_prev;
147592241e0Tom Erickson	else
147692241e0Tom Erickson		curr = NULL;
147792241e0Tom Erickson
147892241e0Tom Erickson	priv->nvp_curr = curr;
147992241e0Tom Erickson
148092241e0Tom Erickson	return (curr != NULL ? &curr->nvi_nvp : NULL);
148192241e0Tom Erickson}
148292241e0Tom Erickson
148392241e0Tom Ericksonboolean_t
148492241e0Tom Ericksonnvlist_empty(nvlist_t *nvl)
148592241e0Tom Erickson{
148692241e0Tom Erickson	nvpriv_t *priv;
148792241e0Tom Erickson
148892241e0Tom Erickson	if (nvl == NULL ||
148992241e0Tom Erickson	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
149092241e0Tom Erickson		return (B_TRUE);
149192241e0Tom Erickson
149292241e0Tom Erickson	return (priv->nvp_list == NULL);
149392241e0Tom Erickson}
149492241e0Tom Erickson
14957c478bdstevel@tonic-gatechar *
14967c478bdstevel@tonic-gatenvpair_name(nvpair_t *nvp)
14977c478bdstevel@tonic-gate{
14987c478bdstevel@tonic-gate	return (NVP_NAME(nvp));
14997c478bdstevel@tonic-gate}
15007c478bdstevel@tonic-gate
15017c478bdstevel@tonic-gatedata_type_t
15027c478bdstevel@tonic-gatenvpair_type(nvpair_t *nvp)
15037c478bdstevel@tonic-gate{
15047c478bdstevel@tonic-gate	return (NVP_TYPE(nvp));
15057c478bdstevel@tonic-gate}
15067c478bdstevel@tonic-gate
1507602ca9ecthint
1508602ca9ecthnvpair_type_is_array(nvpair_t *nvp)
1509602ca9ecth{
1510602ca9ecth	data_type_t type = NVP_TYPE(nvp);
1511602ca9ecth
1512