Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 22 Dec 2015 23:05:43 +0000 (UTC)
From:      Garrett Cooper <ngie@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r292632 - user/ngie/stable-10-libnv/lib/libnv
Message-ID:  <201512222305.tBMN5hSd088581@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ngie
Date: Tue Dec 22 23:05:43 2015
New Revision: 292632
URL: https://svnweb.freebsd.org/changeset/base/292632

Log:
  MFC r271578,r271579,r271847,r272102,r272843,r273752,r277920,r277921,r277925,r277926,r277927,r279421,r279422,r279423:
  
  r271578 (by pjd):
  
  Remove the limit on descriptors that can be send in one nvlist.
  
  Submitted by:	Mariusz Zaborski
  
  r271579 (by pjd):
  
  Use non-recursive algorithm for traversing nvlists. This also removes
  the limit on number of nested nvlists.
  
  Submitted by:	Mariusz Zaborski
  
  r271847 (by pjd):
  
  Don't use nvl in case of a failure.
  
  Reported by:	Coverity
  CID:		1238922
  
  r272102 (by pjd):
  
  Document the new nvlist_get_parent() function.
  
  Submitted by:	Mariusz Zaborski
  
  r272843 (by pjd):
  
  Fix problem on big endian systems introduced in r271579 - when we were
  returning from handling a nested nvlist we were resetting big-endian flag.
  
  Reported by:	Kuleshov Aleksey @ yandex.ru
  Tested by:	Kuleshov Aleksey @ yandex.ru
  
  r273752 (by jmg):
  
  fix typo, properly install a link to nv for nvlist_freev...
  
  r277920 (by pjd):
  
  If moving descriptor or binary data to an nvlist fails, we need to close the
  descriptor or free the memory before returning.
  
  Submitted by:	Mariusz Zaborski <oshogbo@FreeBSD.org>
  
  While here, protect errno, so it won't be overwritted by close(2) or free(3).
  
  r277921 (by pjd):
  
  Modify nvlist_get_parent() API to take additional cookie argument.
  This allow for non-recursive iteration over nested nvlists, as in documented
  example.
  
  Submitted by:	Mariusz Zaborski <oshogbo@FreeBSD.org>
  
  r277925 (by pjd):
  
  Handle empty nvlists correctly.
  
  Submitted by:	Mariusz Zaborski <oshogbo@FreeBSD.org>
  
  r277926 (by pjd):
  
  Add missing nvlist_get_parent(3) link.
  
  Submitted by:	Mariusz Zaborski <oshogbo@FreeBSD.org>
  
  r277927 (by pjd):
  
  Make gcc happy.
  
  Reported by:	bz
  
  r279421 (by rstone):
  
  Make libnv headers includable from C++
  
  Differential Revision:		https://reviews.freebsd.org/D1868
  Reviewed by:			jfv, pjd
  Sponsored by:			Sandvine Inc.
  
  r279422 (by rstone):
  
  Tests of basic nvlist add functions
  
  Differential Revision:		https://reviews.freebsd.org/D1869
  Reviewed by:			jfv, pjd
  Sponsored by:			Sandvine Inc.
  
  r279423 (by rstone):
  
  Revert r279422.  My "apply patch and commit" script wasn't adding
  new files properly.
  
  Pointy hat to: rstone

Modified:
  user/ngie/stable-10-libnv/lib/libnv/Makefile
  user/ngie/stable-10-libnv/lib/libnv/dnv.h
  user/ngie/stable-10-libnv/lib/libnv/msgio.c
  user/ngie/stable-10-libnv/lib/libnv/nv.3
  user/ngie/stable-10-libnv/lib/libnv/nv.h
  user/ngie/stable-10-libnv/lib/libnv/nv_impl.h
  user/ngie/stable-10-libnv/lib/libnv/nvlist.c
  user/ngie/stable-10-libnv/lib/libnv/nvlist_impl.h
  user/ngie/stable-10-libnv/lib/libnv/nvpair.c
  user/ngie/stable-10-libnv/lib/libnv/nvpair_impl.h
Directory Properties:
  user/ngie/stable-10-libnv/   (props changed)

Modified: user/ngie/stable-10-libnv/lib/libnv/Makefile
==============================================================================
--- user/ngie/stable-10-libnv/lib/libnv/Makefile	Tue Dec 22 23:02:12 2015	(r292631)
+++ user/ngie/stable-10-libnv/lib/libnv/Makefile	Tue Dec 22 23:05:43 2015	(r292632)
@@ -60,6 +60,7 @@ MLINKS+=nv.3 nvlist_create.3 \
 	nv.3 nvlist_get_nvlist.3 \
 	nv.3 nvlist_get_descriptor.3 \
 	nv.3 nvlist_get_binary.3 \
