Path: blob/main/sys/contrib/openzfs/module/nvpair/nvpair.c
48383 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.24* Copyright (c) 2015, 2017 by Delphix. All rights reserved.25* Copyright 2018 RackTop Systems.26*/2728/*29* Links to Illumos.org for more information on Interface Libraries:30* [1] https://illumos.org/man/3lib/libnvpair31* [2] https://illumos.org/man/3nvpair/nvlist_alloc32* [3] https://illumos.org/man/9f/nvlist_alloc33* [4] https://illumos.org/man/9f/nvlist_next_nvpair34* [5] https://illumos.org/man/9f/nvpair_value_byte35*/3637#include <sys/debug.h>38#include <sys/isa_defs.h>39#include <sys/nvpair.h>40#include <sys/nvpair_impl.h>41#include <sys/types.h>42#include <sys/param.h>43#include <sys/string.h>44#include <rpc/types.h>45#include <rpc/xdr.h>46#include <sys/mod.h>4748#if defined(_KERNEL)49#include <sys/sunddi.h>50#include <sys/sysmacros.h>51#else52#include <stdarg.h>53#include <stdlib.h>54#include <stddef.h>55#endif5657#define skip_whitespace(p) while ((*(p) == ' ') || (*(p) == '\t')) (p)++5859/*60* nvpair.c - Provides kernel & userland interfaces for manipulating61* name-value pairs.62*63* Overview Diagram64*65* +--------------+66* | nvlist_t |67* |--------------|68* | nvl_version |69* | nvl_nvflag |70* | nvl_priv -+-+71* | nvl_flag | |72* | nvl_pad | |73* +--------------+ |74* V75* +--------------+ last i_nvp in list76* | nvpriv_t | +--------------------->77* |--------------| |78* +--+- nvp_list | | +------------+79* | | nvp_last -+--+ + nv_alloc_t |80* | | nvp_curr | |------------|81* | | nvp_nva -+----> | nva_ops |82* | | nvp_stat | | nva_arg |83* | +--------------+ +------------+84* |85* +-------+86* V87* +---------------------+ +-------------------+88* | i_nvp_t | +-->| i_nvp_t | +-->89* |---------------------| | |-------------------| |90* | nvi_next -+--+ | nvi_next -+--+91* | nvi_prev (NULL) | <----+ nvi_prev |92* | . . . . . . . . . . | | . . . . . . . . . |93* | nvp (nvpair_t) | | nvp (nvpair_t) |94* | - nvp_size | | - nvp_size |95* | - nvp_name_sz | | - nvp_name_sz |96* | - nvp_value_elem | | - nvp_value_elem |97* | - nvp_type | | - nvp_type |98* | - data ... | | - data ... |99* +---------------------+ +-------------------+100*101*102*103* +---------------------+ +---------------------+104* | i_nvp_t | +--> +-->| i_nvp_t (last) |105* |---------------------| | | |---------------------|106* | nvi_next -+--+ ... --+ | nvi_next (NULL) |107* <-+- nvi_prev |<-- ... <----+ nvi_prev |108* | . . . . . . . . . | | . . . . . . . . . |109* | nvp (nvpair_t) | | nvp (nvpair_t) |110* | - nvp_size | | - nvp_size |111* | - nvp_name_sz | | - nvp_name_sz |112* | - nvp_value_elem | | - nvp_value_elem |113* | - DATA_TYPE_NVLIST | | - nvp_type |114* | - data (embedded) | | - data ... |115* | nvlist name | +---------------------+116* | +--------------+ |117* | | nvlist_t | |118* | |--------------| |119* | | nvl_version | |120* | | nvl_nvflag | |121* | | nvl_priv --+---+---->122* | | nvl_flag | |123* | | nvl_pad | |124* | +--------------+ |125* +---------------------+126*127*128* N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will129* allow value to be aligned on 8 byte boundary130*131* name_len is the length of the name string including the null terminator132* so it must be >= 1133*/134#define NVP_SIZE_CALC(name_len, data_len) \135(NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))136137static int i_get_value_size(data_type_t type, const void *data, uint_t nelem);138static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,139uint_t nelem, const void *data);140141#define NV_STAT_EMBEDDED 0x1142#define EMBEDDED_NVL(nvp) ((nvlist_t *)(void *)NVP_VALUE(nvp))143#define EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp))144145#define NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))146#define NVPAIR2I_NVP(nvp) \147((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))148149#ifdef _KERNEL150static const int nvpair_max_recursion = 20;151#else152static const int nvpair_max_recursion = 100;153#endif154155static const uint64_t nvlist_hashtable_init_size = (1 << 4);156157int158nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)159{160va_list valist;161int err = 0;162163nva->nva_ops = nvo;164nva->nva_arg = NULL;165166va_start(valist, nvo);167if (nva->nva_ops->nv_ao_init != NULL)168err = nva->nva_ops->nv_ao_init(nva, valist);169va_end(valist);170171return (err);172}173174void175nv_alloc_reset(nv_alloc_t *nva)176{177if (nva->nva_ops->nv_ao_reset != NULL)178nva->nva_ops->nv_ao_reset(nva);179}180181void182nv_alloc_fini(nv_alloc_t *nva)183{184if (nva->nva_ops->nv_ao_fini != NULL)185nva->nva_ops->nv_ao_fini(nva);186}187188nv_alloc_t *189nvlist_lookup_nv_alloc(nvlist_t *nvl)190{191nvpriv_t *priv;192193if (nvl == NULL ||194(priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)195return (NULL);196197return (priv->nvp_nva);198}199200static void *201nv_mem_zalloc(nvpriv_t *nvp, size_t size)202{203nv_alloc_t *nva = nvp->nvp_nva;204void *buf;205206if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)207memset(buf, 0, size);208209return (buf);210}211212static void213nv_mem_free(nvpriv_t *nvp, void *buf, size_t size)214{215nv_alloc_t *nva = nvp->nvp_nva;216217nva->nva_ops->nv_ao_free(nva, buf, size);218}219220static void221nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)222{223memset(priv, 0, sizeof (nvpriv_t));224225priv->nvp_nva = nva;226priv->nvp_stat = stat;227}228229static nvpriv_t *230nv_priv_alloc(nv_alloc_t *nva)231{232nvpriv_t *priv;233234/*235* nv_mem_alloc() cannot called here because it needs the priv236* argument.237*/238if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)239return (NULL);240241nv_priv_init(priv, nva, 0);242243return (priv);244}245246/*247* Embedded lists need their own nvpriv_t's. We create a new248* nvpriv_t using the parameters and allocator from the parent249* list's nvpriv_t.250*/251static nvpriv_t *252nv_priv_alloc_embedded(nvpriv_t *priv)253{254nvpriv_t *emb_priv;255256if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)257return (NULL);258259nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);260261return (emb_priv);262}263264static int265nvt_tab_alloc(nvpriv_t *priv, uint64_t buckets)266{267ASSERT0P(priv->nvp_hashtable);268ASSERT0(priv->nvp_nbuckets);269ASSERT0(priv->nvp_nentries);270271i_nvp_t **tab = nv_mem_zalloc(priv, buckets * sizeof (i_nvp_t *));272if (tab == NULL)273return (ENOMEM);274275priv->nvp_hashtable = tab;276priv->nvp_nbuckets = buckets;277return (0);278}279280static void281nvt_tab_free(nvpriv_t *priv)282{283i_nvp_t **tab = priv->nvp_hashtable;284if (tab == NULL) {285ASSERT0(priv->nvp_nbuckets);286ASSERT0(priv->nvp_nentries);287return;288}289290nv_mem_free(priv, tab, priv->nvp_nbuckets * sizeof (i_nvp_t *));291292priv->nvp_hashtable = NULL;293priv->nvp_nbuckets = 0;294priv->nvp_nentries = 0;295}296297static uint32_t298nvt_hash(const char *p)299{300uint32_t g, hval = 0;301302while (*p) {303hval = (hval << 4) + *p++;304if ((g = (hval & 0xf0000000)) != 0)305hval ^= g >> 24;306hval &= ~g;307}308return (hval);309}310311static boolean_t312nvt_nvpair_match(const nvpair_t *nvp1, const nvpair_t *nvp2, uint32_t nvflag)313{314boolean_t match = B_FALSE;315if (nvflag & NV_UNIQUE_NAME_TYPE) {316if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0 &&317NVP_TYPE(nvp1) == NVP_TYPE(nvp2))318match = B_TRUE;319} else {320ASSERT(nvflag == 0 || nvflag & NV_UNIQUE_NAME);321if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0)322match = B_TRUE;323}324return (match);325}326327static nvpair_t *328nvt_lookup_name_type(const nvlist_t *nvl, const char *name, data_type_t type)329{330const nvpriv_t *priv = (const nvpriv_t *)(uintptr_t)nvl->nvl_priv;331ASSERT(priv != NULL);332333i_nvp_t **tab = priv->nvp_hashtable;334335if (tab == NULL) {336ASSERT0P(priv->nvp_list);337ASSERT0(priv->nvp_nbuckets);338ASSERT0(priv->nvp_nentries);339return (NULL);340} else {341ASSERT(priv->nvp_nbuckets != 0);342}343344uint64_t hash = nvt_hash(name);345uint64_t index = hash & (priv->nvp_nbuckets - 1);346347ASSERT3U(index, <, priv->nvp_nbuckets);348i_nvp_t *entry = tab[index];349350for (i_nvp_t *e = entry; e != NULL; e = e->nvi_hashtable_next) {351if (strcmp(NVP_NAME(&e->nvi_nvp), name) == 0 &&352(type == DATA_TYPE_DONTCARE ||353NVP_TYPE(&e->nvi_nvp) == type))354return (&e->nvi_nvp);355}356return (NULL);357}358359static nvpair_t *360nvt_lookup_name(const nvlist_t *nvl, const char *name)361{362return (nvt_lookup_name_type(nvl, name, DATA_TYPE_DONTCARE));363}364365static int366nvt_resize(nvpriv_t *priv, uint32_t new_size)367{368i_nvp_t **tab = priv->nvp_hashtable;369370/*371* Migrate all the entries from the current table372* to a newly-allocated table with the new size by373* re-adjusting the pointers of their entries.374*/375uint32_t size = priv->nvp_nbuckets;376uint32_t new_mask = new_size - 1;377ASSERT(ISP2(new_size));378379i_nvp_t **new_tab = nv_mem_zalloc(priv, new_size * sizeof (i_nvp_t *));380if (new_tab == NULL)381return (ENOMEM);382383uint32_t nentries = 0;384for (uint32_t i = 0; i < size; i++) {385i_nvp_t *next, *e = tab[i];386387while (e != NULL) {388next = e->nvi_hashtable_next;389390uint32_t hash = nvt_hash(NVP_NAME(&e->nvi_nvp));391uint32_t index = hash & new_mask;392393e->nvi_hashtable_next = new_tab[index];394new_tab[index] = e;395nentries++;396397e = next;398}399tab[i] = NULL;400}401ASSERT3U(nentries, ==, priv->nvp_nentries);402403nvt_tab_free(priv);404405priv->nvp_hashtable = new_tab;406priv->nvp_nbuckets = new_size;407priv->nvp_nentries = nentries;408409return (0);410}411412static boolean_t413nvt_needs_togrow(nvpriv_t *priv)414{415/*416* Grow only when we have more elements than buckets417* and the # of buckets doesn't overflow.418*/419return (priv->nvp_nentries > priv->nvp_nbuckets &&420(UINT32_MAX >> 1) >= priv->nvp_nbuckets);421}422423/*424* Allocate a new table that's twice the size of the old one,425* and migrate all the entries from the old one to the new426* one by re-adjusting their pointers.427*/428static int429nvt_grow(nvpriv_t *priv)430{431uint32_t current_size = priv->nvp_nbuckets;432/* ensure we won't overflow */433ASSERT3U(UINT32_MAX >> 1, >=, current_size);434return (nvt_resize(priv, current_size << 1));435}436437static boolean_t438nvt_needs_toshrink(nvpriv_t *priv)439{440/*441* Shrink only when the # of elements is less than or442* equal to 1/4 the # of buckets. Never shrink less than443* nvlist_hashtable_init_size.444*/445ASSERT3U(priv->nvp_nbuckets, >=, nvlist_hashtable_init_size);446if (priv->nvp_nbuckets == nvlist_hashtable_init_size)447return (B_FALSE);448return (priv->nvp_nentries <= (priv->nvp_nbuckets >> 2));449}450451/*452* Allocate a new table that's half the size of the old one,453* and migrate all the entries from the old one to the new454* one by re-adjusting their pointers.455*/456static int457nvt_shrink(nvpriv_t *priv)458{459uint32_t current_size = priv->nvp_nbuckets;460/* ensure we won't overflow */461ASSERT3U(current_size, >=, nvlist_hashtable_init_size);462return (nvt_resize(priv, current_size >> 1));463}464465static int466nvt_remove_nvpair(nvlist_t *nvl, const nvpair_t *nvp)467{468nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;469470if (nvt_needs_toshrink(priv)) {471int err = nvt_shrink(priv);472if (err != 0)473return (err);474}475i_nvp_t **tab = priv->nvp_hashtable;476477const char *name = NVP_NAME(nvp);478uint64_t hash = nvt_hash(name);479uint64_t index = hash & (priv->nvp_nbuckets - 1);480481ASSERT3U(index, <, priv->nvp_nbuckets);482i_nvp_t *bucket = tab[index];483484for (i_nvp_t *prev = NULL, *e = bucket;485e != NULL; prev = e, e = e->nvi_hashtable_next) {486if (nvt_nvpair_match(&e->nvi_nvp, nvp, nvl->nvl_nvflag)) {487if (prev != NULL) {488prev->nvi_hashtable_next =489e->nvi_hashtable_next;490} else {491ASSERT3P(e, ==, bucket);492tab[index] = e->nvi_hashtable_next;493}494e->nvi_hashtable_next = NULL;495priv->nvp_nentries--;496break;497}498}499500return (0);501}502503static int504nvt_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)505{506nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;507508/* initialize nvpair table now if it doesn't exist. */509if (priv->nvp_hashtable == NULL) {510int err = nvt_tab_alloc(priv, nvlist_hashtable_init_size);511if (err != 0)512return (err);513}514515/*516* if we don't allow duplicate entries, make sure to517* unlink any existing entries from the table.518*/519if (nvl->nvl_nvflag != 0) {520int err = nvt_remove_nvpair(nvl, nvp);521if (err != 0)522return (err);523}524525if (nvt_needs_togrow(priv)) {526int err = nvt_grow(priv);527if (err != 0)528return (err);529}530i_nvp_t **tab = priv->nvp_hashtable;531532const char *name = NVP_NAME(nvp);533uint64_t hash = nvt_hash(name);534uint64_t index = hash & (priv->nvp_nbuckets - 1);535536ASSERT3U(index, <, priv->nvp_nbuckets);537// cppcheck-suppress nullPointerRedundantCheck538i_nvp_t *bucket = tab[index];539540/* insert link at the beginning of the bucket */541i_nvp_t *new_entry = NVPAIR2I_NVP(nvp);542ASSERT0P(new_entry->nvi_hashtable_next);543new_entry->nvi_hashtable_next = bucket;544// cppcheck-suppress nullPointerRedundantCheck545tab[index] = new_entry;546547priv->nvp_nentries++;548return (0);549}550551static void552nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)553{554nvl->nvl_version = NV_VERSION;555nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);556nvl->nvl_priv = (uint64_t)(uintptr_t)priv;557nvl->nvl_flag = 0;558nvl->nvl_pad = 0;559}560561uint_t562nvlist_nvflag(nvlist_t *nvl)563{564return (nvl->nvl_nvflag);565}566567static nv_alloc_t *568nvlist_nv_alloc(int kmflag)569{570#if defined(_KERNEL)571switch (kmflag) {572case KM_SLEEP:573return (nv_alloc_sleep);574case KM_NOSLEEP:575return (nv_alloc_nosleep);576default:577return (nv_alloc_pushpage);578}579#else580(void) kmflag;581return (nv_alloc_nosleep);582#endif /* _KERNEL */583}584585/*586* nvlist_alloc - Allocate nvlist.587*/588int589nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)590{591return (nvlist_xalloc(nvlp, nvflag, nvlist_nv_alloc(kmflag)));592}593594int595nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)596{597nvpriv_t *priv;598599if (nvlp == NULL || nva == NULL)600return (EINVAL);601602if ((priv = nv_priv_alloc(nva)) == NULL)603return (ENOMEM);604605if ((*nvlp = nv_mem_zalloc(priv,606NV_ALIGN(sizeof (nvlist_t)))) == NULL) {607nv_mem_free(priv, priv, sizeof (nvpriv_t));608return (ENOMEM);609}610611nvlist_init(*nvlp, nvflag, priv);612613return (0);614}615616/*617* nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.618*/619static nvpair_t *620nvp_buf_alloc(nvlist_t *nvl, size_t len)621{622nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;623i_nvp_t *buf;624nvpair_t *nvp;625size_t nvsize;626627/*628* Allocate the buffer629*/630nvsize = len + offsetof(i_nvp_t, nvi_nvp);631632if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)633return (NULL);634635nvp = &buf->nvi_nvp;636nvp->nvp_size = len;637638return (nvp);639}640641/*642* nvp_buf_free - de-Allocate an i_nvp_t.643*/644static void645nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)646{647nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;648size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);649650nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);651}652653/*654* nvp_buf_link - link a new nv pair into the nvlist.655*/656static void657nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)658{659nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;660i_nvp_t *curr = NVPAIR2I_NVP(nvp);661662/* Put element at end of nvlist */663if (priv->nvp_list == NULL) {664priv->nvp_list = priv->nvp_last = curr;665} else {666curr->nvi_prev = priv->nvp_last;667priv->nvp_last->nvi_next = curr;668priv->nvp_last = curr;669}670}671672/*673* nvp_buf_unlink - unlink an removed nvpair out of the nvlist.674*/675static void676nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)677{678nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;679i_nvp_t *curr = NVPAIR2I_NVP(nvp);680681/*682* protect nvlist_next_nvpair() against walking on freed memory.683*/684if (priv->nvp_curr == curr)685priv->nvp_curr = curr->nvi_next;686687if (curr == priv->nvp_list)688priv->nvp_list = curr->nvi_next;689else690curr->nvi_prev->nvi_next = curr->nvi_next;691692if (curr == priv->nvp_last)693priv->nvp_last = curr->nvi_prev;694else695curr->nvi_next->nvi_prev = curr->nvi_prev;696}697698/*699* take a nvpair type and number of elements and make sure the are valid700*/701static int702i_validate_type_nelem(data_type_t type, uint_t nelem)703{704switch (type) {705case DATA_TYPE_BOOLEAN:706if (nelem != 0)707return (EINVAL);708break;709case DATA_TYPE_BOOLEAN_VALUE:710case DATA_TYPE_BYTE:711case DATA_TYPE_INT8:712case DATA_TYPE_UINT8:713case DATA_TYPE_INT16:714case DATA_TYPE_UINT16:715case DATA_TYPE_INT32:716case DATA_TYPE_UINT32:717case DATA_TYPE_INT64:718case DATA_TYPE_UINT64:719case DATA_TYPE_STRING:720case DATA_TYPE_HRTIME:721case DATA_TYPE_NVLIST:722#if !defined(_KERNEL)723case DATA_TYPE_DOUBLE:724#endif725if (nelem != 1)726return (EINVAL);727break;728case DATA_TYPE_BOOLEAN_ARRAY:729case DATA_TYPE_BYTE_ARRAY:730case DATA_TYPE_INT8_ARRAY:731case DATA_TYPE_UINT8_ARRAY:732case DATA_TYPE_INT16_ARRAY:733case DATA_TYPE_UINT16_ARRAY:734case DATA_TYPE_INT32_ARRAY:735case DATA_TYPE_UINT32_ARRAY:736case DATA_TYPE_INT64_ARRAY:737case DATA_TYPE_UINT64_ARRAY:738case DATA_TYPE_STRING_ARRAY:739case DATA_TYPE_NVLIST_ARRAY:740/* we allow arrays with 0 elements */741break;742default:743return (EINVAL);744}745return (0);746}747748/*749* Verify nvp_name_sz and check the name string length.750*/751static int752i_validate_nvpair_name(nvpair_t *nvp)753{754if ((nvp->nvp_name_sz <= 0) ||755(nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))756return (EFAULT);757758/* verify the name string, make sure its terminated */759if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')760return (EFAULT);761762return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);763}764765static int766i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)767{768switch (type) {769case DATA_TYPE_BOOLEAN_VALUE:770if (*(boolean_t *)data != B_TRUE &&771*(boolean_t *)data != B_FALSE)772return (EINVAL);773break;774case DATA_TYPE_BOOLEAN_ARRAY: {775int i;776777for (i = 0; i < nelem; i++)778if (((boolean_t *)data)[i] != B_TRUE &&779((boolean_t *)data)[i] != B_FALSE)780return (EINVAL);781break;782}783default:784break;785}786787return (0);788}789790/*791* This function takes a pointer to what should be a nvpair and it's size792* and then verifies that all the nvpair fields make sense and can be793* trusted. This function is used when decoding packed nvpairs.794*/795static int796i_validate_nvpair(nvpair_t *nvp)797{798data_type_t type = NVP_TYPE(nvp);799int size1, size2;800801/* verify nvp_name_sz, check the name string length */802if (i_validate_nvpair_name(nvp) != 0)803return (EFAULT);804805if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)806return (EFAULT);807808/*809* verify nvp_type, nvp_value_elem, and also possibly810* verify string values and get the value size.811*/812size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));813size1 = nvp->nvp_size - NVP_VALOFF(nvp);814if (size2 < 0 || size1 != NV_ALIGN(size2))815return (EFAULT);816817return (0);818}819820static int821nvlist_copy_pairs(const nvlist_t *snvl, nvlist_t *dnvl)822{823const nvpriv_t *priv;824const i_nvp_t *curr;825826if ((priv = (const nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)827return (EINVAL);828829for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {830const nvpair_t *nvp = &curr->nvi_nvp;831int err;832833if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),834NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)835return (err);836}837838return (0);839}840841/*842* Frees all memory allocated for an nvpair (like embedded lists) with843* the exception of the nvpair buffer itself.844*/845static void846nvpair_free(nvpair_t *nvp)847{848switch (NVP_TYPE(nvp)) {849case DATA_TYPE_NVLIST:850nvlist_free(EMBEDDED_NVL(nvp));851break;852case DATA_TYPE_NVLIST_ARRAY: {853nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);854int i;855856for (i = 0; i < NVP_NELEM(nvp); i++)857if (nvlp[i] != NULL)858nvlist_free(nvlp[i]);859break;860}861default:862break;863}864}865866/*867* nvlist_free - free an unpacked nvlist868*/869void870nvlist_free(nvlist_t *nvl)871{872nvpriv_t *priv;873i_nvp_t *curr;874875if (nvl == NULL ||876(priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)877return;878879/*880* Unpacked nvlist are linked through i_nvp_t881*/882curr = priv->nvp_list;883while (curr != NULL) {884nvpair_t *nvp = &curr->nvi_nvp;885curr = curr->nvi_next;886887nvpair_free(nvp);888nvp_buf_free(nvl, nvp);889}890891if (!(priv->nvp_stat & NV_STAT_EMBEDDED))892nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));893else894nvl->nvl_priv = 0;895896nvt_tab_free(priv);897nv_mem_free(priv, priv, sizeof (nvpriv_t));898}899900static int901nvlist_contains_nvp(const nvlist_t *nvl, const nvpair_t *nvp)902{903const nvpriv_t *priv = (const nvpriv_t *)(uintptr_t)nvl->nvl_priv;904const i_nvp_t *curr;905906if (nvp == NULL)907return (0);908909for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)910if (&curr->nvi_nvp == nvp)911return (1);912913return (0);914}915916/*917* Make a copy of nvlist918*/919int920nvlist_dup(const nvlist_t *nvl, nvlist_t **nvlp, int kmflag)921{922return (nvlist_xdup(nvl, nvlp, nvlist_nv_alloc(kmflag)));923}924925int926nvlist_xdup(const nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)927{928int err;929nvlist_t *ret;930931if (nvl == NULL || nvlp == NULL)932return (EINVAL);933934if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0)935return (err);936937if ((err = nvlist_copy_pairs(nvl, ret)) != 0)938nvlist_free(ret);939else940*nvlp = ret;941942return (err);943}944945/*946* Remove all with matching name947*/948int949nvlist_remove_all(nvlist_t *nvl, const char *name)950{951int error = ENOENT;952953if (nvl == NULL || name == NULL || nvl->nvl_priv == 0)954return (EINVAL);955956nvpair_t *nvp;957while ((nvp = nvt_lookup_name(nvl, name)) != NULL) {958VERIFY0(nvlist_remove_nvpair(nvl, nvp));959error = 0;960}961962return (error);963}964965/*966* Remove first one with matching name and type967*/968int969nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)970{971if (nvl == NULL || name == NULL || nvl->nvl_priv == 0)972return (EINVAL);973974nvpair_t *nvp = nvt_lookup_name_type(nvl, name, type);975if (nvp == NULL)976return (ENOENT);977978return (nvlist_remove_nvpair(nvl, nvp));979}980981int982nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)983{984if (nvl == NULL || nvp == NULL)985return (EINVAL);986987int err = nvt_remove_nvpair(nvl, nvp);988if (err != 0)989return (err);990991nvp_buf_unlink(nvl, nvp);992nvpair_free(nvp);993nvp_buf_free(nvl, nvp);994return (0);995}996997/*998* This function calculates the size of an nvpair value.999*1000* The data argument controls the behavior in case of the data types1001* DATA_TYPE_STRING and1002* DATA_TYPE_STRING_ARRAY1003* Is data == NULL then the size of the string(s) is excluded.1004*/1005static int1006i_get_value_size(data_type_t type, const void *data, uint_t nelem)1007{1008uint64_t value_sz;10091010if (i_validate_type_nelem(type, nelem) != 0)1011return (-1);10121013/* Calculate required size for holding value */1014switch (type) {1015case DATA_TYPE_BOOLEAN:1016value_sz = 0;1017break;1018case DATA_TYPE_BOOLEAN_VALUE:1019value_sz = sizeof (boolean_t);1020break;1021case DATA_TYPE_BYTE:1022value_sz = sizeof (uchar_t);1023break;1024case DATA_TYPE_INT8:1025value_sz = sizeof (int8_t);1026break;1027case DATA_TYPE_UINT8:1028value_sz = sizeof (uint8_t);1029break;1030case DATA_TYPE_INT16:1031value_sz = sizeof (int16_t);1032break;1033case DATA_TYPE_UINT16:1034value_sz = sizeof (uint16_t);1035break;1036case DATA_TYPE_INT32:1037value_sz = sizeof (int32_t);1038break;1039case DATA_TYPE_UINT32:1040value_sz = sizeof (uint32_t);1041break;1042case DATA_TYPE_INT64:1043value_sz = sizeof (int64_t);1044break;1045case DATA_TYPE_UINT64:1046value_sz = sizeof (uint64_t);1047break;1048#if !defined(_KERNEL)1049case DATA_TYPE_DOUBLE:1050value_sz = sizeof (double);1051break;1052#endif1053case DATA_TYPE_STRING:1054if (data == NULL)1055value_sz = 0;1056else1057value_sz = strlen(data) + 1;1058break;1059case DATA_TYPE_BOOLEAN_ARRAY:1060value_sz = (uint64_t)nelem * sizeof (boolean_t);1061break;1062case DATA_TYPE_BYTE_ARRAY:1063value_sz = (uint64_t)nelem * sizeof (uchar_t);1064break;1065case DATA_TYPE_INT8_ARRAY:1066value_sz = (uint64_t)nelem * sizeof (int8_t);1067break;1068case DATA_TYPE_UINT8_ARRAY:1069value_sz = (uint64_t)nelem * sizeof (uint8_t);1070break;1071case DATA_TYPE_INT16_ARRAY:1072value_sz = (uint64_t)nelem * sizeof (int16_t);1073break;1074case DATA_TYPE_UINT16_ARRAY:1075value_sz = (uint64_t)nelem * sizeof (uint16_t);1076break;1077case DATA_TYPE_INT32_ARRAY:1078value_sz = (uint64_t)nelem * sizeof (int32_t);1079break;1080case DATA_TYPE_UINT32_ARRAY:1081value_sz = (uint64_t)nelem * sizeof (uint32_t);1082break;1083case DATA_TYPE_INT64_ARRAY:1084value_sz = (uint64_t)nelem * sizeof (int64_t);1085break;1086case DATA_TYPE_UINT64_ARRAY:1087value_sz = (uint64_t)nelem * sizeof (uint64_t);1088break;1089case DATA_TYPE_STRING_ARRAY:1090value_sz = (uint64_t)nelem * sizeof (uint64_t);10911092if (data != NULL) {1093char *const *strs = data;1094uint_t i;10951096/* no alignment requirement for strings */1097for (i = 0; i < nelem; i++) {1098if (strs[i] == NULL)1099return (-1);1100value_sz += strlen(strs[i]) + 1;1101}1102}1103break;1104case DATA_TYPE_HRTIME:1105value_sz = sizeof (hrtime_t);1106break;1107case DATA_TYPE_NVLIST:1108value_sz = NV_ALIGN(sizeof (nvlist_t));1109break;1110case DATA_TYPE_NVLIST_ARRAY:1111value_sz = (uint64_t)nelem * sizeof (uint64_t) +1112(uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));1113break;1114default:1115return (-1);1116}11171118return (value_sz > INT32_MAX ? -1 : (int)value_sz);1119}11201121static int1122nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl)1123{1124nvpriv_t *priv;1125int err;11261127if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t)1128nvl->nvl_priv)) == NULL)1129return (ENOMEM);11301131nvlist_init(emb_nvl, onvl->nvl_nvflag, priv);11321133if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) {1134nvlist_free(emb_nvl);1135emb_nvl->nvl_priv = 0;1136}11371138return (err);1139}11401141/*1142* nvlist_add_common - Add new <name,value> pair to nvlist1143*/1144static int1145nvlist_add_common(nvlist_t *nvl, const char *name,1146data_type_t type, uint_t nelem, const void *data)1147{1148nvpair_t *nvp;1149uint_t i;11501151int nvp_sz, name_sz, value_sz;1152int err = 0;11531154if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)1155return (EINVAL);11561157if (nelem != 0 && data == NULL)1158return (EINVAL);11591160/*1161* Verify type and nelem and get the value size.1162* In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY1163* is the size of the string(s) included.1164*/1165if ((value_sz = i_get_value_size(type, data, nelem)) < 0)1166return (EINVAL);11671168if (i_validate_nvpair_value(type, nelem, data) != 0)1169return (EINVAL);11701171/*1172* If we're adding an nvlist or nvlist array, ensure that we are not1173* adding the input nvlist to itself, which would cause recursion,1174* and ensure that no NULL nvlist pointers are present.1175*/1176switch (type) {1177case DATA_TYPE_NVLIST:1178if (data == nvl || data == NULL)1179return (EINVAL);1180break;1181case DATA_TYPE_NVLIST_ARRAY: {1182nvlist_t **onvlp = (nvlist_t **)data;1183for (i = 0; i < nelem; i++) {1184if (onvlp[i] == nvl || onvlp[i] == NULL)1185return (EINVAL);1186}1187break;1188}1189default:1190break;1191}11921193/* calculate sizes of the nvpair elements and the nvpair itself */1194name_sz = strlen(name) + 1;1195if (name_sz >= 1ULL << (sizeof (nvp->nvp_name_sz) * NBBY - 1))1196return (EINVAL);11971198nvp_sz = NVP_SIZE_CALC(name_sz, value_sz);11991200if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL)1201return (ENOMEM);12021203ASSERT(nvp->nvp_size == nvp_sz);1204nvp->nvp_name_sz = name_sz;1205nvp->nvp_value_elem = nelem;1206nvp->nvp_type = type;1207memcpy(NVP_NAME(nvp), name, name_sz);12081209switch (type) {1210case DATA_TYPE_BOOLEAN:1211break;1212case DATA_TYPE_STRING_ARRAY: {1213char *const *strs = data;1214char *buf = NVP_VALUE(nvp);1215char **cstrs = (void *)buf;12161217/* skip pre-allocated space for pointer array */1218buf += nelem * sizeof (uint64_t);1219for (i = 0; i < nelem; i++) {1220int slen = strlen(strs[i]) + 1;1221memcpy(buf, strs[i], slen);1222cstrs[i] = buf;1223buf += slen;1224}1225break;1226}1227case DATA_TYPE_NVLIST: {1228nvlist_t *nnvl = EMBEDDED_NVL(nvp);1229nvlist_t *onvl = (nvlist_t *)data;12301231if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) {1232nvp_buf_free(nvl, nvp);1233return (err);1234}1235break;1236}1237case DATA_TYPE_NVLIST_ARRAY: {1238nvlist_t **onvlp = (nvlist_t **)data;1239nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);1240nvlist_t *embedded = (nvlist_t *)1241((uintptr_t)nvlp + nelem * sizeof (uint64_t));12421243for (i = 0; i < nelem; i++) {1244if ((err = nvlist_copy_embedded(nvl,1245onvlp[i], embedded)) != 0) {1246/*1247* Free any successfully created lists1248*/1249nvpair_free(nvp);1250nvp_buf_free(nvl, nvp);1251return (err);1252}12531254nvlp[i] = embedded++;1255}1256break;1257}1258default:1259memcpy(NVP_VALUE(nvp), data, value_sz);1260}12611262/* if unique name, remove before add */1263if (nvl->nvl_nvflag & NV_UNIQUE_NAME)1264(void) nvlist_remove_all(nvl, name);1265else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE)1266(void) nvlist_remove(nvl, name, type);12671268err = nvt_add_nvpair(nvl, nvp);1269if (err != 0) {1270nvpair_free(nvp);1271nvp_buf_free(nvl, nvp);1272return (err);1273}1274nvp_buf_link(nvl, nvp);12751276return (0);1277}12781279int1280nvlist_add_boolean(nvlist_t *nvl, const char *name)1281{1282return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL));1283}12841285int1286nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)1287{1288return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val));1289}12901291int1292nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)1293{1294return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val));1295}12961297int1298nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)1299{1300return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val));1301}13021303int1304nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)1305{1306return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val));1307}13081309int1310nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)1311{1312return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val));1313}13141315int1316nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)1317{1318return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val));1319}13201321int1322nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)1323{1324return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val));1325}13261327int1328nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)1329{1330return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val));1331}13321333int1334nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)1335{1336return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val));1337}13381339int1340nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)1341{1342return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val));1343}13441345#if !defined(_KERNEL)1346int1347nvlist_add_double(nvlist_t *nvl, const char *name, double val)1348{1349return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val));1350}1351#endif13521353int1354nvlist_add_string(nvlist_t *nvl, const char *name, const char *val)1355{1356return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val));1357}13581359int1360nvlist_add_boolean_array(nvlist_t *nvl, const char *name,1361const boolean_t *a, uint_t n)1362{1363return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));1364}13651366int1367nvlist_add_byte_array(nvlist_t *nvl, const char *name, const uchar_t *a,1368uint_t n)1369{1370return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));1371}13721373int1374nvlist_add_int8_array(nvlist_t *nvl, const char *name, const int8_t *a,1375uint_t n)1376{1377return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));1378}13791380int1381nvlist_add_uint8_array(nvlist_t *nvl, const char *name, const uint8_t *a,1382uint_t n)1383{1384return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));1385}13861387int1388nvlist_add_int16_array(nvlist_t *nvl, const char *name, const int16_t *a,1389uint_t n)1390{1391return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));1392}13931394int1395nvlist_add_uint16_array(nvlist_t *nvl, const char *name, const uint16_t *a,1396uint_t n)1397{1398return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));1399}14001401int1402nvlist_add_int32_array(nvlist_t *nvl, const char *name, const int32_t *a,1403uint_t n)1404{1405return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));1406}14071408int1409nvlist_add_uint32_array(nvlist_t *nvl, const char *name, const uint32_t *a,1410uint_t n)1411{1412return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));1413}14141415int1416nvlist_add_int64_array(nvlist_t *nvl, const char *name, const int64_t *a,1417uint_t n)1418{1419return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));1420}14211422int1423nvlist_add_uint64_array(nvlist_t *nvl, const char *name, const uint64_t *a,1424uint_t n)1425{1426return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));1427}14281429int1430nvlist_add_string_array(nvlist_t *nvl, const char *name,1431const char *const *a, uint_t n)1432{1433return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));1434}14351436int1437nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val)1438{1439return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val));1440}14411442int1443nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *val)1444{1445return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));1446}14471448int1449nvlist_add_nvlist_array(nvlist_t *nvl, const char *name,1450const nvlist_t * const *a, uint_t n)1451{1452return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));1453}14541455/* reading name-value pairs */1456nvpair_t *1457nvlist_next_nvpair(nvlist_t *nvl, const nvpair_t *nvp)1458{1459nvpriv_t *priv;1460i_nvp_t *curr;14611462if (nvl == NULL ||1463(priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)1464return (NULL);14651466curr = NVPAIR2I_NVP(nvp);14671468/*1469* Ensure that nvp is a valid nvpair on this nvlist.1470* NB: nvp_curr is used only as a hint so that we don't always1471* have to walk the list to determine if nvp is still on the list.1472*/1473if (nvp == NULL)1474curr = priv->nvp_list;1475else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))1476curr = curr->nvi_next;1477else1478curr = NULL;14791480priv->nvp_curr = curr;14811482return (curr != NULL ? &curr->nvi_nvp : NULL);1483}14841485nvpair_t *1486nvlist_prev_nvpair(nvlist_t *nvl, const nvpair_t *nvp)1487{1488nvpriv_t *priv;1489i_nvp_t *curr;14901491if (nvl == NULL ||1492(priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)1493return (NULL);14941495curr = NVPAIR2I_NVP(nvp);14961497if (nvp == NULL)1498curr = priv->nvp_last;1499else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))1500curr = curr->nvi_prev;1501else1502curr = NULL;15031504priv->nvp_curr = curr;15051506return (curr != NULL ? &curr->nvi_nvp : NULL);1507}15081509boolean_t1510nvlist_empty(const nvlist_t *nvl)1511{1512const nvpriv_t *priv;15131514if (nvl == NULL ||1515(priv = (const nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)1516return (B_TRUE);15171518return (priv->nvp_list == NULL);1519}15201521const char *1522nvpair_name(const nvpair_t *nvp)1523{1524return (NVP_NAME(nvp));1525}15261527data_type_t1528nvpair_type(const nvpair_t *nvp)1529{1530return (NVP_TYPE(nvp));1531}15321533int1534nvpair_type_is_array(const nvpair_t *nvp)1535{1536data_type_t type = NVP_TYPE(nvp);15371538if ((type == DATA_TYPE_BYTE_ARRAY) ||1539(type == DATA_TYPE_INT8_ARRAY) ||1540(type == DATA_TYPE_UINT8_ARRAY) ||1541(type == DATA_TYPE_INT16_ARRAY) ||1542(type == DATA_TYPE_UINT16_ARRAY) ||1543(type == DATA_TYPE_INT32_ARRAY) ||1544(type == DATA_TYPE_UINT32_ARRAY) ||1545(type == DATA_TYPE_INT64_ARRAY) ||1546(type == DATA_TYPE_UINT64_ARRAY) ||1547(type == DATA_TYPE_BOOLEAN_ARRAY) ||1548(type == DATA_TYPE_STRING_ARRAY) ||1549(type == DATA_TYPE_NVLIST_ARRAY))1550return (1);1551return (0);15521553}15541555static int1556nvpair_value_common(const nvpair_t *nvp, data_type_t type, uint_t *nelem,1557void *data)1558{1559int value_sz;15601561if (nvp == NULL || nvpair_type(nvp) != type)1562return (EINVAL);15631564/*1565* For non-array types, we copy the data.1566* For array types (including string), we set a pointer.1567*/1568switch (type) {1569case DATA_TYPE_BOOLEAN:1570if (nelem != NULL)1571*nelem = 0;1572break;15731574case DATA_TYPE_BOOLEAN_VALUE:1575case DATA_TYPE_BYTE:1576case DATA_TYPE_INT8:1577case DATA_TYPE_UINT8:1578case DATA_TYPE_INT16:1579case DATA_TYPE_UINT16:1580case DATA_TYPE_INT32:1581case DATA_TYPE_UINT32:1582case DATA_TYPE_INT64:1583case DATA_TYPE_UINT64:1584case DATA_TYPE_HRTIME:1585#if !defined(_KERNEL)1586case DATA_TYPE_DOUBLE:1587#endif1588if (data == NULL)1589return (EINVAL);1590if ((value_sz = i_get_value_size(type, NULL, 1)) < 0)1591return (EINVAL);1592memcpy(data, NVP_VALUE(nvp), (size_t)value_sz);1593if (nelem != NULL)1594*nelem = 1;1595break;15961597case DATA_TYPE_NVLIST:1598case DATA_TYPE_STRING:1599if (data == NULL)1600return (EINVAL);1601/*1602* This discards the const from nvp, so all callers for these1603* types must not accept const nvpairs.1604*/1605*(void **)data = (void *)NVP_VALUE(nvp);1606if (nelem != NULL)1607*nelem = 1;1608break;16091610case DATA_TYPE_BOOLEAN_ARRAY:1611case DATA_TYPE_BYTE_ARRAY:1612case DATA_TYPE_INT8_ARRAY:1613case DATA_TYPE_UINT8_ARRAY:1614case DATA_TYPE_INT16_ARRAY:1615case DATA_TYPE_UINT16_ARRAY:1616case DATA_TYPE_INT32_ARRAY:1617case DATA_TYPE_UINT32_ARRAY:1618case DATA_TYPE_INT64_ARRAY:1619case DATA_TYPE_UINT64_ARRAY:1620case DATA_TYPE_STRING_ARRAY:1621case DATA_TYPE_NVLIST_ARRAY:1622if (nelem == NULL || data == NULL)1623return (EINVAL);1624/*1625* This discards the const from nvp, so all callers for these1626* types must not accept const nvpairs.1627*/1628if ((*nelem = NVP_NELEM(nvp)) != 0)1629*(void **)data = (void *)NVP_VALUE(nvp);1630else1631*(void **)data = NULL;1632break;16331634default:1635return (ENOTSUP);1636}16371638return (0);1639}16401641static int1642nvlist_lookup_common(const nvlist_t *nvl, const char *name, data_type_t type,1643uint_t *nelem, void *data)1644{1645if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)1646return (EINVAL);16471648if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE)))1649return (ENOTSUP);16501651nvpair_t *nvp = nvt_lookup_name_type(nvl, name, type);1652if (nvp == NULL)1653return (ENOENT);16541655return (nvpair_value_common(nvp, type, nelem, data));1656}16571658int1659nvlist_lookup_boolean(const nvlist_t *nvl, const char *name)1660{1661return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL));1662}16631664int1665nvlist_lookup_boolean_value(const nvlist_t *nvl, const char *name,1666boolean_t *val)1667{1668return (nvlist_lookup_common(nvl, name,1669DATA_TYPE_BOOLEAN_VALUE, NULL, val));1670}16711672int1673nvlist_lookup_byte(const nvlist_t *nvl, const char *name, uchar_t *val)1674{1675return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val));1676}16771678int1679nvlist_lookup_int8(const nvlist_t *nvl, const char *name, int8_t *val)1680{1681return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val));1682}16831684int1685nvlist_lookup_uint8(const nvlist_t *nvl, const char *name, uint8_t *val)1686{1687return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val));1688}16891690int1691nvlist_lookup_int16(const nvlist_t *nvl, const char *name, int16_t *val)1692{1693return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val));1694}16951696int1697nvlist_lookup_uint16(const nvlist_t *nvl, const char *name, uint16_t *val)1698{1699return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val));1700}17011702int1703nvlist_lookup_int32(const nvlist_t *nvl, const char *name, int32_t *val)1704{1705return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val));1706}17071708int1709nvlist_lookup_uint32(const nvlist_t *nvl, const char *name, uint32_t *val)1710{1711return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val));1712}17131714int1715nvlist_lookup_int64(const nvlist_t *nvl, const char *name, int64_t *val)1716{1717return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val));1718}17191720int1721nvlist_lookup_uint64(const nvlist_t *nvl, const char *name, uint64_t *val)1722{1723return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val));1724}17251726#if !defined(_KERNEL)1727int1728nvlist_lookup_double(const nvlist_t *nvl, const char *name, double *val)1729{1730return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val));1731}1732#endif17331734int1735nvlist_lookup_string(const nvlist_t *nvl, const char *name, const char **val)1736{1737return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val));1738}17391740int1741nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val)1742{1743return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val));1744}17451746int1747nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name,1748boolean_t **a, uint_t *n)1749{1750return (nvlist_lookup_common(nvl, name,1751DATA_TYPE_BOOLEAN_ARRAY, n, a));1752}17531754int1755nvlist_lookup_byte_array(nvlist_t *nvl, const char *name,1756uchar_t **a, uint_t *n)1757{1758return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));1759}17601761int1762nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n)1763{1764return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));1765}17661767int1768nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name,1769uint8_t **a, uint_t *n)1770{1771return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));1772}17731774int1775nvlist_lookup_int16_array(nvlist_t *nvl, const char *name,1776int16_t **a, uint_t *n)1777{1778return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));1779}17801781int1782nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name,1783uint16_t **a, uint_t *n)1784{1785return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));1786}17871788int1789nvlist_lookup_int32_array(nvlist_t *nvl, const char *name,1790int32_t **a, uint_t *n)1791{1792return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));1793}17941795int1796nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name,1797uint32_t **a, uint_t *n)1798{1799return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));1800}18011802int1803nvlist_lookup_int64_array(nvlist_t *nvl, const char *name,1804int64_t **a, uint_t *n)1805{1806return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));1807}18081809int1810nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name,1811uint64_t **a, uint_t *n)1812{1813return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));1814}18151816int1817nvlist_lookup_string_array(nvlist_t *nvl, const char *name,1818char ***a, uint_t *n)1819{1820return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));1821}18221823int1824nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name,1825nvlist_t ***a, uint_t *n)1826{1827return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));1828}18291830int1831nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val)1832{1833return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val));1834}18351836int1837nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...)1838{1839va_list ap;1840char *name;1841int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0);1842int ret = 0;18431844va_start(ap, flag);1845while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {1846data_type_t type;1847void *val;1848uint_t *nelem;18491850switch (type = va_arg(ap, data_type_t)) {1851case DATA_TYPE_BOOLEAN:1852ret = nvlist_lookup_common(nvl, name, type, NULL, NULL);1853break;18541855case DATA_TYPE_BOOLEAN_VALUE:1856case DATA_TYPE_BYTE:1857case DATA_TYPE_INT8:1858case DATA_TYPE_UINT8:1859case DATA_TYPE_INT16:1860case DATA_TYPE_UINT16:1861case DATA_TYPE_INT32:1862case DATA_TYPE_UINT32:1863case DATA_TYPE_INT64:1864case DATA_TYPE_UINT64:1865case DATA_TYPE_HRTIME:1866case DATA_TYPE_STRING:1867case DATA_TYPE_NVLIST:1868#if !defined(_KERNEL)1869case DATA_TYPE_DOUBLE:1870#endif1871val = va_arg(ap, void *);1872ret = nvlist_lookup_common(nvl, name, type, NULL, val);1873break;18741875case DATA_TYPE_BYTE_ARRAY:1876case DATA_TYPE_BOOLEAN_ARRAY:1877case DATA_TYPE_INT8_ARRAY:1878case DATA_TYPE_UINT8_ARRAY:1879case DATA_TYPE_INT16_ARRAY:1880case DATA_TYPE_UINT16_ARRAY:1881case DATA_TYPE_INT32_ARRAY:1882case DATA_TYPE_UINT32_ARRAY:1883case DATA_TYPE_INT64_ARRAY:1884case DATA_TYPE_UINT64_ARRAY:1885case DATA_TYPE_STRING_ARRAY:1886case DATA_TYPE_NVLIST_ARRAY:1887val = va_arg(ap, void *);1888nelem = va_arg(ap, uint_t *);1889ret = nvlist_lookup_common(nvl, name, type, nelem, val);1890break;18911892default:1893ret = EINVAL;1894}18951896if (ret == ENOENT && noentok)1897ret = 0;1898}1899va_end(ap);19001901return (ret);1902}19031904/*1905* Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function1906* returns zero and a pointer to the matching nvpair is returned in '*ret'1907* (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate1908* multiple levels of embedded nvlists, with 'sep' as the separator. As an1909* example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or1910* "a.d[3].e[1]". This matches the C syntax for array embed (for convenience,1911* code also supports "a.d[3]e[1]" syntax).1912*1913* If 'ip' is non-NULL and the last name component is an array, return the1914* value of the "...[index]" array index in *ip. For an array reference that1915* is not indexed, *ip will be returned as -1. If there is a syntax error in1916* 'name', and 'ep' is non-NULL then *ep will be set to point to the location1917* inside the 'name' string where the syntax error was detected.1918*/1919static int1920nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep,1921nvpair_t **ret, int *ip, const char **ep)1922{1923nvpair_t *nvp;1924const char *np;1925char *sepp = NULL;1926char *idxp, *idxep;1927nvlist_t **nva;1928long idx = 0;1929int n;19301931if (ip)1932*ip = -1; /* not indexed */1933if (ep)1934*ep = NULL;19351936if ((nvl == NULL) || (name == NULL))1937return (EINVAL);19381939sepp = NULL;1940idx = 0;1941/* step through components of name */1942for (np = name; np && *np; np = sepp) {1943/* ensure unique names */1944if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))1945return (ENOTSUP);19461947/* skip white space */1948skip_whitespace(np);1949if (*np == 0)1950break;19511952/* set 'sepp' to end of current component 'np' */1953if (sep)1954sepp = strchr(np, sep);1955else1956sepp = NULL;19571958/* find start of next "[ index ]..." */1959idxp = strchr(np, '[');19601961/* if sepp comes first, set idxp to NULL */1962if (sepp && idxp && (sepp < idxp))1963idxp = NULL;19641965/*1966* At this point 'idxp' is set if there is an index1967* expected for the current component.1968*/1969if (idxp) {1970/* set 'n' to length of current 'np' name component */1971n = idxp++ - np;19721973/* keep sepp up to date for *ep use as we advance */1974skip_whitespace(idxp);1975sepp = idxp;19761977/* determine the index value */1978#if defined(_KERNEL)1979if (ddi_strtol(idxp, &idxep, 0, &idx))1980goto fail;1981#else1982idx = strtol(idxp, &idxep, 0);1983#endif1984if (idxep == idxp)1985goto fail;19861987/* keep sepp up to date for *ep use as we advance */1988sepp = idxep;19891990/* skip white space index value and check for ']' */1991skip_whitespace(sepp);1992if (*sepp++ != ']')1993goto fail;19941995/* for embedded arrays, support C syntax: "a[1].b" */1996skip_whitespace(sepp);1997if (sep && (*sepp == sep))1998sepp++;1999} else if (sepp) {2000n = sepp++ - np;2001} else {2002n = strlen(np);2003}20042005/* trim trailing whitespace by reducing length of 'np' */2006if (n == 0)2007goto fail;2008for (n--; (np[n] == ' ') || (np[n] == '\t'); n--)2009;2010n++;20112012/* skip whitespace, and set sepp to NULL if complete */2013if (sepp) {2014skip_whitespace(sepp);2015if (*sepp == 0)2016sepp = NULL;2017}20182019/*2020* At this point:2021* o 'n' is the length of current 'np' component.2022* o 'idxp' is set if there was an index, and value 'idx'.2023* o 'sepp' is set to the beginning of the next component,2024* and set to NULL if we have no more components.2025*2026* Search for nvpair with matching component name.2027*/2028for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;2029nvp = nvlist_next_nvpair(nvl, nvp)) {20302031/* continue if no match on name */2032if (strncmp(np, nvpair_name(nvp), n) ||2033(strlen(nvpair_name(nvp)) != n))2034continue;20352036/* if indexed, verify type is array oriented */2037if (idxp && !nvpair_type_is_array(nvp))2038goto fail;20392040/*2041* Full match found, return nvp and idx if this2042* was the last component.2043*/2044if (sepp == NULL) {2045if (ret)2046*ret = nvp;2047if (ip && idxp)2048*ip = (int)idx; /* return index */2049return (0); /* found */2050}20512052/*2053* More components: current match must be2054* of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY2055* to support going deeper.2056*/2057if (nvpair_type(nvp) == DATA_TYPE_NVLIST) {2058nvl = EMBEDDED_NVL(nvp);2059break;2060} else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {2061if (nvpair_value_nvlist_array(nvp,2062&nva, (uint_t *)&n) != 0)2063goto fail;2064if (nva == NULL)2065goto fail;2066if ((n < 0) || (idx >= n))2067goto fail;2068nvl = nva[idx];2069break;2070}20712072/* type does not support more levels */2073goto fail;2074}2075if (nvp == NULL)2076goto fail; /* 'name' not found */20772078/* search for match of next component in embedded 'nvl' list */2079}20802081fail: if (ep && sepp)2082*ep = sepp;2083return (EINVAL);2084}20852086/*2087* Return pointer to nvpair with specified 'name'.2088*/2089int2090nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)2091{2092return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL));2093}20942095/*2096* Determine if named nvpair exists in nvlist (use embedded separator of '.'2097* and return array index). See nvlist_lookup_nvpair_ei_sep for more detailed2098* description.2099*/2100int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl,2101const char *name, nvpair_t **ret, int *ip, const char **ep)2102{2103return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep));2104}21052106boolean_t2107nvlist_exists(const nvlist_t *nvl, const char *name)2108{2109nvpriv_t *priv;2110nvpair_t *nvp;2111i_nvp_t *curr;21122113if (name == NULL || nvl == NULL ||2114(priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)2115return (B_FALSE);21162117for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {2118nvp = &curr->nvi_nvp;21192120if (strcmp(name, NVP_NAME(nvp)) == 0)2121return (B_TRUE);2122}21232124return (B_FALSE);2125}21262127int2128nvpair_value_boolean_value(const nvpair_t *nvp, boolean_t *val)2129{2130return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));2131}21322133int2134nvpair_value_byte(const nvpair_t *nvp, uchar_t *val)2135{2136return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val));2137}21382139int2140nvpair_value_int8(const nvpair_t *nvp, int8_t *val)2141{2142return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val));2143}21442145int2146nvpair_value_uint8(const nvpair_t *nvp, uint8_t *val)2147{2148return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val));2149}21502151int2152nvpair_value_int16(const nvpair_t *nvp, int16_t *val)2153{2154return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val));2155}21562157int2158nvpair_value_uint16(const nvpair_t *nvp, uint16_t *val)2159{2160return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val));2161}21622163int2164nvpair_value_int32(const nvpair_t *nvp, int32_t *val)2165{2166return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val));2167}21682169int2170nvpair_value_uint32(const nvpair_t *nvp, uint32_t *val)2171{2172return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val));2173}21742175int2176nvpair_value_int64(const nvpair_t *nvp, int64_t *val)2177{2178return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val));2179}21802181int2182nvpair_value_uint64(const nvpair_t *nvp, uint64_t *val)2183{2184return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val));2185}21862187#if !defined(_KERNEL)2188int2189nvpair_value_double(const nvpair_t *nvp, double *val)2190{2191return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val));2192}2193#endif21942195int2196nvpair_value_string(const nvpair_t *nvp, const char **val)2197{2198return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val));2199}22002201int2202nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val)2203{2204return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val));2205}22062207int2208nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem)2209{2210return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val));2211}22122213int2214nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem)2215{2216return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val));2217}22182219int2220nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem)2221{2222return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val));2223}22242225int2226nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem)2227{2228return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val));2229}22302231int2232nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem)2233{2234return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val));2235}22362237int2238nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem)2239{2240return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val));2241}22422243int2244nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem)2245{2246return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val));2247}22482249int2250nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem)2251{2252return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val));2253}22542255int2256nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem)2257{2258return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val));2259}22602261int2262nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem)2263{2264return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val));2265}22662267int2268nvpair_value_string_array(nvpair_t *nvp, const char ***val, uint_t *nelem)2269{2270return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val));2271}22722273int2274nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem)2275{2276return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val));2277}22782279int2280nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val)2281{2282return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val));2283}22842285/*2286* Add specified pair to the list.2287*/2288int2289nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)2290{2291if (nvl == NULL || nvp == NULL)2292return (EINVAL);22932294return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp),2295NVP_NELEM(nvp), NVP_VALUE(nvp)));2296}22972298/*2299* Merge the supplied nvlists and put the result in dst.2300* The merged list will contain all names specified in both lists,2301* the values are taken from nvl in the case of duplicates.2302* Return 0 on success.2303*/2304int2305nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)2306{2307(void) flag;23082309if (nvl == NULL || dst == NULL)2310return (EINVAL);23112312if (dst != nvl)2313return (nvlist_copy_pairs(nvl, dst));23142315return (0);2316}23172318/*2319* Encoding related routines2320*/2321#define NVS_OP_ENCODE 02322#define NVS_OP_DECODE 12323#define NVS_OP_GETSIZE 223242325typedef struct nvs_ops nvs_ops_t;23262327typedef struct {2328int nvs_op;2329const nvs_ops_t *nvs_ops;2330void *nvs_private;2331nvpriv_t *nvs_priv;2332int nvs_recursion;2333} nvstream_t;23342335/*2336* nvs operations are:2337* - nvs_nvlist2338* encoding / decoding of an nvlist header (nvlist_t)2339* calculates the size used for header and end detection2340*2341* - nvs_nvpair2342* responsible for the first part of encoding / decoding of an nvpair2343* calculates the decoded size of an nvpair2344*2345* - nvs_nvp_op2346* second part of encoding / decoding of an nvpair2347*2348* - nvs_nvp_size2349* calculates the encoding size of an nvpair2350*2351* - nvs_nvl_fini2352* encodes the end detection mark (zeros).2353*/2354struct nvs_ops {2355int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *);2356int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *);2357int (*nvs_nvp_op)(nvstream_t *, nvpair_t *);2358int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *);2359int (*nvs_nvl_fini)(nvstream_t *);2360};23612362typedef struct {2363char nvh_encoding; /* nvs encoding method */2364char nvh_endian; /* nvs endian */2365char nvh_reserved1; /* reserved for future use */2366char nvh_reserved2; /* reserved for future use */2367} nvs_header_t;23682369static int2370nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl)2371{2372nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;2373i_nvp_t *curr;23742375/*2376* Walk nvpair in list and encode each nvpair2377*/2378for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)2379if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0)2380return (EFAULT);23812382return (nvs->nvs_ops->nvs_nvl_fini(nvs));2383}23842385static int2386nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl)2387{2388nvpair_t *nvp;2389size_t nvsize;2390int err;23912392/*2393* Get decoded size of next pair in stream, alloc2394* memory for nvpair_t, then decode the nvpair2395*/2396while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) {2397if (nvsize == 0) /* end of list */2398break;23992400/* make sure len makes sense */2401if (nvsize < NVP_SIZE_CALC(1, 0))2402return (EFAULT);24032404if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL)2405return (ENOMEM);24062407if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) {2408nvp_buf_free(nvl, nvp);2409return (err);2410}24112412if (i_validate_nvpair(nvp) != 0) {2413nvpair_free(nvp);2414nvp_buf_free(nvl, nvp);2415return (EFAULT);2416}24172418err = nvt_add_nvpair(nvl, nvp);2419if (err != 0) {2420nvpair_free(nvp);2421nvp_buf_free(nvl, nvp);2422return (err);2423}2424nvp_buf_link(nvl, nvp);2425}2426return (err);2427}24282429static int2430nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)2431{2432nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;2433i_nvp_t *curr;2434uint64_t nvsize = *buflen;2435size_t size;24362437/*2438* Get encoded size of nvpairs in nvlist2439*/2440for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {2441if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0)2442return (EINVAL);24432444if ((nvsize += size) > INT32_MAX)2445return (EINVAL);2446}24472448*buflen = nvsize;2449return (0);2450}24512452static int2453nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)2454{2455int err;24562457if (nvl->nvl_priv == 0)2458return (EFAULT);24592460/*2461* Perform the operation, starting with header, then each nvpair2462*/2463if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0)2464return (err);24652466switch (nvs->nvs_op) {2467case NVS_OP_ENCODE:2468err = nvs_encode_pairs(nvs, nvl);2469break;24702471case NVS_OP_DECODE:2472err = nvs_decode_pairs(nvs, nvl);2473break;24742475case NVS_OP_GETSIZE:2476err = nvs_getsize_pairs(nvs, nvl, buflen);2477break;24782479default:2480err = EINVAL;2481}24822483return (err);2484}24852486static int2487nvs_embedded(nvstream_t *nvs, nvlist_t *embedded)2488{2489switch (nvs->nvs_op) {2490case NVS_OP_ENCODE: {2491int err;24922493if (nvs->nvs_recursion >= nvpair_max_recursion)2494return (EINVAL);2495nvs->nvs_recursion++;2496err = nvs_operation(nvs, embedded, NULL);2497nvs->nvs_recursion--;2498return (err);2499}2500case NVS_OP_DECODE: {2501nvpriv_t *priv;2502int err;25032504if (embedded->nvl_version != NV_VERSION)2505return (ENOTSUP);25062507if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL)2508return (ENOMEM);25092510nvlist_init(embedded, embedded->nvl_nvflag, priv);25112512if (nvs->nvs_recursion >= nvpair_max_recursion) {2513nvlist_free(embedded);2514return (EINVAL);2515}2516nvs->nvs_recursion++;2517if ((err = nvs_operation(nvs, embedded, NULL)) != 0)2518nvlist_free(embedded);2519nvs->nvs_recursion--;2520return (err);2521}2522default:2523break;2524}25252526return (EINVAL);2527}25282529static int2530nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size)2531{2532size_t nelem = NVP_NELEM(nvp);2533nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);2534int i;25352536switch (nvs->nvs_op) {2537case NVS_OP_ENCODE:2538for (i = 0; i < nelem; i++)2539if (nvs_embedded(nvs, nvlp[i]) != 0)2540return (EFAULT);2541break;25422543case NVS_OP_DECODE: {2544size_t len = nelem * sizeof (uint64_t);2545nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len);25462547memset(nvlp, 0, len); /* don't trust packed data */2548for (i = 0; i < nelem; i++) {2549if (nvs_embedded(nvs, embedded) != 0) {2550nvpair_free(nvp);2551return (EFAULT);2552}25532554nvlp[i] = embedded++;2555}2556break;2557}2558case NVS_OP_GETSIZE: {2559uint64_t nvsize = 0;25602561for (i = 0; i < nelem; i++) {2562size_t nvp_sz = 0;25632564if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0)2565return (EINVAL);25662567if ((nvsize += nvp_sz) > INT32_MAX)2568return (EINVAL);2569}25702571*size = nvsize;2572break;2573}2574default:2575return (EINVAL);2576}25772578return (0);2579}25802581static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *);2582static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *);25832584/*2585* Common routine for nvlist operations:2586* encode, decode, getsize (encoded size).2587*/2588static int2589nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,2590int nvs_op)2591{2592int err = 0;2593nvstream_t nvs;2594int nvl_endian;2595#if defined(_ZFS_LITTLE_ENDIAN)2596int host_endian = 1;2597#elif defined(_ZFS_BIG_ENDIAN)2598int host_endian = 0;2599#else2600#error "No endian defined!"2601#endif /* _ZFS_LITTLE_ENDIAN */2602nvs_header_t *nvh;26032604if (buflen == NULL || nvl == NULL ||2605(nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)2606return (EINVAL);26072608nvs.nvs_op = nvs_op;2609nvs.nvs_recursion = 0;26102611/*2612* For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and2613* a buffer is allocated. The first 4 bytes in the buffer are2614* used for encoding method and host endian.2615*/2616switch (nvs_op) {2617case NVS_OP_ENCODE:2618if (buf == NULL || *buflen < sizeof (nvs_header_t))2619return (EINVAL);26202621nvh = (void *)buf;2622nvh->nvh_encoding = encoding;2623nvh->nvh_endian = nvl_endian = host_endian;2624nvh->nvh_reserved1 = 0;2625nvh->nvh_reserved2 = 0;2626break;26272628case NVS_OP_DECODE:2629if (buf == NULL || *buflen < sizeof (nvs_header_t))2630return (EINVAL);26312632/* get method of encoding from first byte */2633nvh = (void *)buf;2634encoding = nvh->nvh_encoding;2635nvl_endian = nvh->nvh_endian;2636break;26372638case NVS_OP_GETSIZE:2639nvl_endian = host_endian;26402641/*2642* add the size for encoding2643*/2644*buflen = sizeof (nvs_header_t);2645break;26462647default:2648return (ENOTSUP);2649}26502651/*2652* Create an nvstream with proper encoding method2653*/2654switch (encoding) {2655case NV_ENCODE_NATIVE:2656/*2657* check endianness, in case we are unpacking2658* from a file2659*/2660if (nvl_endian != host_endian)2661return (ENOTSUP);2662err = nvs_native(&nvs, nvl, buf, buflen);2663break;2664case NV_ENCODE_XDR:2665err = nvs_xdr(&nvs, nvl, buf, buflen);2666break;2667default:2668err = ENOTSUP;2669break;2670}26712672return (err);2673}26742675int2676nvlist_size(nvlist_t *nvl, size_t *size, int encoding)2677{2678return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));2679}26802681/*2682* Pack nvlist into contiguous memory2683*/2684int2685nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,2686int kmflag)2687{2688return (nvlist_xpack(nvl, bufp, buflen, encoding,2689nvlist_nv_alloc(kmflag)));2690}26912692int2693nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,2694nv_alloc_t *nva)2695{2696nvpriv_t nvpriv;2697size_t alloc_size;2698char *buf;2699int err;27002701if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL)2702return (EINVAL);27032704if (*bufp != NULL)2705return (nvlist_common(nvl, *bufp, buflen, encoding,2706NVS_OP_ENCODE));27072708/*2709* Here is a difficult situation:2710* 1. The nvlist has fixed allocator properties.2711* All other nvlist routines (like nvlist_add_*, ...) use2712* these properties.2713* 2. When using nvlist_pack() the user can specify their own2714* allocator properties (e.g. by using KM_NOSLEEP).2715*2716* We use the user specified properties (2). A clearer solution2717* will be to remove the kmflag from nvlist_pack(), but we will2718* not change the interface.2719*/2720nv_priv_init(&nvpriv, nva, 0);27212722if ((err = nvlist_size(nvl, &alloc_size, encoding)))2723return (err);27242725if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL)2726return (ENOMEM);27272728if ((err = nvlist_common(nvl, buf, &alloc_size, encoding,2729NVS_OP_ENCODE)) != 0) {2730nv_mem_free(&nvpriv, buf, alloc_size);2731} else {2732*buflen = alloc_size;2733*bufp = buf;2734}27352736return (err);2737}27382739/*2740* Unpack buf into an nvlist_t2741*/2742int2743nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag)2744{2745return (nvlist_xunpack(buf, buflen, nvlp, nvlist_nv_alloc(kmflag)));2746}27472748int2749nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva)2750{2751nvlist_t *nvl;2752int err;27532754if (nvlp == NULL)2755return (EINVAL);27562757if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0)2758return (err);27592760if ((err = nvlist_common(nvl, buf, &buflen, NV_ENCODE_NATIVE,2761NVS_OP_DECODE)) != 0)2762nvlist_free(nvl);2763else2764*nvlp = nvl;27652766return (err);2767}27682769/*2770* Native encoding functions2771*/2772typedef struct {2773/*2774* This structure is used when decoding a packed nvpair in2775* the native format. n_base points to a buffer containing the2776* packed nvpair. n_end is a pointer to the end of the buffer.2777* (n_end actually points to the first byte past the end of the2778* buffer.) n_curr is a pointer that lies between n_base and n_end.2779* It points to the current data that we are decoding.2780* The amount of data left in the buffer is equal to n_end - n_curr.2781* n_flag is used to recognize a packed embedded list.2782*/2783caddr_t n_base;2784caddr_t n_end;2785caddr_t n_curr;2786uint_t n_flag;2787} nvs_native_t;27882789static int2790nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf,2791size_t buflen)2792{2793switch (nvs->nvs_op) {2794case NVS_OP_ENCODE:2795case NVS_OP_DECODE:2796nvs->nvs_private = native;2797native->n_curr = native->n_base = buf;2798native->n_end = buf + buflen;2799native->n_flag = 0;2800return (0);28012802case NVS_OP_GETSIZE:2803nvs->nvs_private = native;2804native->n_curr = native->n_base = native->n_end = NULL;2805native->n_flag = 0;2806return (0);2807default:2808return (EINVAL);2809}2810}28112812static void2813nvs_native_destroy(nvstream_t *nvs)2814{2815nvs->nvs_private = NULL;2816}28172818static int2819native_cp(nvstream_t *nvs, void *buf, size_t size)2820{2821nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;28222823if (native->n_curr + size > native->n_end)2824return (EFAULT);28252826/*2827* The memcpy() below eliminates alignment requirement2828* on the buffer (stream) and is preferred over direct access.2829*/2830switch (nvs->nvs_op) {2831case NVS_OP_ENCODE:2832memcpy(native->n_curr, buf, size);2833break;2834case NVS_OP_DECODE:2835memcpy(buf, native->n_curr, size);2836break;2837default:2838return (EINVAL);2839}28402841native->n_curr += size;2842return (0);2843}28442845/*2846* operate on nvlist_t header2847*/2848static int2849nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)2850{2851nvs_native_t *native = nvs->nvs_private;28522853switch (nvs->nvs_op) {2854case NVS_OP_ENCODE:2855case NVS_OP_DECODE:2856if (native->n_flag)2857return (0); /* packed embedded list */28582859native->n_flag = 1;28602861/* copy version and nvflag of the nvlist_t */2862if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 ||2863native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0)2864return (EFAULT);28652866return (0);28672868case NVS_OP_GETSIZE:2869/*2870* if calculate for packed embedded list2871* 4 for end of the embedded list2872* else2873* 2 * sizeof (int32_t) for nvl_version and nvl_nvflag2874* and 4 for end of the entire list2875*/2876if (native->n_flag) {2877*size += 4;2878} else {2879native->n_flag = 1;2880*size += 2 * sizeof (int32_t) + 4;2881}28822883return (0);28842885default:2886return (EINVAL);2887}2888}28892890static int2891nvs_native_nvl_fini(nvstream_t *nvs)2892{2893if (nvs->nvs_op == NVS_OP_ENCODE) {2894nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;2895/*2896* Add 4 zero bytes at end of nvlist. They are used2897* for end detection by the decode routine.2898*/2899if (native->n_curr + sizeof (int) > native->n_end)2900return (EFAULT);29012902memset(native->n_curr, 0, sizeof (int));2903native->n_curr += sizeof (int);2904}29052906return (0);2907}29082909static int2910nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp)2911{2912if (nvs->nvs_op == NVS_OP_ENCODE) {2913nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;2914nvlist_t *packed = (void *)2915(native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));2916/*2917* Null out the pointer that is meaningless in the packed2918* structure. The address may not be aligned, so we have2919* to use memset.2920*/2921memset((char *)packed + offsetof(nvlist_t, nvl_priv),29220, sizeof (uint64_t));2923}29242925return (nvs_embedded(nvs, EMBEDDED_NVL(nvp)));2926}29272928static int2929nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp)2930{2931if (nvs->nvs_op == NVS_OP_ENCODE) {2932nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;2933char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp);2934size_t len = NVP_NELEM(nvp) * sizeof (uint64_t);2935nvlist_t *packed = (nvlist_t *)((uintptr_t)value + len);2936int i;2937/*2938* Null out pointers that are meaningless in the packed2939* structure. The addresses may not be aligned, so we have2940* to use memset.2941*/2942memset(value, 0, len);29432944for (i = 0; i < NVP_NELEM(nvp); i++, packed++)2945/*2946* Null out the pointer that is meaningless in the2947* packed structure. The address may not be aligned,2948* so we have to use memset.2949*/2950memset((char *)packed + offsetof(nvlist_t, nvl_priv),29510, sizeof (uint64_t));2952}29532954return (nvs_embedded_nvl_array(nvs, nvp, NULL));2955}29562957static void2958nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp)2959{2960switch (nvs->nvs_op) {2961case NVS_OP_ENCODE: {2962nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;2963uint64_t *strp = (void *)2964(native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));2965/*2966* Null out pointers that are meaningless in the packed2967* structure. The addresses may not be aligned, so we have2968* to use memset.2969*/2970memset(strp, 0, NVP_NELEM(nvp) * sizeof (uint64_t));2971break;2972}2973case NVS_OP_DECODE: {2974char **strp = (void *)NVP_VALUE(nvp);2975char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t));2976int i;29772978for (i = 0; i < NVP_NELEM(nvp); i++) {2979strp[i] = buf;2980buf += strlen(buf) + 1;2981}2982break;2983}2984}2985}29862987static int2988nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp)2989{2990data_type_t type;2991int value_sz;2992int ret = 0;29932994/*2995* We do the initial memcpy of the data before we look at2996* the nvpair type, because when we're decoding, we won't2997* have the correct values for the pair until we do the memcpy.2998*/2999switch (nvs->nvs_op) {3000case NVS_OP_ENCODE:3001case NVS_OP_DECODE:3002if (native_cp(nvs, nvp, nvp->nvp_size) != 0)3003return (EFAULT);3004break;3005default:3006return (EINVAL);3007}30083009/* verify nvp_name_sz, check the name string length */3010if (i_validate_nvpair_name(nvp) != 0)3011return (EFAULT);30123013type = NVP_TYPE(nvp);30143015/*3016* Verify type and nelem and get the value size.3017* In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY3018* is the size of the string(s) excluded.3019*/3020if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0)3021return (EFAULT);30223023if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size)3024return (EFAULT);30253026switch (type) {3027case DATA_TYPE_NVLIST:3028ret = nvpair_native_embedded(nvs, nvp);3029break;3030case DATA_TYPE_NVLIST_ARRAY:3031ret = nvpair_native_embedded_array(nvs, nvp);3032break;3033case DATA_TYPE_STRING_ARRAY:3034nvpair_native_string_array(nvs, nvp);3035break;3036default:3037break;3038}30393040return (ret);3041}30423043static int3044nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)3045{3046uint64_t nvp_sz = nvp->nvp_size;30473048switch (NVP_TYPE(nvp)) {3049case DATA_TYPE_NVLIST: {3050size_t nvsize = 0;30513052if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0)3053return (EINVAL);30543055nvp_sz += nvsize;3056break;3057}3058case DATA_TYPE_NVLIST_ARRAY: {3059size_t nvsize;30603061if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0)3062return (EINVAL);30633064nvp_sz += nvsize;3065break;3066}3067default:3068break;3069}30703071if (nvp_sz > INT32_MAX)3072return (EINVAL);30733074*size = nvp_sz;30753076return (0);3077}30783079static int3080nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)3081{3082switch (nvs->nvs_op) {3083case NVS_OP_ENCODE:3084return (nvs_native_nvp_op(nvs, nvp));30853086case NVS_OP_DECODE: {3087nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;3088int32_t decode_len;30893090/* try to read the size value from the stream */3091if (native->n_curr + sizeof (int32_t) > native->n_end)3092return (EFAULT);3093memcpy(&decode_len, native->n_curr, sizeof (int32_t));30943095/* sanity check the size value */3096if (decode_len < 0 ||3097decode_len > native->n_end - native->n_curr)3098return (EFAULT);30993100*size = decode_len;31013102/*3103* If at the end of the stream then move the cursor3104* forward, otherwise nvpair_native_op() will read3105* the entire nvpair at the same cursor position.3106*/3107if (*size == 0)3108native->n_curr += sizeof (int32_t);3109break;3110}31113112default:3113return (EINVAL);3114}31153116return (0);3117}31183119static const nvs_ops_t nvs_native_ops = {3120.nvs_nvlist = nvs_native_nvlist,3121.nvs_nvpair = nvs_native_nvpair,3122.nvs_nvp_op = nvs_native_nvp_op,3123.nvs_nvp_size = nvs_native_nvp_size,3124.nvs_nvl_fini = nvs_native_nvl_fini3125};31263127static int3128nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)3129{3130nvs_native_t native;3131int err;31323133nvs->nvs_ops = &nvs_native_ops;31343135if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t),3136*buflen - sizeof (nvs_header_t))) != 0)3137return (err);31383139err = nvs_operation(nvs, nvl, buflen);31403141nvs_native_destroy(nvs);31423143return (err);3144}31453146/*3147* XDR encoding functions3148*3149* An xdr packed nvlist is encoded as:3150*3151* - encoding method and host endian (4 bytes)3152* - nvl_version (4 bytes)3153* - nvl_nvflag (4 bytes)3154*3155* - encoded nvpairs, the format of one xdr encoded nvpair is:3156* - encoded size of the nvpair (4 bytes)3157* - decoded size of the nvpair (4 bytes)3158* - name string, (4 + sizeof(NV_ALIGN4(string))3159* a string is coded as size (4 bytes) and data3160* - data type (4 bytes)3161* - number of elements in the nvpair (4 bytes)3162* - data3163*3164* - 2 zero's for end of the entire list (8 bytes)3165*/3166static int3167nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen)3168{3169/* xdr data must be 4 byte aligned */3170if ((ulong_t)buf % 4 != 0)3171return (EFAULT);31723173switch (nvs->nvs_op) {3174case NVS_OP_ENCODE:3175xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE);3176nvs->nvs_private = xdr;3177return (0);3178case NVS_OP_DECODE:3179xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE);3180nvs->nvs_private = xdr;3181return (0);3182case NVS_OP_GETSIZE:3183nvs->nvs_private = NULL;3184return (0);3185default:3186return (EINVAL);3187}3188}31893190static void3191nvs_xdr_destroy(nvstream_t *nvs)3192{3193switch (nvs->nvs_op) {3194case NVS_OP_ENCODE:3195case NVS_OP_DECODE:3196nvs->nvs_private = NULL;3197break;3198default:3199break;3200}3201}32023203static int3204nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)3205{3206switch (nvs->nvs_op) {3207case NVS_OP_ENCODE:3208case NVS_OP_DECODE: {3209XDR *xdr = nvs->nvs_private;32103211if (!xdr_int(xdr, &nvl->nvl_version) ||3212!xdr_u_int(xdr, &nvl->nvl_nvflag))3213return (EFAULT);3214break;3215}3216case NVS_OP_GETSIZE: {3217/*3218* 2 * 4 for nvl_version + nvl_nvflag3219* and 8 for end of the entire list3220*/3221*size += 2 * 4 + 8;3222break;3223}3224default:3225return (EINVAL);3226}3227return (0);3228}32293230static int3231nvs_xdr_nvl_fini(nvstream_t *nvs)3232{3233if (nvs->nvs_op == NVS_OP_ENCODE) {3234XDR *xdr = nvs->nvs_private;3235int zero = 0;32363237if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero))3238return (EFAULT);3239}32403241return (0);3242}32433244/*3245* xdrproc_t-compatible callbacks for xdr_array()3246*/32473248#if defined(_KERNEL) && defined(__linux__) /* Linux kernel */32493250#define NVS_BUILD_XDRPROC_T(type) \3251static bool_t \3252nvs_xdr_nvp_##type(XDR *xdrs, void *ptr) \3253{ \3254return (xdr_##type(xdrs, ptr)); \3255}32563257#elif !defined(_KERNEL) && defined(XDR_CONTROL) /* tirpc */32583259#define NVS_BUILD_XDRPROC_T(type) \3260static bool_t \3261nvs_xdr_nvp_##type(XDR *xdrs, ...) \3262{ \3263va_list args; \3264void *ptr; \3265\3266va_start(args, xdrs); \3267ptr = va_arg(args, void *); \3268va_end(args); \3269\3270return (xdr_##type(xdrs, ptr)); \3271}32723273#else /* FreeBSD, sunrpc */32743275#define NVS_BUILD_XDRPROC_T(type) \3276static bool_t \3277nvs_xdr_nvp_##type(XDR *xdrs, void *ptr, ...) \3278{ \3279return (xdr_##type(xdrs, ptr)); \3280}32813282#endif32833284NVS_BUILD_XDRPROC_T(char);3285NVS_BUILD_XDRPROC_T(short);3286NVS_BUILD_XDRPROC_T(u_short);3287NVS_BUILD_XDRPROC_T(int);3288NVS_BUILD_XDRPROC_T(u_int);3289NVS_BUILD_XDRPROC_T(longlong_t);3290NVS_BUILD_XDRPROC_T(u_longlong_t);32913292/*3293* The format of xdr encoded nvpair is:3294* encode_size, decode_size, name string, data type, nelem, data3295*/3296static int3297nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp)3298{3299ASSERT(nvs != NULL && nvp != NULL);33003301data_type_t type;3302char *buf;3303char *buf_end = (char *)nvp + nvp->nvp_size;3304int value_sz;3305uint_t nelem, buflen;3306bool_t ret = FALSE;3307XDR *xdr = nvs->nvs_private;33083309ASSERT(xdr != NULL);33103311/* name string */3312if ((buf = NVP_NAME(nvp)) >= buf_end)3313return (EFAULT);3314buflen = buf_end - buf;33153316if (!xdr_string(xdr, &buf, buflen - 1))3317return (EFAULT);3318nvp->nvp_name_sz = strlen(buf) + 1;33193320/* type and nelem */3321if (!xdr_int(xdr, (int *)&nvp->nvp_type) ||3322!xdr_int(xdr, &nvp->nvp_value_elem))3323return (EFAULT);33243325type = NVP_TYPE(nvp);3326nelem = nvp->nvp_value_elem;33273328/*3329* Verify type and nelem and get the value size.3330* In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY3331* is the size of the string(s) excluded.3332*/3333if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0)3334return (EFAULT);33353336/* if there is no data to extract then return */3337if (nelem == 0)3338return (0);33393340/* value */3341if ((buf = NVP_VALUE(nvp)) >= buf_end)3342return (EFAULT);3343buflen = buf_end - buf;33443345if (buflen < value_sz)3346return (EFAULT);33473348switch (type) {3349case DATA_TYPE_NVLIST:3350if (nvs_embedded(nvs, (void *)buf) == 0)3351return (0);3352break;33533354case DATA_TYPE_NVLIST_ARRAY:3355if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0)3356return (0);3357break;33583359case DATA_TYPE_BOOLEAN:3360ret = TRUE;3361break;33623363case DATA_TYPE_BYTE:3364case DATA_TYPE_INT8:3365case DATA_TYPE_UINT8:3366ret = xdr_char(xdr, buf);3367break;33683369case DATA_TYPE_INT16:3370ret = xdr_short(xdr, (void *)buf);3371break;33723373case DATA_TYPE_UINT16:3374ret = xdr_u_short(xdr, (void *)buf);3375break;33763377case DATA_TYPE_BOOLEAN_VALUE:3378case DATA_TYPE_INT32:3379ret = xdr_int(xdr, (void *)buf);3380break;33813382case DATA_TYPE_UINT32:3383ret = xdr_u_int(xdr, (void *)buf);3384break;33853386case DATA_TYPE_INT64:3387ret = xdr_longlong_t(xdr, (void *)buf);3388break;33893390case DATA_TYPE_UINT64:3391ret = xdr_u_longlong_t(xdr, (void *)buf);3392break;33933394case DATA_TYPE_HRTIME:3395/*3396* NOTE: must expose the definition of hrtime_t here3397*/3398ret = xdr_longlong_t(xdr, (void *)buf);3399break;3400#if !defined(_KERNEL)3401case DATA_TYPE_DOUBLE:3402ret = xdr_double(xdr, (void *)buf);3403break;3404#endif3405case DATA_TYPE_STRING:3406ret = xdr_string(xdr, &buf, buflen - 1);3407break;34083409case DATA_TYPE_BYTE_ARRAY:3410ret = xdr_opaque(xdr, buf, nelem);3411break;34123413case DATA_TYPE_INT8_ARRAY:3414case DATA_TYPE_UINT8_ARRAY:3415ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t),3416nvs_xdr_nvp_char);3417break;34183419case DATA_TYPE_INT16_ARRAY:3420ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t),3421sizeof (int16_t), nvs_xdr_nvp_short);3422break;34233424case DATA_TYPE_UINT16_ARRAY:3425ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t),3426sizeof (uint16_t), nvs_xdr_nvp_u_short);3427break;34283429case DATA_TYPE_BOOLEAN_ARRAY:3430case DATA_TYPE_INT32_ARRAY:3431ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t),3432sizeof (int32_t), nvs_xdr_nvp_int);3433break;34343435case DATA_TYPE_UINT32_ARRAY:3436ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t),3437sizeof (uint32_t), nvs_xdr_nvp_u_int);3438break;34393440case DATA_TYPE_INT64_ARRAY:3441ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t),3442sizeof (int64_t), nvs_xdr_nvp_longlong_t);3443break;34443445case DATA_TYPE_UINT64_ARRAY:3446ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t),3447sizeof (uint64_t), nvs_xdr_nvp_u_longlong_t);3448break;34493450case DATA_TYPE_STRING_ARRAY: {3451size_t len = nelem * sizeof (uint64_t);3452char **strp = (void *)buf;3453int i;34543455if (nvs->nvs_op == NVS_OP_DECODE)3456memset(buf, 0, len); /* don't trust packed data */34573458for (i = 0; i < nelem; i++) {3459if (buflen <= len)3460return (EFAULT);34613462buf += len;3463buflen -= len;34643465if (xdr_string(xdr, &buf, buflen - 1) != TRUE)3466return (EFAULT);34673468if (nvs->nvs_op == NVS_OP_DECODE)3469strp[i] = buf;3470len = strlen(buf) + 1;3471}3472ret = TRUE;3473break;3474}3475default:3476break;3477}34783479return (ret == TRUE ? 0 : EFAULT);3480}34813482static int3483nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)3484{3485data_type_t type = NVP_TYPE(nvp);3486/*3487* encode_size + decode_size + name string size + data type + nelem3488* where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))3489*/3490uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4;34913492switch (type) {3493case DATA_TYPE_BOOLEAN:3494break;34953496case DATA_TYPE_BOOLEAN_VALUE:3497case DATA_TYPE_BYTE:3498case DATA_TYPE_INT8:3499case DATA_TYPE_UINT8:3500case DATA_TYPE_INT16:3501case DATA_TYPE_UINT16:3502case DATA_TYPE_INT32:3503case DATA_TYPE_UINT32:3504nvp_sz += 4; /* 4 is the minimum xdr unit */3505break;35063507case DATA_TYPE_INT64:3508case DATA_TYPE_UINT64:3509case DATA_TYPE_HRTIME:3510#if !defined(_KERNEL)3511case DATA_TYPE_DOUBLE:3512#endif3513nvp_sz += 8;3514break;35153516case DATA_TYPE_STRING:3517nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp)));3518break;35193520case DATA_TYPE_BYTE_ARRAY:3521nvp_sz += NV_ALIGN4(NVP_NELEM(nvp));3522break;35233524case DATA_TYPE_BOOLEAN_ARRAY:3525case DATA_TYPE_INT8_ARRAY:3526case DATA_TYPE_UINT8_ARRAY:3527case DATA_TYPE_INT16_ARRAY:3528case DATA_TYPE_UINT16_ARRAY:3529case DATA_TYPE_INT32_ARRAY:3530case DATA_TYPE_UINT32_ARRAY:3531nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp);3532break;35333534case DATA_TYPE_INT64_ARRAY:3535case DATA_TYPE_UINT64_ARRAY:3536nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp);3537break;35383539case DATA_TYPE_STRING_ARRAY: {3540int i;3541char **strs = (void *)NVP_VALUE(nvp);35423543for (i = 0; i < NVP_NELEM(nvp); i++)3544nvp_sz += 4 + NV_ALIGN4(strlen(strs[i]));35453546break;3547}35483549case DATA_TYPE_NVLIST:3550case DATA_TYPE_NVLIST_ARRAY: {3551size_t nvsize = 0;3552int old_nvs_op = nvs->nvs_op;3553int err;35543555nvs->nvs_op = NVS_OP_GETSIZE;3556if (type == DATA_TYPE_NVLIST)3557err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize);3558else3559err = nvs_embedded_nvl_array(nvs, nvp, &nvsize);3560nvs->nvs_op = old_nvs_op;35613562if (err != 0)3563return (EINVAL);35643565nvp_sz += nvsize;3566break;3567}35683569default:3570return (EINVAL);3571}35723573if (nvp_sz > INT32_MAX)3574return (EINVAL);35753576*size = nvp_sz;35773578return (0);3579}358035813582/*3583* The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates3584* the largest nvpair that could be encoded in the buffer.3585*3586* See comments above nvpair_xdr_op() for the format of xdr encoding.3587* The size of a xdr packed nvpair without any data is 5 words.3588*3589* Using the size of the data directly as an estimate would be ok3590* in all cases except one. If the data type is of DATA_TYPE_STRING_ARRAY3591* then the actual nvpair has space for an array of pointers to index3592* the strings. These pointers are not encoded into the packed xdr buffer.3593*3594* If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are3595* of length 0, then each string is encoded in xdr format as a single word.3596* Therefore when expanded to an nvpair there will be 2.25 word used for3597* each string. (a int64_t allocated for pointer usage, and a single char3598* for the null termination.)3599*3600* This is the calculation performed by the NVS_XDR_MAX_LEN macro.3601*/3602#define NVS_XDR_HDR_LEN ((size_t)(5 * 4))3603#define NVS_XDR_DATA_LEN(y) (((size_t)(y) <= NVS_XDR_HDR_LEN) ? \36040 : ((size_t)(y) - NVS_XDR_HDR_LEN))3605#define NVS_XDR_MAX_LEN(x) (NVP_SIZE_CALC(1, 0) + \3606(NVS_XDR_DATA_LEN(x) * 2) + \3607NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4)))36083609static int3610nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)3611{3612XDR *xdr = nvs->nvs_private;3613int32_t encode_len, decode_len;36143615switch (nvs->nvs_op) {3616case NVS_OP_ENCODE: {3617size_t nvsize;36183619if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0)3620return (EFAULT);36213622decode_len = nvp->nvp_size;3623encode_len = nvsize;3624if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))3625return (EFAULT);36263627return (nvs_xdr_nvp_op(nvs, nvp));3628}3629case NVS_OP_DECODE: {3630struct xdr_bytesrec bytesrec;36313632/* get the encode and decode size */3633if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))3634return (EFAULT);3635*size = decode_len;36363637/* are we at the end of the stream? */3638if (*size == 0)3639return (0);36403641/* sanity check the size parameter */3642if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec))3643return (EFAULT);36443645if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail))3646return (EFAULT);3647break;3648}36493650default:3651return (EINVAL);3652}3653return (0);3654}36553656static const struct nvs_ops nvs_xdr_ops = {3657.nvs_nvlist = nvs_xdr_nvlist,3658.nvs_nvpair = nvs_xdr_nvpair,3659.nvs_nvp_op = nvs_xdr_nvp_op,3660.nvs_nvp_size = nvs_xdr_nvp_size,3661.nvs_nvl_fini = nvs_xdr_nvl_fini3662};36633664static int3665nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)3666{3667XDR xdr;3668int err;36693670nvs->nvs_ops = &nvs_xdr_ops;36713672if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t),3673*buflen - sizeof (nvs_header_t))) != 0)3674return (err);36753676err = nvs_operation(nvs, nvl, buflen);36773678nvs_xdr_destroy(nvs);36793680return (err);3681}36823683#define NVP(buf, size, len, buf_end, elem, type, vtype, ptype, format) { \3684vtype value; \3685int rc; \3686\3687(void) nvpair_value_##type(elem, &value); \3688rc = snprintf(buf, size, "%*s%s: " format "\n", indent, "", \3689nvpair_name(elem), (ptype)value); \3690if (rc < 0) \3691return (rc); \3692size = MAX((int)size - rc, 0); \3693buf = size == 0 ? NULL : buf_end - size; \3694len += rc; \3695}36963697#define NVPA(buf, size, len, buf_end, elem, type, vtype, ptype, format) \3698{ \3699uint_t i, count; \3700vtype *value; \3701int rc; \3702\3703(void) nvpair_value_##type(elem, &value, &count); \3704for (i = 0; i < count; i++) { \3705rc = snprintf(buf, size, "%*s%s[%d]: " format "\n", indent, \3706"", nvpair_name(elem), i, (ptype)value[i]); \3707if (rc < 0) \3708return (rc); \3709size = MAX((int)size - rc, 0); \3710buf = size == 0 ? NULL : buf_end - size; \3711len += rc; \3712} \3713}37143715/*3716* snprintf() version of dump_nvlist()3717*3718* Works just like snprintf(), but with an nvlist and indent count as args.3719*3720* Output is similar to nvlist_print() but handles arrays slightly differently.3721*3722* Return value matches C99 snprintf() return value conventions.3723*/3724int3725nvlist_snprintf(char *buf, size_t size, nvlist_t *list, int indent)3726{3727nvpair_t *elem = NULL;3728boolean_t bool_value;3729nvlist_t *nvlist_value;3730nvlist_t **nvlist_array_value;3731uint_t i, count;3732int len = 0;3733int rc;3734char *buf_end = &buf[size];37353736if (list == NULL)3737return (0);37383739while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {3740switch (nvpair_type(elem)) {3741case DATA_TYPE_BOOLEAN:3742rc = snprintf(buf, size, "%*s%s\n", indent, "",3743nvpair_name(elem));3744if (rc < 0)3745return (rc);3746size = MAX((int)size - rc, 0);3747buf = size == 0 ? NULL : buf_end - size;3748len += rc;3749break;37503751case DATA_TYPE_BOOLEAN_VALUE:3752(void) nvpair_value_boolean_value(elem, &bool_value);3753rc = snprintf(buf, size, "%*s%s: %s\n", indent, "",3754nvpair_name(elem), bool_value ? "true" : "false");3755if (rc < 0)3756return (rc);3757size = MAX((int)size - rc, 0);3758buf = size == 0 ? NULL : buf_end - size;3759len += rc;3760break;37613762case DATA_TYPE_BYTE:3763NVP(buf, size, len, buf_end, elem, byte, uchar_t, int,3764"%u");3765break;37663767case DATA_TYPE_INT8:3768NVP(buf, size, len, buf_end, elem, int8, int8_t, int,3769"%d");3770break;37713772case DATA_TYPE_UINT8:3773NVP(buf, size, len, buf_end, elem, uint8, uint8_t, int,3774"%u");3775break;37763777case DATA_TYPE_INT16:3778NVP(buf, size, len, buf_end, elem, int16, int16_t, int,3779"%d");3780break;37813782case DATA_TYPE_UINT16:3783NVP(buf, size, len, buf_end, elem, uint16, uint16_t,3784int, "%u");3785break;37863787case DATA_TYPE_INT32:3788NVP(buf, size, len, buf_end, elem, int32, int32_t,3789long, "%ld");3790break;37913792case DATA_TYPE_UINT32:3793NVP(buf, size, len, buf_end, elem, uint32, uint32_t,3794ulong_t, "%lu");3795break;37963797case DATA_TYPE_INT64:3798NVP(buf, size, len, buf_end, elem, int64, int64_t,3799longlong_t, "%lld");3800break;38013802case DATA_TYPE_UINT64:3803NVP(buf, size, len, buf_end, elem, uint64, uint64_t,3804u_longlong_t, "%llu");3805break;38063807case DATA_TYPE_STRING:3808NVP(buf, size, len, buf_end, elem, string, const char *,3809const char *, "'%s'");3810break;38113812case DATA_TYPE_BYTE_ARRAY:3813NVPA(buf, size, len, buf_end, elem, byte_array, uchar_t,3814int, "%u");3815break;38163817case DATA_TYPE_INT8_ARRAY:3818NVPA(buf, size, len, buf_end, elem, int8_array, int8_t,3819int, "%d");3820break;38213822case DATA_TYPE_UINT8_ARRAY:3823NVPA(buf, size, len, buf_end, elem, uint8_array,3824uint8_t, int, "%u");3825break;38263827case DATA_TYPE_INT16_ARRAY:3828NVPA(buf, size, len, buf_end, elem, int16_array,3829int16_t, int, "%d");3830break;38313832case DATA_TYPE_UINT16_ARRAY:3833NVPA(buf, size, len, buf_end, elem, uint16_array,3834uint16_t, int, "%u");3835break;38363837case DATA_TYPE_INT32_ARRAY:3838NVPA(buf, size, len, buf_end, elem, int32_array,3839int32_t, long, "%ld");3840break;38413842case DATA_TYPE_UINT32_ARRAY:3843NVPA(buf, size, len, buf_end, elem, uint32_array,3844uint32_t, ulong_t, "%lu");3845break;38463847case DATA_TYPE_INT64_ARRAY:3848NVPA(buf, size, len, buf_end, elem, int64_array,3849int64_t, longlong_t, "%lld");3850break;38513852case DATA_TYPE_UINT64_ARRAY:3853NVPA(buf, size, len, buf_end, elem, uint64_array,3854uint64_t, u_longlong_t, "%llu");3855break;38563857case DATA_TYPE_STRING_ARRAY:3858NVPA(buf, size, len, buf_end, elem, string_array,3859const char *, const char *, "'%s'");3860break;38613862case DATA_TYPE_NVLIST:3863(void) nvpair_value_nvlist(elem, &nvlist_value);38643865rc = snprintf(buf, size, "%*s%s:\n", indent, "",3866nvpair_name(elem));3867if (rc < 0)3868return (rc);3869size = MAX((int)size - rc, 0);3870buf = size == 0 ? NULL : buf_end - size;3871len += rc;38723873rc = nvlist_snprintf(buf, size, nvlist_value,3874indent + 4);3875if (rc < 0)3876return (rc);3877size = MAX((int)size - rc, 0);3878buf = size == 0 ? NULL : buf_end - size;3879len += rc;3880break;38813882case DATA_TYPE_NVLIST_ARRAY:3883(void) nvpair_value_nvlist_array(elem,3884&nvlist_array_value, &count);3885for (i = 0; i < count; i++) {3886rc = snprintf(buf, size, "%*s%s[%u]:\n",3887indent, "", nvpair_name(elem), i);3888if (rc < 0)3889return (rc);3890size = MAX((int)size - rc, 0);3891buf = size == 0 ? NULL : buf_end - size;3892len += rc;38933894rc = nvlist_snprintf(buf, size,3895nvlist_array_value[i], indent + 4);3896if (rc < 0)3897return (rc);3898size = MAX((int)size - rc, 0);3899buf = size == 0 ? NULL : buf_end - size;3900len += rc;3901}3902break;39033904default:3905rc = snprintf(buf, size, "bad config type %d for %s\n",3906nvpair_type(elem), nvpair_name(elem));3907if (rc < 0)3908return (rc);3909size = MAX((int)size - rc, 0);3910buf = size == 0 ? NULL : buf_end - size;3911len += rc;3912}3913}3914return (len);3915}39163917EXPORT_SYMBOL(nv_alloc_init);3918EXPORT_SYMBOL(nv_alloc_reset);3919EXPORT_SYMBOL(nv_alloc_fini);39203921/* list management */3922EXPORT_SYMBOL(nvlist_alloc);3923EXPORT_SYMBOL(nvlist_free);3924EXPORT_SYMBOL(nvlist_size);3925EXPORT_SYMBOL(nvlist_pack);3926EXPORT_SYMBOL(nvlist_unpack);3927EXPORT_SYMBOL(nvlist_dup);3928EXPORT_SYMBOL(nvlist_merge);39293930EXPORT_SYMBOL(nvlist_xalloc);3931EXPORT_SYMBOL(nvlist_xpack);3932EXPORT_SYMBOL(nvlist_xunpack);3933EXPORT_SYMBOL(nvlist_xdup);3934EXPORT_SYMBOL(nvlist_lookup_nv_alloc);39353936EXPORT_SYMBOL(nvlist_add_nvpair);3937EXPORT_SYMBOL(nvlist_add_boolean);3938EXPORT_SYMBOL(nvlist_add_boolean_value);3939EXPORT_SYMBOL(nvlist_add_byte);3940EXPORT_SYMBOL(nvlist_add_int8);3941EXPORT_SYMBOL(nvlist_add_uint8);3942EXPORT_SYMBOL(nvlist_add_int16);3943EXPORT_SYMBOL(nvlist_add_uint16);3944EXPORT_SYMBOL(nvlist_add_int32);3945EXPORT_SYMBOL(nvlist_add_uint32);3946EXPORT_SYMBOL(nvlist_add_int64);3947EXPORT_SYMBOL(nvlist_add_uint64);3948EXPORT_SYMBOL(nvlist_add_string);3949EXPORT_SYMBOL(nvlist_add_nvlist);3950EXPORT_SYMBOL(nvlist_add_boolean_array);3951EXPORT_SYMBOL(nvlist_add_byte_array);3952EXPORT_SYMBOL(nvlist_add_int8_array);3953EXPORT_SYMBOL(nvlist_add_uint8_array);3954EXPORT_SYMBOL(nvlist_add_int16_array);3955EXPORT_SYMBOL(nvlist_add_uint16_array);3956EXPORT_SYMBOL(nvlist_add_int32_array);3957EXPORT_SYMBOL(nvlist_add_uint32_array);3958EXPORT_SYMBOL(nvlist_add_int64_array);3959EXPORT_SYMBOL(nvlist_add_uint64_array);3960EXPORT_SYMBOL(nvlist_add_string_array);3961EXPORT_SYMBOL(nvlist_add_nvlist_array);3962EXPORT_SYMBOL(nvlist_next_nvpair);3963EXPORT_SYMBOL(nvlist_prev_nvpair);3964EXPORT_SYMBOL(nvlist_empty);3965EXPORT_SYMBOL(nvlist_add_hrtime);39663967EXPORT_SYMBOL(nvlist_remove);3968EXPORT_SYMBOL(nvlist_remove_nvpair);3969EXPORT_SYMBOL(nvlist_remove_all);39703971EXPORT_SYMBOL(nvlist_lookup_boolean);3972EXPORT_SYMBOL(nvlist_lookup_boolean_value);3973EXPORT_SYMBOL(nvlist_lookup_byte);3974EXPORT_SYMBOL(nvlist_lookup_int8);3975EXPORT_SYMBOL(nvlist_lookup_uint8);3976EXPORT_SYMBOL(nvlist_lookup_int16);3977EXPORT_SYMBOL(nvlist_lookup_uint16);3978EXPORT_SYMBOL(nvlist_lookup_int32);3979EXPORT_SYMBOL(nvlist_lookup_uint32);3980EXPORT_SYMBOL(nvlist_lookup_int64);3981EXPORT_SYMBOL(nvlist_lookup_uint64);3982EXPORT_SYMBOL(nvlist_lookup_string);3983EXPORT_SYMBOL(nvlist_lookup_nvlist);3984EXPORT_SYMBOL(nvlist_lookup_boolean_array);3985EXPORT_SYMBOL(nvlist_lookup_byte_array);3986EXPORT_SYMBOL(nvlist_lookup_int8_array);3987EXPORT_SYMBOL(nvlist_lookup_uint8_array);3988EXPORT_SYMBOL(nvlist_lookup_int16_array);3989EXPORT_SYMBOL(nvlist_lookup_uint16_array);3990EXPORT_SYMBOL(nvlist_lookup_int32_array);3991EXPORT_SYMBOL(nvlist_lookup_uint32_array);3992EXPORT_SYMBOL(nvlist_lookup_int64_array);3993EXPORT_SYMBOL(nvlist_lookup_uint64_array);3994EXPORT_SYMBOL(nvlist_lookup_string_array);3995EXPORT_SYMBOL(nvlist_lookup_nvlist_array);3996EXPORT_SYMBOL(nvlist_lookup_hrtime);3997EXPORT_SYMBOL(nvlist_lookup_pairs);39983999EXPORT_SYMBOL(nvlist_lookup_nvpair);4000EXPORT_SYMBOL(nvlist_exists);40014002EXPORT_SYMBOL(nvlist_snprintf);40034004/* processing nvpair */4005EXPORT_SYMBOL(nvpair_name);4006EXPORT_SYMBOL(nvpair_type);4007EXPORT_SYMBOL(nvpair_value_boolean_value);4008EXPORT_SYMBOL(nvpair_value_byte);4009EXPORT_SYMBOL(nvpair_value_int8);4010EXPORT_SYMBOL(nvpair_value_uint8);4011EXPORT_SYMBOL(nvpair_value_int16);4012EXPORT_SYMBOL(nvpair_value_uint16);4013EXPORT_SYMBOL(nvpair_value_int32);4014EXPORT_SYMBOL(nvpair_value_uint32);4015EXPORT_SYMBOL(nvpair_value_int64);4016EXPORT_SYMBOL(nvpair_value_uint64);4017EXPORT_SYMBOL(nvpair_value_string);4018EXPORT_SYMBOL(nvpair_value_nvlist);4019EXPORT_SYMBOL(nvpair_value_boolean_array);4020EXPORT_SYMBOL(nvpair_value_byte_array);4021EXPORT_SYMBOL(nvpair_value_int8_array);4022EXPORT_SYMBOL(nvpair_value_uint8_array);4023EXPORT_SYMBOL(nvpair_value_int16_array);4024EXPORT_SYMBOL(nvpair_value_uint16_array);4025EXPORT_SYMBOL(nvpair_value_int32_array);4026EXPORT_SYMBOL(nvpair_value_uint32_array);4027EXPORT_SYMBOL(nvpair_value_int64_array);4028EXPORT_SYMBOL(nvpair_value_uint64_array);4029EXPORT_SYMBOL(nvpair_value_string_array);4030EXPORT_SYMBOL(nvpair_value_nvlist_array);4031EXPORT_SYMBOL(nvpair_value_hrtime);403240334034