changeset 11170:349270d482cf

6854201 NDMP needs to include user and group quotas in backup stream
author Reza Sabdar <Reza.Sabdar@Sun.COM>
date Mon, 23 Nov 2009 16:04:12 -0800
parents d46461938be8
children 5f22130fc712
files usr/src/cmd/ndmpd/include/tlm.h usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c usr/src/cmd/ndmpd/tlm/tlm_backup_reader.c usr/src/cmd/ndmpd/tlm/tlm_restore_writer.c usr/src/lib/libndmp/common/libndmp.h
diffstat 5 files changed, 365 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/ndmpd/include/tlm.h	Mon Nov 23 14:57:01 2009 -0800
+++ b/usr/src/cmd/ndmpd/include/tlm.h	Mon Nov 23 16:04:12 2009 -0800
@@ -51,6 +51,8 @@
 #include <sys/stat.h>
 #include <time.h>
 #include <sys/queue.h>
+#include <sys/fs/zfs.h>
+#include <libzfs.h>
 
 #define	IS_SET(f, m)	(((f) & (m)) != 0)
 
@@ -468,23 +470,77 @@
  */
 #define	ZFS_MAX_PROPS		100
 #define	ZFS_META_MAGIC		"ZFSMETA"
+#define	ZFS_META_MAGIC_EXT	"ZFSMETA2"
 
+/* Add new major/minor for header changes */
+typedef enum {
+	META_HDR_MAJOR_0,	/* Original format */
+	META_HDR_MAJOR_1,	/* Extended format */
+} ndmp_metadata_header_major_t;
+
+#define	META_HDR_MAJOR_VERSION	META_HDR_MAJOR_1
+
+typedef enum {
+	META_HDR_MINOR_0,
+} ndmp_metadata_header_minor_t;
+
+#define	META_HDR_MINOR_VERSION	META_HDR_MINOR_0
+
+/* To support older backups */
 typedef struct ndmp_metadata_property {
 	char mp_name[NAME_MAX];
 	char mp_value[NAME_MAX];
 	char mp_source[NAME_MAX];
 } ndmp_metadata_property_t;
 
+typedef struct ndmp_metadata_property_ext {
+	char mp_name[ZFS_MAXNAMELEN];
+	char mp_value[ZFS_MAXPROPLEN];
+	char mp_source[ZFS_MAXPROPLEN];
+} ndmp_metadata_property_ext_t;
+
+typedef struct ndmp_metadata_top_header {
+	char th_plname[100];
+	uint_t th_plversion;
+	char th_magic[10];
+	void *th_reserved_1;
+	int th_count;
+} ndmp_metadata_top_header_t;
+
+/* Original metadata format */
 typedef struct ndmp_metadata_header {
-	char nh_plname[100];
-	uint_t nh_plversion;
-	char nh_magic[10];
-	void *nh_handle;
-	int nh_count;
+	ndmp_metadata_top_header_t nh_hdr;
 	char nh_dataset[NAME_MAX];
 	ndmp_metadata_property_t nh_property[1];
 } ndmp_metadata_header_t;
 