+	nv.3 nvlist_get_parent.3 \
 	nv.3 nvlist_take_bool.3 \
 	nv.3 nvlist_take_number.3 \
 	nv.3 nvlist_take_string.3 \
@@ -148,7 +149,7 @@ MLINKS+=nv.3 nvlist_existsv.3 \
 	nv.3 nvlist_takev_nvlist.3 \
 	nv.3 nvlist_takev_descriptor.3 \
 	nv.3 nvlist_takev_binary.3 \
-	nv.3 nvlist_freef.3 \
+	nv.3 nvlist_freev.3 \
 	nv.3 nvlist_freev_type.3 \
 	nv.3 nvlist_freev_null.3 \
 	nv.3 nvlist_freev_bool.3 \

Modified: user/ngie/stable-10-libnv/lib/libnv/dnv.h
==============================================================================
--- user/ngie/stable-10-libnv/lib/libnv/dnv.h	Tue Dec 22 23:02:12 2015	(r292631)
+++ user/ngie/stable-10-libnv/lib/libnv/dnv.h	Tue Dec 22 23:05:43 2015	(r292632)
@@ -45,6 +45,8 @@ struct nvlist;
 typedef struct nvlist nvlist_t;
 #endif
 
+__BEGIN_DECLS
+
 /*
  * The dnvlist_get functions returns value associated with the given name.
  * If it returns a pointer, the pointer represents internal buffer and should
@@ -103,4 +105,6 @@ nvlist_t *dnvlist_takev_nvlist(nvlist_t 
 int dnvlist_takev_descriptor(nvlist_t *nvl, int defval, const char *namefmt, va_list nameap) __printflike(3, 0);
 void *dnvlist_takev_binary(nvlist_t *nvl, size_t *sizep, void *defval, size_t defsize, const char *namefmt, va_list nameap) __printflike(5, 0);
 
+__END_DECLS
+
 #endif	/* !_DNV_H_ */

Modified: user/ngie/stable-10-libnv/lib/libnv/msgio.c
==============================================================================
--- user/ngie/stable-10-libnv/lib/libnv/msgio.c	Tue Dec 22 23:02:12 2015	(r292631)
+++ user/ngie/stable-10-libnv/lib/libnv/msgio.c	Tue Dec 22 23:05:43 2015	(r292632)
@@ -31,7 +31,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/socket.h>
 
 #include <errno.h>
@@ -56,6 +56,8 @@ __FBSDID("$FreeBSD$");
 #define	PJDLOG_ABORT(...)		abort()
 #endif
 
