From owner-svn-src-user@freebsd.org Tue Dec 22 23:05:45 2015 Return-Path: Delivered-To: svn-src-user@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 219A2A4F259 for ; Tue, 22 Dec 2015 23:05:45 +0000 (UTC) (envelope-from ngie@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id C9542186C; Tue, 22 Dec 2015 23:05:44 +0000 (UTC) (envelope-from ngie@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tBMN5ifw088592; Tue, 22 Dec 2015 23:05:44 GMT (envelope-from ngie@FreeBSD.org) Received: (from ngie@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tBMN5hSd088581; Tue, 22 Dec 2015 23:05:43 GMT (envelope-from ngie@FreeBSD.org) Message-Id: <201512222305.tBMN5hSd088581@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ngie set sender to ngie@FreeBSD.org using -f From: Garrett Cooper Date: Tue, 22 Dec 2015 23:05:43 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r292632 - user/ngie/stable-10-libnv/lib/libnv X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 22 Dec 2015 23:05:45 -0000 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 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 r277925 (by pjd): Handle empty nvlists correctly. Submitted by: Mariusz Zaborski r277926 (by pjd): Add missing nvlist_get_parent(3) link. Submitted by: Mariusz Zaborski 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 __FBSDID("$FreeBSD$"); -#include +#include #include #include @@ -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 ***