+/* Extended metadata format */
+typedef struct ndmp_metadata_header_ext {
+	ndmp_metadata_top_header_t nh_hdr;
+	char nh_dataset[ZFS_MAXNAMELEN];
+	int32_t nh_total_bytes;
+	int32_t nh_major;
+	int32_t nh_minor;
+	ndmp_metadata_property_ext_t nh_property[1];
+} ndmp_metadata_header_ext_t;
+
+#define	nh_plname	nh_hdr.th_plname
+#define	nh_plversion	nh_hdr.th_plversion
+#define	nh_magic	nh_hdr.th_magic
+#define	nh_count	nh_hdr.th_count
+
+typedef struct ndmp_metadata_handle {
+	void *ml_handle;
+	int32_t ml_quota_prop;
+	union {
+		ndmp_metadata_header_t *u_hdr;
+		ndmp_metadata_header_ext_t *u_xhdr;
+	} ml_hdr_u;
+} ndmp_metadata_handle_t;
+
+#define	ml_hdr	ml_hdr_u.u_hdr
+#define	ml_xhdr	ml_hdr_u.u_xhdr
+
 /*
  * Node in struct hardlink_q
  *
--- a/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c	Mon Nov 23 14:57:01 2009 -0800
+++ b/usr/src/cmd/ndmpd/ndmp/ndmpd_tar3.c	Mon Nov 23 16:04:12 2009 -0800
@@ -2453,9 +2453,10 @@
 			nctx.nc_plversion = ndmp_pl->np_plversion;
 			nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
 			nctx.nc_cmds = cmds;
+			nctx.nc_params = params;
 			if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx,
 			    nlp->nlp_backup_path)) != 0) {
-				NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m");
+				NDMP_LOG(LOG_ERR, "Pre-backup plug-in: %m");
 				goto backup_out;
 			}
 		}
@@ -3223,13 +3224,14 @@
 		if (ndmp_pl != NULL &&
 		    ndmp_pl->np_pre_restore != NULL) {
 			nctx.nc_cmds = cmds;
+			nctx.nc_params = params;
 			ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
 			    dar_index - 1);
 
 			if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx,
 			    ep->nm3_opath, ep->nm3_dpath))
 			    != 0) {
-				NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
+				NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
 				cmds->tcs_command->tc_reader = TLM_STOP;
 				ndmp_stop_local_reader(session, cmds);
 				ndmp_wait_for_reader(cmds);
@@ -3443,6 +3445,28 @@
 	return (0);
 }
 
+/*
+ * Expands the format string and logs the resulting message to the
+ * remote DMA
+ */
+void
+ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...)
+{
+	va_list ap;
+	char buf[256];
+	ndmpd_module_params_t *params;
+
+	if (nctx == NULL ||
+	    (params = (ndmpd_module_params_t *)nctx->nc_params) == NULL)
+		return;
+
+	va_start(ap, fmt);
+	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
+	va_end(ap);
+
+	MOD_LOGV3(params, (ndmp_log_type)lt, "%s", buf);
+}
+
 
 /*
  * ndmpd_rs_sar_tar_v3
@@ -3525,10 +3549,11 @@
 		if (ndmp_pl != NULL &&
 		    ndmp_pl->np_pre_restore != NULL) {
 			nctx.nc_cmds = cmds;
+			nctx.nc_params = params;
 			if ((err = ndmp_plugin_pre_restore(&nctx, params,
 			    nlp->nlp_nfiles))
 			    != 0) {
-				NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m");
+				NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
 				cmds->tcs_command->tc_reader = TLM_STOP;
 				ndmp_stop_local_reader(session, cmds);
 				ndmp_wait_for_reader(cmds);
--- a/usr/src/cmd/ndmpd/tlm/tlm_backup_reader.c	Mon Nov 23 14:57:01 2009 -0800
+++ b/usr/src/cmd/ndmpd/tlm/tlm_backup_reader.c	Mon Nov 23 16:04:12 2009 -0800
@@ -72,7 +72,7 @@
     tlm_cmd_t *);
 
 extern  libzfs_handle_t *zlibh;
-extern  mutex_t zlib_mtx;
+extern	mutex_t zlib_mtx;
 
 
 /*
@@ -1180,30 +1180,41 @@
 static int
 zfs_put_prop_cb(int prop, void *pp)
 {
-	ndmp_metadata_header_t *mhp;
-	ndmp_metadata_property_t *mpp;
-	char buf[ZFS_MAXNAMELEN];
-	char sbuf[ZFS_MAXNAMELEN];
+	ndmp_metadata_handle_t *mhd;
+	ndmp_metadata_header_ext_t *mhp;
+	ndmp_metadata_property_ext_t *mpp;
+	char vbuf[ZFS_MAXPROPLEN];
+	char sbuf[ZFS_MAXPROPLEN];
 	zprop_source_t stype;
 	char *sourcestr;
 
 	if (pp == NULL)
 		return (ZPROP_INVAL);
 
-	mhp = (ndmp_metadata_header_t *)pp;
+	mhd = (ndmp_metadata_handle_t *)pp;
+	mhp = mhd->ml_xhdr;
+	mpp = &mhp->nh_property[mhp->nh_count];
 
-	if (zfs_prop_get(mhp->nh_handle, prop, buf, sizeof (buf),
-	    &stype, sbuf, sizeof (sbuf), B_TRUE) != 0)
+	if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
+	    sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
+		return (ZPROP_INVAL);
+
+	if (zfs_prop_get(mhd->ml_handle, prop, vbuf, sizeof (vbuf),
+	    &stype, sbuf, sizeof (sbuf), B_TRUE) != 0) {
+		mhp->nh_count++;
 		return (ZPROP_CONT);
+	}
 
-	mpp = &mhp->nh_property[mhp->nh_count++];
-	(void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop), NAME_MAX);
-	(void) strlcpy(mpp->mp_value, buf, NAME_MAX);
+	(void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop), ZFS_MAXNAMELEN);
+	(void) strlcpy(mpp->mp_value, vbuf, ZFS_MAXPROPLEN);
 
 	switch (stype) {
 	case ZPROP_SRC_NONE:
 		sourcestr = "none";
 		break;
+	case ZPROP_SRC_RECEIVED:
+		sourcestr = "received";
+		break;
 	case ZPROP_SRC_LOCAL:
 		sourcestr = mhp->nh_dataset;
 		break;
@@ -1217,11 +1228,103 @@
 		sourcestr = sbuf;
 		break;
 	}
-	(void) strlcpy(mpp->mp_source, sourcestr, NAME_MAX);
+	(void) strlcpy(mpp->mp_source, sourcestr, ZFS_MAXPROPLEN);
 
+	mhp->nh_count++;
 	return (ZPROP_CONT);
 }
 
+/*
+ * Callback to backup each ZFS user/group quota
+ */
+static int
+zfs_put_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
+{
+	ndmp_metadata_handle_t *mhd;
+	ndmp_metadata_header_ext_t *mhp;
+	ndmp_metadata_property_ext_t *mpp;
+	char *typestr;
+
+	if (pp == NULL)
+		return (ZPROP_INVAL);
+
+	mhd = (ndmp_metadata_handle_t *)pp;
+	mhp = mhd->ml_xhdr;
+	mpp = &mhp->nh_property[mhp->nh_count];
+
+	if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
+	    sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
+		return (ZPROP_INVAL);
+
+	if (mhd->ml_quota_prop == ZFS_PROP_USERQUOTA)
+		typestr = "userquota";
+	else
+		typestr = "groupquota";
+
+	if (domain == NULL || *domain == '\0')
+		(void) snprintf(mpp->mp_name, ZFS_MAXNAMELEN, "%s@%llu",
+		    typestr, (longlong_t)rid);
+	else
+		(void) snprintf(mpp->mp_name, ZFS_MAXNAMELEN, "%s@%s-%llu",
+		    typestr, domain, (longlong_t)rid);
+	(void) snprintf(mpp->mp_value, ZFS_MAXPROPLEN, "%llu", space);
+	(void) strlcpy(mpp->mp_source, mhp->nh_dataset, ZFS_MAXPROPLEN);
+
+	mhp->nh_count++;
+	return (0);
+}
+
+/*
+ * Callback to count each ZFS property
+ */
+/*ARGSUSED*/
+static int
+zfs_count_prop_cb(int prop, void *pp)
+{
+	(*(int *)pp)++;
+	return (ZPROP_CONT);
+}
+
+/*
+ * Callback to count each ZFS user/group quota
+ */
+/*ARGSUSED*/
+static int
+zfs_count_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
+{
+	(*(int *)pp)++;
+	return (0);
+}
+
+/*
+ * Count the number of ZFS properties and user/group quotas
+ */
+int
+zfs_get_prop_counts(zfs_handle_t *zhp)
+{
+	int count = 0;
+	nvlist_t *uprops;
+	nvpair_t *elp;
+
+	if (zhp == NULL)
+		return (0);
+
+	(void) zprop_iter(zfs_count_prop_cb, &count, TRUE, TRUE,
+	    ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
+
+	(void) zfs_userspace(zhp, ZFS_PROP_USERQUOTA, zfs_count_quota_cb,
+	    &count);
+	(void) zfs_userspace(zhp, ZFS_PROP_GROUPQUOTA, zfs_count_quota_cb,
+	    &count);
+
+	uprops = zfs_get_user_props(zhp);
+
+	elp = nvlist_next_nvpair(uprops, NULL);
+	for (; elp != NULL; elp = nvlist_next_nvpair(uprops, elp))
+		count++;
+
+	return (count);
+}
 
 /*
  * Notifies ndmpd that the metadata associated with the given ZFS dataset
@@ -1231,8 +1334,10 @@
 ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset)
 {
 	tlm_commands_t *cmds;
-	ndmp_metadata_header_t *mhp;
-	ndmp_metadata_property_t *mpp;
+	ndmp_metadata_handle_t mhd;
+	ndmp_metadata_header_ext_t *mhp;
+	ndmp_metadata_property_ext_t *mpp;
+	zfs_handle_t *zhp;
 	tlm_cmd_t *lcmd;
 	long actual_size;
 	nvlist_t *uprops, *ulist;
@@ -1242,6 +1347,7 @@
 	char *wbuf, *pp, *tp;
 	long size, lsize, sz;
 	int align = RECORDSIZE - 1;
+	int pcount;
 
 	if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
 		return (-1);
@@ -1250,35 +1356,46 @@
 	    lcmd->tc_buffers == NULL)
 		return (-1);
 
-	size = sizeof (ndmp_metadata_header_t) +
-	    ZFS_MAX_PROPS * sizeof (ndmp_metadata_property_t);
+	(void) mutex_lock(&zlib_mtx);
+	if ((zhp = zfs_open(zlibh, dataset, ZFS_TYPE_DATASET)) == NULL) {
+		(void) mutex_unlock(&zlib_mtx);
+		return (-1);
+	}
+
+	pcount = zfs_get_prop_counts(zhp);
+	size = sizeof (ndmp_metadata_header_ext_t) +
+	    pcount * sizeof (ndmp_metadata_property_ext_t);
+
 	size += align;
 	size &= ~align;
 
-	if ((mhp = malloc(size)) == NULL)
+	if ((mhp = malloc(size)) == NULL) {
+		zfs_close(zhp);
+		(void) mutex_unlock(&zlib_mtx);
 		return (-1);
+	}
+
 	(void) memset(mhp, 0, size);
 
+	mhd.ml_handle = zhp;
+	mhd.ml_xhdr = mhp;
+	mhp->nh_total_bytes = size;
+	mhp->nh_major = META_HDR_MAJOR_VERSION;
+	mhp->nh_minor = META_HDR_MINOR_VERSION;
 	mhp->nh_plversion = nctx->nc_plversion;
+
 	(void) strlcpy(mhp->nh_plname, nctx->nc_plname,
 	    sizeof (mhp->nh_plname));
-	(void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC, sizeof (mhp->nh_magic));
+	(void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC_EXT,
+	    sizeof (mhp->nh_magic));
 	(void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset));
 
-	(void) mutex_lock(&zlib_mtx);
-	if ((mhp->nh_handle = zfs_open(zlibh, dataset,
-	    ZFS_TYPE_DATASET)) == NULL) {
-		(void) mutex_unlock(&zlib_mtx);
-		free(mhp);
-		return (ZPROP_INVAL);
-	}
-
 	/* Get all the ZFS properties */
-	(void) zprop_iter(zfs_put_prop_cb, mhp, TRUE, TRUE,
+	(void) zprop_iter(zfs_put_prop_cb, &mhd, TRUE, TRUE,
 	    ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
 
 	/* Get user properties */
-	uprops = zfs_get_user_props(mhp->nh_handle);
+	uprops = zfs_get_user_props(mhd.ml_handle);
 
 	elp = nvlist_next_nvpair(uprops, NULL);
 
@@ -1287,21 +1404,29 @@
 		if (nvpair_value_nvlist(elp, &ulist) != 0 ||
 		    nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 ||
 		    nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) {
-			zfs_close(mhp->nh_handle);
+			zfs_close(mhd.ml_handle);
 			(void) mutex_unlock(&zlib_mtx);
 			free(mhp);
 			return (-1);
 		}
 		if ((pname = nvpair_name(elp)) != NULL)
-			(void) strlcpy(mpp->mp_name, pname, NAME_MAX);
+			(void) strlcpy(mpp->mp_name, pname, ZFS_MAXNAMELEN);
 
-		(void) strlcpy(mpp->mp_value, sval, NAME_MAX);
-		(void) strlcpy(mpp->mp_source, ssrc, NAME_MAX);
+		(void) strlcpy(mpp->mp_value, sval, ZFS_MAXPROPLEN);
+		(void) strlcpy(mpp->mp_source, ssrc, ZFS_MAXPROPLEN);
 		mhp->nh_count++;
 		elp = nvlist_next_nvpair(uprops, elp);
 	}
 
-	zfs_close(mhp->nh_handle);
+	mhd.ml_quota_prop = ZFS_PROP_USERQUOTA;
+	(void) zfs_userspace(mhd.ml_handle, ZFS_PROP_USERQUOTA,
+	    zfs_put_quota_cb, &mhd);
+	mhd.ml_quota_prop = ZFS_PROP_GROUPQUOTA;
+	(void) zfs_userspace(mhd.ml_handle, ZFS_PROP_GROUPQUOTA,
+	    zfs_put_quota_cb, &mhd);
+	mhp->nh_count = pcount;
+
+	zfs_close(mhd.ml_handle);
 	(void) mutex_unlock(&zlib_mtx);
 
 	if ((wbuf = get_write_buffer(size, &actual_size, TRUE,
@@ -1316,7 +1441,7 @@
 		while (sz < size &&
 		    ((tp = get_write_buffer(size - sz, &lsize,
 		    TRUE, lcmd))) != NULL) {
-			(void) memcpy(tp, pp, size - sz);
+			(void) memcpy(tp, pp, lsize);
 			sz += lsize;
 			pp += lsize;
 		}
--- a/usr/src/cmd/ndmpd/tlm/tlm_restore_writer.c	Mon Nov 23 14:57:01 2009 -0800
+++ b/usr/src/cmd/ndmpd/tlm/tlm_restore_writer.c	Mon Nov 23 16:04:12 2009 -0800
@@ -2160,14 +2160,14 @@
 {
 	tlm_commands_t *cmds;
 	ndmp_metadata_header_t *mhp;
+	ndmp_metadata_header_ext_t *mhpx;
 	ndmp_metadata_property_t *mpp;
+	ndmp_metadata_property_ext_t *mppx;
 	tlm_cmd_t *lcmd;
 	int actual_size;
 	nvlist_t *nvl;
-	nvlist_t *nvl_head;
 	nvlist_t *valp;
 	nvpair_t *nvp = NULL;
-	nvpair_t *nvph = NULL;
 	char plname[100];
 	char *mhbuf, *pp, *tp;
 	int rv, i;
@@ -2182,15 +2182,12 @@
 	    lcmd->tc_buffers == NULL)
 		return (-1);
 
+	/* Default minimum bytes needed */
 	size = sizeof (ndmp_metadata_header_t) +
 	    ZFS_MAX_PROPS * sizeof (ndmp_metadata_property_t);
 	size += align;
 	size &= ~align;
 
-	/* For nvlist cleanup */
-	if (nvlist_alloc(&nvl_head, NV_UNIQUE_NAME, 0) != 0)
-		return (-1);
-
 	if ((mhbuf = malloc(size)) == NULL)
 		return (-1);
 
@@ -2200,13 +2197,29 @@
 		pp = mhbuf;
 
 		if (strncmp(mhp->nh_magic, ZFS_META_MAGIC,
+		    sizeof (mhp->nh_magic)) != 0 &&
+		    strncmp(mhp->nh_magic, ZFS_META_MAGIC_EXT,
 		    sizeof (mhp->nh_magic)) != 0) {
 			/* No more metadata */
 			tlm_unget_read_buffer(lcmd->tc_buffers, actual_size);
-			nvlist_free(nvl_head);
+			free(mhbuf);
 			return (0);
 		}
 
+		if (strncmp(mhp->nh_magic, ZFS_META_MAGIC_EXT,
+		    sizeof (mhp->nh_magic)) == 0) {
+			mhpx = (ndmp_metadata_header_ext_t *)mhp;
+			if (mhpx->nh_total_bytes > size) {
+				if ((pp = realloc(mhbuf, mhpx->nh_total_bytes))
+				    == NULL) {
+					free(mhbuf);
+					return (-1);
+				}
+				mhbuf = pp;
+			}
+			size = mhpx->nh_total_bytes;
+		}
+
 		(void) memcpy(pp, (char *)mhp, (actual_size < size) ?
 		    actual_size : size);
 		pp += (actual_size < size) ? actual_size : size;
@@ -2215,55 +2228,116 @@
 		while (sz < size &&
 		    ((tp = get_read_buffer(size - sz, &rv, &lsize,
 		    lcmd))) != NULL) {
-			(void) memcpy(pp, tp, size - sz);
+			(void) memcpy(pp, tp, lsize);
 			sz += lsize;
 			pp += lsize;
 		}
 		if (sz > size) {
 			tlm_unget_read_buffer(lcmd->tc_buffers, sz - size);
 		}
+
 		/* LINTED improper alignment */
 		mhp = (ndmp_metadata_header_t *)mhbuf;
 
-		nctx->nc_plversion = mhp->nh_plversion;
-		(void) strlcpy(plname, mhp->nh_plname, sizeof (plname));
+		nvl = NULL;
+		if (strncmp(mhp->nh_magic, ZFS_META_MAGIC_EXT,
+		    sizeof (mhp->nh_magic)) == 0) {
+			/* New metadata format */
+			/* LINTED improper alignment */
+			mhpx = (ndmp_metadata_header_ext_t *)mhbuf;
 
-		if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
-			goto nvlist_err;
+			if (mhpx->nh_major > META_HDR_MAJOR_VERSION) {
+				/* Major header mismatch */
+				NDMP_LOG(LOG_ERR, "metadata header mismatch",
+				    "M%d != M%d", mhpx->nh_major,
+				    META_HDR_MAJOR_VERSION);
+				free(mhbuf);
+				return (-1);
+			}
+			if (mhpx->nh_major == META_HDR_MAJOR_VERSION &&
+			    mhpx->nh_minor > META_HDR_MINOR_VERSION) {
+				/* Minor header mismatch */
+				NDMP_LOG(LOG_ERR, "Warning:"
+				    "metadata header mismatch m%d != m%d",
+				    mhpx->nh_minor,
+				    META_HDR_MINOR_VERSION);
+				continue;
+			}
+
+			nctx->nc_plversion = mhpx->nh_plversion;
+			(void) strlcpy(plname, mhpx->nh_plname,
+			    sizeof (plname));
+
+			if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+				goto nvlist_err;
 
-		mpp = &mhp->nh_property[0];
-		for (i = 0; i < mhp->nh_count && mpp; i++) {
-			if (nvlist_alloc(&valp, NV_UNIQUE_NAME, 0) != 0 ||
-			    nvlist_add_string(valp, "value",
-			    mpp->mp_value) != 0 ||
-			    nvlist_add_string(valp, "source",
-			    mpp->mp_source) != 0 ||
-			    nvlist_add_nvlist(nvl, mpp->mp_name, valp) != 0)
+			mppx = &mhpx->nh_property[0];
+			for (i = 0; i < mhpx->nh_count && mppx; i++, mppx++) {
+				if (!*mppx->mp_name)
+					continue;
+				valp = NULL;
+				if (nvlist_alloc(&valp,
+				    NV_UNIQUE_NAME, 0) != 0 ||
+				    nvlist_add_string(valp, "value",
+				    mppx->mp_value) != 0 ||
+				    nvlist_add_string(valp, "source",
+				    mppx->mp_source) != 0 ||
+				    nvlist_add_nvlist(nvl, mppx->mp_name,
+				    valp) != 0) {
+					nvlist_free(valp);
+					goto nvlist_err;
+				}
+				nvlist_free(valp);
+			}
+		} else {
+			nctx->nc_plversion = mhp->nh_plversion;
+			(void) strlcpy(plname, mhp->nh_plname,
+			    sizeof (plname));
+
+			if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
 				goto nvlist_err;
-			mpp++;
+
+			mpp = &mhp->nh_property[0];
+			for (i = 0; i < mhp->nh_count && mpp; i++, mpp++) {
+				if (!*mpp->mp_name)
+					continue;
+				valp = NULL;
+				if (nvlist_alloc(&valp,
+				    NV_UNIQUE_NAME, 0) != 0 ||
+				    nvlist_add_string(valp, "value",
+				    mpp->mp_value) != 0 ||
+				    nvlist_add_string(valp, "source",
+				    mpp->mp_source) != 0 ||
+				    nvlist_add_nvlist(nvl, mpp->mp_name,
+				    valp) != 0) {
+					nvlist_free(valp);
+					goto nvlist_err;
+				}
+				nvlist_free(valp);
+			}
 		}
 
 		if (np_restore_property(nvl, ptr) != 0)
 			goto nvlist_err;
 
-		(void) nvlist_add_nvlist(nvl_head, "_", nvl);
-	}
-	free(mhbuf);
-
-	nvlist_free(nvl_head);
-	return (0);
-
-nvlist_err:
-	free(mhbuf);
-	while ((nvph = nvlist_next_nvpair(nvl_head, nvph)) != NULL &&
-	    nvpair_value_nvlist(nvph, &nvl) == 0) {
 		while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL &&
 		    nvpair_value_nvlist(nvp, &valp) == 0) {
 			nvlist_free(valp);
 		}
 		nvlist_free(nvl);
 	}
-	nvlist_free(nvl_head);
+
+	free(mhbuf);
+	return (0);
+
+nvlist_err:
+	free(mhbuf);
+
+	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL &&
+	    nvpair_value_nvlist(nvp, &valp) == 0) {
+		nvlist_free(valp);
+	}
+	nvlist_free(nvl);
 	return (-1);
 }
 
--- a/usr/src/lib/libndmp/common/libndmp.h	Mon Nov 23 14:57:01 2009 -0800
+++ b/usr/src/lib/libndmp/common/libndmp.h	Mon Nov 23 16:04:12 2009 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -66,6 +66,7 @@
 	uint_t nc_plversion;
 	void *nc_pldata;
 	void *nc_cmds;
+	void *nc_params;
 } ndmp_context_t;
 
 typedef struct ndmp_plugin {
@@ -84,6 +85,13 @@
 		int);
 } ndmp_plugin_t;
 
+typedef enum ndmp_log_dma_type {
+	NDMP_LOGD_NORMAL = 0,
+	NDMP_LOGD_DEBUG = 1,
+	NDMP_LOGD_ERROR = 2,
+	NDMP_LOGD_WARNING = 3
+} ndmp_log_dma_type_t;
+
 /* libndmp error codes */
 #define	ENDMP_BASE	2000
 enum {
@@ -360,6 +368,7 @@
 extern uint_t ndmp_context_get_version(ndmp_context_t *);
 extern void ndmp_context_set_specific(ndmp_context_t *, void *);
 extern void *ndmp_context_get_specific(ndmp_context_t *);
+void ndmp_log_dma(ndmp_context_t *, ndmp_log_dma_type_t, const char *, ...);
 
 #ifdef	__cplusplus
 }