+#define	PKG_MAX_SIZE	(MCLBYTES / CMSG_SPACE(sizeof(int)) - 1)
+
 static int
 msghdr_add_fd(struct cmsghdr *cmsg, int fd)
 {
@@ -234,22 +236,31 @@ cred_recv(int sock, struct cmsgcred *cre
 	return (0);
 }
 
-int
-fd_send(int sock, const int *fds, size_t nfds)
+static int
+fd_package_send(int sock, const int *fds, size_t nfds)
 {
 	struct msghdr msg;
 	struct cmsghdr *cmsg;
+	struct iovec iov;
 	unsigned int i;
 	int serrno, ret;
+	uint8_t dummy;
 
-	if (nfds == 0 || fds == NULL) {
-		errno = EINVAL;
-		return (-1);
-	}
+	PJDLOG_ASSERT(sock >= 0);
+	PJDLOG_ASSERT(fds != NULL);
+	PJDLOG_ASSERT(nfds > 0);
 
 	bzero(&msg, sizeof(msg));
-	msg.msg_iov = NULL;
-	msg.msg_iovlen = 0;
+
+	/*
+	 * XXX: Look into cred_send function for more details.
+	 */
+	dummy = 0;
+	iov.iov_base = &dummy;
+	iov.iov_len = sizeof(dummy);
+
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
 	msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
 	msg.msg_control = calloc(1, msg.msg_controllen);
 	if (msg.msg_control == NULL)
@@ -274,22 +285,32 @@ end:
 	return (ret);
 }
 
-int
-fd_recv(int sock, int *fds, size_t nfds)
+static int
+fd_package_recv(int sock, int *fds, size_t nfds)
 {
 	struct msghdr msg;
 	struct cmsghdr *cmsg;
 	unsigned int i;
 	int serrno, ret;
+	struct iovec iov;
+	uint8_t dummy;
 
-	if (nfds == 0 || fds == NULL) {
-		errno = EINVAL;
-		return (-1);
-	}
+	PJDLOG_ASSERT(sock >= 0);
+	PJDLOG_ASSERT(nfds > 0);
+	PJDLOG_ASSERT(fds != NULL);
 
+	i = 0;
 	bzero(&msg, sizeof(msg));
-	msg.msg_iov = NULL;
-	msg.msg_iovlen = 0;
+	bzero(&iov, sizeof(iov));
+
+	/*
+	 * XXX: Look into cred_send function for more details.
+	 */
+	iov.iov_base = &dummy;
+	iov.iov_len = sizeof(dummy);
+
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
 	msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
 	msg.msg_control = calloc(1, msg.msg_controllen);
 	if (msg.msg_control == NULL)
@@ -333,6 +354,64 @@ end:
 }
 
 int
+fd_recv(int sock, int *fds, size_t nfds)
+{
+	unsigned int i, step, j;
+	int ret, serrno;
+
+	if (nfds == 0 || fds == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	ret = i = step = 0;
+	while (i < nfds) {
+		if (PKG_MAX_SIZE < nfds - i)
+			step = PKG_MAX_SIZE;
+		else
+			step = nfds - i;
+		ret = fd_package_recv(sock, fds + i, step);
+		if (ret != 0) {
+			/* Close all received descriptors. */
+			serrno = errno;
+			for (j = 0; j < i; j++)
+				close(fds[j]);
+			errno = serrno;
+			break;
+		}
+		i += step;
+	}
+
+	return (ret);
+}
+
+int
+fd_send(int sock, const int *fds, size_t nfds)
+{
+	unsigned int i, step;
+	int ret;
+
+	if (nfds == 0 || fds == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+
+	ret = i = step = 0;
+	while (i < nfds) {
+		if (PKG_MAX_SIZE < nfds - i)
+			step = PKG_MAX_SIZE;
+		else
+			step = nfds - i;
+		ret = fd_package_send(sock, fds + i, step);
+		if (ret != 0)
+			break;
+		i += step;
+	}
+
+	return (ret);
+}
+
+int
 buf_send(int sock, void *buf, size_t size)
 {
 	ssize_t done;

Modified: user/ngie/stable-10-libnv/lib/libnv/nv.3
==============================================================================
--- user/ngie/stable-10-libnv/lib/libnv/nv.3	Tue Dec 22 23:02:12 2015	(r292631)
+++ user/ngie/stable-10-libnv/lib/libnv/nv.3	Tue Dec 22 23:05:43 2015	(r292632)
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 21, 2014
+.Dd January 30, 2015
 .Dt NV 3
 .Os
 .Sh NAME
@@ -150,6 +150,8 @@
 .Fn nvlist_get_descriptor "const nvlist_t *nvl" "const char *name"
 .Ft "const void *"
 .Fn nvlist_get_binary "const nvlist_t *nvl" "const char *name" "size_t *sizep"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_parent "const nvlist_t *nvl" "void **cookiep"
 .\"
 .Ft bool
 .Fn nvlist_take_bool "nvlist_t *nvl" "const char *name"
@@ -437,6 +439,10 @@ extension, which allows to provide defau
 The nvlist must not be in error state.
 .Pp
 The
+.Fn nvlist_get_parent
+function allows to obtain the parent nvlist from the nested nvlist.
+.Pp
+The
 .Fn nvlist_take_bool ,
 .Fn nvlist_take_number ,
 .Fn nvlist_take_string ,
@@ -582,6 +588,28 @@ while ((name = nvlist_next(nvl, &type, &
 	printf("\\n");
 }
 .Ed
+.Pp
+Iterating over every nested nvlist:
+.Bd -literal
+nvlist_t *nvl;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock);
+if (nvl == NULL)
+	err(1, "nvlist_recv() failed");
+
+cookie = NULL;
+do {
+	while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+		if (type == NV_TYPE_NVLIST) {
+			nvl = nvlist_get_nvlist(nvl, name);
+			cookie = NULL;
+		}
+	}
+} while ((nvl = nvlist_get_parent(nvl, &cookie)) != NULL);
+.Ed
 .Sh SEE ALSO
 .Xr close 2 ,
 .Xr dup 2 ,

Modified: user/ngie/stable-10-libnv/lib/libnv/nv.h
==============================================================================
--- user/ngie/stable-10-libnv/lib/libnv/nv.h	Tue Dec 22 23:02:12 2015	(r292631)
+++ user/ngie/stable-10-libnv/lib/libnv/nv.h	Tue Dec 22 23:05:43 2015	(r292632)
@@ -63,6 +63,8 @@ typedef struct nvlist nvlist_t;
  */
 #define	NV_FLAG_IGNORE_CASE		0x01
 
+__BEGIN_DECLS
+
 nvlist_t	*nvlist_create(int flags);
 void		 nvlist_destroy(nvlist_t *nvl);
 int		 nvlist_error(const nvlist_t *nvl);
@@ -83,6 +85,8 @@ nvlist_t *nvlist_xfer(int sock, nvlist_t
 
 const char *nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep);
 
+const nvlist_t *nvlist_get_parent(const nvlist_t *nvl, void **cookiep);
+
 /*
  * The nvlist_exists functions check if the given name (optionally of the given
  * type) exists on nvlist.
@@ -270,4 +274,6 @@ void nvlist_freev_nvlist(nvlist_t *nvl, 
 void nvlist_freev_descriptor(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
 void nvlist_freev_binary(nvlist_t *nvl, const char *namefmt, va_list nameap) __printflike(2, 0);
 
+__END_DECLS
+
 #endif	/* !_NV_H_ */

Modified: user/ngie/stable-10-libnv/lib/libnv/nv_impl.h
==============================================================================
--- user/ngie/stable-10-libnv/lib/libnv/nv_impl.h	Tue Dec 22 23:02:12 2015	(r292631)
+++ user/ngie/stable-10-libnv/lib/libnv/nv_impl.h	Tue Dec 22 23:05:43 2015	(r292632)
@@ -39,6 +39,8 @@ struct nvpair;
 typedef struct nvpair nvpair_t;
 #endif
 
+#define	NV_TYPE_NVLIST_UP		255
+
 #define	NV_TYPE_FIRST		NV_TYPE_NULL
 #define	NV_TYPE_LAST		NV_TYPE_BINARY
 
@@ -55,6 +57,8 @@ void nvlist_add_nvpair(nvlist_t *nvl, co
 
 void nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp);
 
+void nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent);
+
 const nvpair_t *nvlist_get_nvpair(const nvlist_t *nvl, const char *name);
 
 nvpair_t *nvlist_take_nvpair(nvlist_t *nvl, const char *name);

Modified: user/ngie/stable-10-libnv/lib/libnv/nvlist.c
==============================================================================
--- user/ngie/stable-10-libnv/lib/libnv/nvlist.c	Tue Dec 22 23:02:12 2015	(r292631)
+++ user/ngie/stable-10-libnv/lib/libnv/nvlist.c	Tue Dec 22 23:05:43 2015	(r292632)
@@ -73,10 +73,11 @@ __FBSDID("$FreeBSD$");
 
 #define	NVLIST_MAGIC	0x6e766c	/* "nvl" */
 struct nvlist {
-	int		nvl_magic;
-	int		nvl_error;
-	int		nvl_flags;
-	struct nvl_head	nvl_head;
+	int		 nvl_magic;
+	int		 nvl_error;
+	int		 nvl_flags;
+	nvpair_t	*nvl_parent;
+	struct nvl_head	 nvl_head;
 };
 
 #define	NVLIST_ASSERT(nvl)	do {					\
@@ -106,6 +107,7 @@ nvlist_create(int flags)
 	nvl = malloc(sizeof(*nvl));
 	nvl->nvl_error = 0;
 	nvl->nvl_flags = flags;
+	nvl->nvl_parent = NULL;
 	TAILQ_INIT(&nvl->nvl_head);
 	nvl->nvl_magic = NVLIST_MAGIC;
 
@@ -147,6 +149,40 @@ nvlist_error(const nvlist_t *nvl)
 	return (nvl->nvl_error);
 }
 
+nvpair_t *
+nvlist_get_nvpair_parent(const nvlist_t *nvl)
+{
+
+	NVLIST_ASSERT(nvl);
+
+	return (nvl->nvl_parent);
+}
+
+const nvlist_t *
+nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
+{
+	nvpair_t *nvp;
+
+	NVLIST_ASSERT(nvl);
+
+	nvp = nvl->nvl_parent;
+	if (cookiep != NULL)
+		*cookiep = nvp;
+	if (nvp == NULL)
+		return (NULL);
+
+	return (nvpair_nvlist(nvp));
+}
+
+void
+nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
+{
+
+	NVLIST_ASSERT(nvl);
+
+	nvl->nvl_parent = parent;
+}
+
 bool
 nvlist_empty(const nvlist_t *nvl)
 {
@@ -301,24 +337,36 @@ nvlist_clone(const nvlist_t *nvl)
 	return (newnvl);
 }
 
-/*
- * Dump content of nvlist.
- */
-static void
-nvlist_xdump(const nvlist_t *nvl, int fd, int level)
+static bool
+nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
 {
-	nvpair_t *nvp;
-
-	PJDLOG_ASSERT(level < 3);
 
 	if (nvlist_error(nvl) != 0) {
 		dprintf(fd, "%*serror: %d\n", level * 4, "",
 		    nvlist_error(nvl));
-		return;
+		return (true);
 	}
 
-	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
-	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+	return (false);
+}
+
+/*
+ * Dump content of nvlist.
+ */
+void
+nvlist_dump(const nvlist_t *nvl, int fd)
+{
+	const nvlist_t *tmpnvl;
+	nvpair_t *nvp, *tmpnvp;
+	void *cookie;
+	int level;
+
+	level = 0;
+	if (nvlist_dump_error_check(nvl, fd, level))
+		return;
+
+	nvp = nvlist_first_nvpair(nvl);
+	while (nvp != NULL) {
 		dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
 		    nvpair_type_string(nvpair_type(nvp)));
 		switch (nvpair_type(nvp)) {
@@ -340,7 +388,16 @@ nvlist_xdump(const nvlist_t *nvl, int fd
 			break;
 		case NV_TYPE_NVLIST:
 			dprintf(fd, "\n");
-			nvlist_xdump(nvpair_get_nvlist(nvp), fd, level + 1);
+			tmpnvl = nvpair_get_nvlist(nvp);
+			if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
+				break;
+			tmpnvp = nvlist_first_nvpair(tmpnvl);
+			if (tmpnvp != NULL) {
+				nvl = tmpnvl;
+				nvp = tmpnvp;
+				level++;
+				continue;
+			}
 			break;
 		case NV_TYPE_DESCRIPTOR:
 			dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
@@ -361,14 +418,16 @@ nvlist_xdump(const nvlist_t *nvl, int fd
 		default:
 			PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
 		}
-	}
-}
-
-void
-nvlist_dump(const nvlist_t *nvl, int fd)
-{
 
-	nvlist_xdump(nvl, fd, 0);
+		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
+			cookie = NULL;
+			nvl = nvlist_get_parent(nvl, &cookie);
+			if (nvl == NULL)
+				return;
+			nvp = cookie;
+			level--;
+		}
+	}
 }
 
 void
@@ -381,41 +440,51 @@ nvlist_fdump(const nvlist_t *nvl, FILE *
 
 /*
  * The function obtains size of the nvlist after nvlist_pack().
- * Additional argument 'level' allows to track how deep are we as we obtain
- * size of the NV_TYPE_NVLIST elements using recursion. We allow at most
- * three levels of recursion.
  */
-static size_t
-nvlist_xsize(const nvlist_t *nvl, int level)
+size_t
+nvlist_size(const nvlist_t *nvl)
 {
-	const nvpair_t *nvp;
+	const nvlist_t *tmpnvl;
+	const nvpair_t *nvp, *tmpnvp;
+	void *cookie;
 	size_t size;
 
 	NVLIST_ASSERT(nvl);
 	PJDLOG_ASSERT(nvl->nvl_error == 0);
-	PJDLOG_ASSERT(level < 3);
 
 	size = sizeof(struct nvlist_header);
-	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
-	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+	nvp = nvlist_first_nvpair(nvl);
+	while (nvp != NULL) {
 		size += nvpair_header_size();
 		size += strlen(nvpair_name(nvp)) + 1;
-		if (nvpair_type(nvp) == NV_TYPE_NVLIST)
-			size += nvlist_xsize(nvpair_get_nvlist(nvp), level + 1);
-		else
+		if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
+			size += sizeof(struct nvlist_header);
+			size += nvpair_header_size() + 1;
+			tmpnvl = nvpair_get_nvlist(nvp);
+			PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
+			tmpnvp = nvlist_first_nvpair(tmpnvl);
+			if (tmpnvp != NULL) {
+				nvl = tmpnvl;
+				nvp = tmpnvp;
+				continue;
+			}
+		} else {
 			size += nvpair_size(nvp);
+		}
+
+		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
+			cookie = NULL;
+			nvl = nvlist_get_parent(nvl, &cookie);
+			if (nvl == NULL)
+				goto out;
+			nvp = cookie;
+		}
 	}
 
+out:
 	return (size);
 }
 
-size_t
-nvlist_size(const nvlist_t *nvl)
-{
-
-	return (nvlist_xsize(nvl, 0));
-}
-
 static int *
 nvlist_xdescriptors(const nvlist_t *nvl, int *descs, int level)
 {
@@ -522,7 +591,9 @@ nvlist_xpack(const nvlist_t *nvl, int64_
 {
 	unsigned char *buf, *ptr;
 	size_t left, size;
-	nvpair_t *nvp;
+	const nvlist_t *tmpnvl;
+	nvpair_t *nvp, *tmpnvp;
+	void *cookie;
 
 	NVLIST_ASSERT(nvl);
 
@@ -541,15 +612,68 @@ nvlist_xpack(const nvlist_t *nvl, int64_
 
 	ptr = nvlist_pack_header(nvl, ptr, &left);
 
-	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
-	    nvp = nvlist_next_nvpair(nvl, nvp)) {
-		ptr = nvpair_pack(nvp, ptr, fdidxp, &left);
+	nvp = nvlist_first_nvpair(nvl);
+	while (nvp != NULL) {
+		NVPAIR_ASSERT(nvp);
+
+		nvpair_init_datasize(nvp);
+		ptr = nvpair_pack_header(nvp, ptr, &left);
 		if (ptr == NULL) {
 			free(buf);
 			return (NULL);
 		}
+		switch (nvpair_type(nvp)) {
+		case NV_TYPE_NULL:
+			ptr = nvpair_pack_null(nvp, ptr, &left);
+			break;
+		case NV_TYPE_BOOL:
+			ptr = nvpair_pack_bool(nvp, ptr, &left);
+			break;
+		case NV_TYPE_NUMBER:
+			ptr = nvpair_pack_number(nvp, ptr, &left);
+			break;
+		case NV_TYPE_STRING:
+			ptr = nvpair_pack_string(nvp, ptr, &left);
+			break;
+		case NV_TYPE_NVLIST:
+			tmpnvl = nvpair_get_nvlist(nvp);
+			ptr = nvlist_pack_header(tmpnvl, ptr, &left);
+			if (ptr == NULL)
+				goto out;
+			tmpnvp = nvlist_first_nvpair(tmpnvl);
+			if (tmpnvp != NULL) {
+				nvl = tmpnvl;
+				nvp = tmpnvp;
+				continue;
+			}
+			ptr = nvpair_pack_nvlist_up(ptr, &left);
+			break;
+		case NV_TYPE_DESCRIPTOR:
+			ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
+			break;
+		case NV_TYPE_BINARY:
+			ptr = nvpair_pack_binary(nvp, ptr, &left);
+			break;
+		default:
+			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
+		}
+		if (ptr == NULL) {
+			free(buf);
+			return (NULL);
+		}
+		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
+			cookie = NULL;
+			nvl = nvlist_get_parent(nvl, &cookie);
+			if (nvl == NULL)
+				goto out;
+			nvp = cookie;
+			ptr = nvpair_pack_nvlist_up(ptr, &left);
+			if (ptr == NULL)
+				goto out;
+		}
 	}
 
+out:
 	if (sizep != NULL)
 		*sizep = size;
 	return (buf);
@@ -600,9 +724,9 @@ nvlist_check_header(struct nvlist_header
 	return (true);
 }
 
-static const unsigned char *
+const unsigned char *
 nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
-    int *flagsp, size_t *leftp)
+    bool *isbep, size_t *leftp)
 {
 	struct nvlist_header nvlhdr;
 
@@ -629,7 +753,8 @@ nvlist_unpack_header(nvlist_t *nvl, cons
 	nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK);
 
 	ptr += sizeof(nvlhdr);
-	*flagsp = (int)nvlhdr.nvlh_flags;
+	if (isbep != NULL)
+		*isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
 	*leftp -= sizeof(nvlhdr);
 
 	return (ptr);
@@ -642,32 +767,72 @@ nvlist_t *
 nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
 {
 	const unsigned char *ptr;
-	nvlist_t *nvl;
+	nvlist_t *nvl, *retnvl, *tmpnvl;
 	nvpair_t *nvp;
 	size_t left;
-	int flags;
+	bool isbe;
 
 	left = size;
 	ptr = buf;
 
-	nvl = nvlist_create(0);
+	tmpnvl = NULL;
+	nvl = retnvl = nvlist_create(0);
 	if (nvl == NULL)
 		goto failed;
 
-	ptr = nvlist_unpack_header(nvl, ptr, nfds, &flags, &left);
+	ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
 	if (ptr == NULL)
 		goto failed;
 
 	while (left > 0) {
-		ptr = nvpair_unpack(flags, ptr, &left, fds, nfds, &nvp);
+		ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
+		if (ptr == NULL)
+			goto failed;
+		switch (nvpair_type(nvp)) {
+		case NV_TYPE_NULL:
+			ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
+			break;
+		case NV_TYPE_BOOL:
+			ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
+			break;
+		case NV_TYPE_NUMBER:
+			ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
+			break;
+		case NV_TYPE_STRING:
+			ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
+			break;
+		case NV_TYPE_NVLIST:
+			ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
+			    &tmpnvl);
+			nvlist_set_parent(tmpnvl, nvp);
+			break;
+		case NV_TYPE_DESCRIPTOR:
+			ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
+			    fds, nfds);
+			break;
+		case NV_TYPE_BINARY:
+			ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
+			break;
+		case NV_TYPE_NVLIST_UP:
+			if (nvl->nvl_parent == NULL)
+				goto failed;
+			nvl = nvpair_nvlist(nvl->nvl_parent);
+			continue;
+		default:
+			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
+		}
 		if (ptr == NULL)
 			goto failed;
 		nvlist_move_nvpair(nvl, nvp);
+		if (tmpnvl != NULL) {
+			nvl = tmpnvl;
+			tmpnvl = NULL;
+		}
 	}
 
-	return (nvl);
+	return (retnvl);
 failed:
-	nvlist_destroy(nvl);
+	nvlist_destroy(retnvl);
 	return (NULL);
 }
 
@@ -1328,7 +1493,8 @@ nvlist_movev_nvlist(nvlist_t *nvl, nvlis
 	nvpair_t *nvp;
 
 	if (nvlist_error(nvl) != 0) {
-		nvlist_destroy(value);
+		if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
+			nvlist_destroy(value);
 		errno = nvlist_error(nvl);
 		return;
 	}

Modified: user/ngie/stable-10-libnv/lib/libnv/nvlist_impl.h
==============================================================================
--- user/ngie/stable-10-libnv/lib/libnv/nvlist_impl.h	Tue Dec 22 23:02:12 2015	(r292631)
+++ user/ngie/stable-10-libnv/lib/libnv/nvlist_impl.h	Tue Dec 22 23:05:43 2015	(r292632)
@@ -40,4 +40,8 @@ void *nvlist_xpack(const nvlist_t *nvl, 
 nvlist_t *nvlist_xunpack(const void *buf, size_t size, const int *fds,
     size_t nfds);
 
+nvpair_t *nvlist_get_nvpair_parent(const nvlist_t *nvl);
+const unsigned char *nvlist_unpack_header(nvlist_t *nvl,
+    const unsigned char *ptr, size_t nfds, bool *isbep, size_t *leftp);
+
 #endif	/* !_NVLIST_IMPL_H_ */

Modified: user/ngie/stable-10-libnv/lib/libnv/nvpair.c
==============================================================================
--- user/ngie/stable-10-libnv/lib/libnv/nvpair.c	Tue Dec 22 23:02:12 2015	(r292631)
+++ user/ngie/stable-10-libnv/lib/libnv/nvpair.c	Tue Dec 22 23:05:43 2015	(r292632)
@@ -67,7 +67,7 @@ struct nvpair {
 	int		 nvp_type;
 	uint64_t	 nvp_data;
 	size_t		 nvp_datasize;
-	nvlist_t	*nvp_list;	/* Used for sanity checks. */
+	nvlist_t	*nvp_list;
 	TAILQ_ENTRY(nvpair) nvp_next;
 };
 
@@ -90,7 +90,7 @@ nvpair_assert(const nvpair_t *nvp)
 	NVPAIR_ASSERT(nvp);
 }
 
-const nvlist_t *
+nvlist_t *
 nvpair_nvlist(const nvpair_t *nvp)
 {
 
@@ -131,6 +131,17 @@ nvpair_insert(struct nvl_head *head, nvp
 	nvp->nvp_list = nvl;
 }
 
+static void
+nvpair_remove_nvlist(nvpair_t *nvp)
+{
+	nvlist_t *nvl;
+
+	/* XXX: DECONST is bad, mkay? */
+	nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp));
+	PJDLOG_ASSERT(nvl != NULL);
+	nvlist_set_parent(nvl, NULL);
+}
+
 void
 nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
 {
@@ -138,6 +149,9 @@ nvpair_remove(struct nvl_head *head, nvp
 	NVPAIR_ASSERT(nvp);
 	PJDLOG_ASSERT(nvp->nvp_list == nvl);
 
+	if (nvpair_type(nvp) == NV_TYPE_NVLIST)
+		nvpair_remove_nvlist(nvp);
+
 	TAILQ_REMOVE(head, nvp, nvp_next);
 	nvp->nvp_list = NULL;
 }
@@ -201,7 +215,7 @@ nvpair_size(const nvpair_t *nvp)
 	return (nvp->nvp_datasize);
 }
 
-static unsigned char *
+unsigned char *
 nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
 {
 	struct nvpair_header nvphdr;
@@ -227,7 +241,7 @@ nvpair_pack_header(const nvpair_t *nvp, 
 	return (ptr);
 }
 
-static unsigned char *
+unsigned char *
 nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
     size_t *leftp __unused)
 {
@@ -238,7 +252,7 @@ nvpair_pack_null(const nvpair_t *nvp, un
 	return (ptr);
 }
 
-static unsigned char *
+unsigned char *
 nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
 {
 	uint8_t value;
@@ -256,7 +270,7 @@ nvpair_pack_bool(const nvpair_t *nvp, un
 	return (ptr);
 }
 
-static unsigned char *
+unsigned char *
 nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
 {
 	uint64_t value;
@@ -274,7 +288,7 @@ nvpair_pack_number(const nvpair_t *nvp, 
 	return (ptr);
 }
 
-static unsigned char *
+unsigned char *
 nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
 {
 
@@ -289,37 +303,31 @@ nvpair_pack_string(const nvpair_t *nvp, 
 	return (ptr);
 }
 
-static unsigned char *
-nvpair_pack_nvlist(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
-    size_t *leftp)
+unsigned char *
+nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp)
 {
-	unsigned char *data;
-	size_t size;
-
-	NVPAIR_ASSERT(nvp);
-	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
-
-	if (nvp->nvp_datasize == 0)
-		return (ptr);
-
-	data = nvlist_xpack((const nvlist_t *)(intptr_t)nvp->nvp_data, fdidxp,
-	    &size);
-	if (data == NULL)
-		return (NULL);
-
-	PJDLOG_ASSERT(size == nvp->nvp_datasize);
-	PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+	struct nvpair_header nvphdr;
+	size_t namesize;
+	const char *name = "";
 
-	memcpy(ptr, data, nvp->nvp_datasize);
-	free(data);
+	namesize = 1;
+	nvphdr.nvph_type = NV_TYPE_NVLIST_UP;
+	nvphdr.nvph_namesize = namesize;
+	nvphdr.nvph_datasize = 0;
+	PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
+	memcpy(ptr, &nvphdr, sizeof(nvphdr));
+	ptr += sizeof(nvphdr);
+	*leftp -= sizeof(nvphdr);
 
-	ptr += nvp->nvp_datasize;
-	*leftp -= nvp->nvp_datasize;
+	PJDLOG_ASSERT(*leftp >= namesize);
+	memcpy(ptr, name, namesize);
+	ptr += namesize;
+	*leftp -= namesize;
 
 	return (ptr);
 }
 
-static unsigned char *
+unsigned char *
 nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
     size_t *leftp)
 {
@@ -349,7 +357,7 @@ nvpair_pack_descriptor(const nvpair_t *n
 	return (ptr);
 }
 
-static unsigned char *
+unsigned char *
 nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
 {
 
@@ -364,17 +372,12 @@ nvpair_pack_binary(const nvpair_t *nvp, 
 	return (ptr);
 }
 
-unsigned char *
-nvpair_pack(nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp, size_t *leftp)
+void
+nvpair_init_datasize(nvpair_t *nvp)
 {
 
 	NVPAIR_ASSERT(nvp);
 
-	/*
-	 * We have to update datasize for NV_TYPE_NVLIST on every pack,
-	 * so that proper datasize is placed into nvpair_header
-	 * during the nvpair_pack_header() call below.
-	 */
 	if (nvp->nvp_type == NV_TYPE_NVLIST) {
 		if (nvp->nvp_data == 0) {
 			nvp->nvp_datasize = 0;
@@ -383,42 +386,10 @@ nvpair_pack(nvpair_t *nvp, unsigned char
 			    nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
 		}
 	}
-
-	ptr = nvpair_pack_header(nvp, ptr, leftp);
-	if (ptr == NULL)
-		return (NULL);
-
-	switch (nvp->nvp_type) {
-	case NV_TYPE_NULL:
-		ptr = nvpair_pack_null(nvp, ptr, leftp);
-		break;
-	case NV_TYPE_BOOL:
-		ptr = nvpair_pack_bool(nvp, ptr, leftp);
-		break;
-	case NV_TYPE_NUMBER:
-		ptr = nvpair_pack_number(nvp, ptr, leftp);
-		break;
-	case NV_TYPE_STRING:
-		ptr = nvpair_pack_string(nvp, ptr, leftp);
-		break;
-	case NV_TYPE_NVLIST:
-		ptr = nvpair_pack_nvlist(nvp, ptr, fdidxp, leftp);
-		break;
-	case NV_TYPE_DESCRIPTOR:
-		ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, leftp);
-		break;
-	case NV_TYPE_BINARY:
-		ptr = nvpair_pack_binary(nvp, ptr, leftp);
-		break;
-	default:
-		PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type);
-	}
-
-	return (ptr);
 }
 
-static const unsigned char *
-nvpair_unpack_header(int flags, nvpair_t *nvp, const unsigned char *ptr,
+const unsigned char *
+nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
     size_t *leftp)
 {
 	struct nvpair_header nvphdr;
@@ -434,16 +405,18 @@ nvpair_unpack_header(int flags, nvpair_t
 	if (nvphdr.nvph_type < NV_TYPE_FIRST)
 		goto failed;
 #endif
-	if (nvphdr.nvph_type > NV_TYPE_LAST)
+	if (nvphdr.nvph_type > NV_TYPE_LAST &&
+	    nvphdr.nvph_type != NV_TYPE_NVLIST_UP) {
 		goto failed;
+	}
 
 #if BYTE_ORDER == BIG_ENDIAN
-	if ((flags & NV_FLAG_BIG_ENDIAN) == 0) {
+	if (!isbe) {
 		nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
 		nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
 	}
 #else
-	if ((flags & NV_FLAG_BIG_ENDIAN) != 0) {
+	if (isbe) {
 		nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
 		nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
 	}
@@ -477,8 +450,8 @@ failed:
 	return (NULL);
 }
 
-static const unsigned char *
-nvpair_unpack_null(int flags __unused, nvpair_t *nvp, const unsigned char *ptr,
+const unsigned char *
+nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
     size_t *leftp __unused)
 {
 

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201512222305.tBMN5hSd088581>