--- old/usr/src/head/limits.h	Fri Feb 28 07:08:15 2020
+++ new/usr/src/head/limits.h	Fri Feb 28 07:08:15 2020
@@ -25,6 +25,7 @@
  *
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright 2015 Joyent, Inc.  All rights reserved.
  */
 
 /*	Copyright (c) 1988 AT&T	*/
@@ -37,6 +38,7 @@
 #include <sys/feature_tests.h>
 #include <sys/isa_defs.h>
 #include <iso/limits_iso.h>
+#include <sys/limits.h>
 
 /*
  * Include fixed width type limits as proposed by the ISO/JTC1/SC22/WG14 C
@@ -243,8 +245,6 @@
 #define	_XOPEN_NAME_MAX	255	/* max # bytes in filename excluding null */
 #define	_XOPEN_PATH_MAX	1024	/* max # bytes in a pathname */
 
-#define	IOV_MAX		_XOPEN_IOV_MAX
-
 #if defined(__EXTENSIONS__) || \
 	(!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX))
 
--- old/usr/src/lib/libbc/inc/include/sys/socket.h	Fri Feb 28 07:08:15 2020
+++ new/usr/src/lib/libbc/inc/include/sys/socket.h	Fri Feb 28 07:08:15 2020
@@ -3,8 +3,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Copyright (c) 1982, 1985, 1986 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
@@ -169,6 +167,4 @@
 #define	MSG_PEEK	0x2		/* peek at incoming message */
 #define	MSG_DONTROUTE	0x4		/* send without using routing tables */
 
-#define	MSG_MAXIOVLEN	16
-
 #endif /*!_sys_socket_h*/
--- old/usr/src/pkg/manifests/system-header.mf	Fri Feb 28 07:08:15 2020
+++ new/usr/src/pkg/manifests/system-header.mf	Fri Feb 28 07:08:15 2020
@@ -26,7 +26,7 @@
 # Copyright 2014 Garrett D'Amore <garrett@damore.org>
 # Copyright 2018 Nexenta Systems, Inc.
 # Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
-# Copyright 2019 Joyent, Inc.
+# Copyright 2020 Joyent, Inc.
 # Copyright 2019 Peter Tribble.
 #
 
@@ -1169,6 +1169,7 @@
 file path=usr/include/sys/ldterm.h
 file path=usr/include/sys/lgrp.h
 file path=usr/include/sys/lgrp_user.h
+file path=usr/include/sys/limits.h
 file path=usr/include/sys/link.h
 file path=usr/include/sys/linker_set.h
 file path=usr/include/sys/list.h
--- old/usr/src/uts/common/fs/sockfs/socksubr.c	Fri Feb 28 07:08:15 2020
+++ new/usr/src/uts/common/fs/sockfs/socksubr.c	Fri Feb 28 07:08:15 2020
@@ -23,6 +23,7 @@
  * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2015, Joyent, Inc. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -1887,7 +1888,7 @@
 soreadfile(file_t *fp, uchar_t *buf, u_offset_t fileoff, int *err, size_t size)
 {
 	struct uio auio;
-	struct iovec aiov[MSG_MAXIOVLEN];
+	struct iovec aiov[1];
 	register vnode_t *vp;
 	int ioflag, rwflag;
 	ssize_t cnt;
--- old/usr/src/uts/common/fs/sockfs/socksyscalls.c	Fri Feb 28 07:08:15 2020
+++ new/usr/src/uts/common/fs/sockfs/socksyscalls.c	Fri Feb 28 07:08:15 2020
@@ -21,10 +21,8 @@
 
 /*
  * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-/* Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. */
-/*
+ * Copyright 2015, Joyent, Inc.  All rights reserved.
+ * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  */
 
@@ -54,6 +52,7 @@
 #include <sys/cmn_err.h>
 #include <sys/vmsystm.h>
 #include <sys/policy.h>
+#include <sys/limits.h>
 
 #include <sys/socket.h>
 #include <sys/socketvar.h>
@@ -86,12 +85,6 @@
 extern int	sockfs_defer_nl7c_init;
 
 /*
- * Note: DEF_IOV_MAX is defined and used as it is in "fs/vncalls.c"
- *	 as there isn't a formal definition of IOV_MAX ???
- */
-#define	MSG_MAXIOVLEN	16
-
-/*
  * Kernel component of socket creation.
  *
  * The socket library determines which version number to use.
@@ -1021,9 +1014,10 @@
 	STRUCT_HANDLE(nmsghdr, umsgptr);
 	struct nmsghdr lmsg;
 	struct uio auio;
-	struct iovec aiov[MSG_MAXIOVLEN];
+	struct iovec buf[IOV_MAX_STACK], *aiov = buf;
+	ssize_t iovsize = 0;
 	int iovcnt;
-	ssize_t len;
+	ssize_t len, rval;
 	int i;
 	int *flagsp;
 	model_t	model;
@@ -1066,10 +1060,15 @@
 
 	iovcnt = lmsg.msg_iovlen;
 
-	if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
+	if (iovcnt <= 0 || iovcnt > IOV_MAX) {
 		return (set_errno(EMSGSIZE));
 	}
 
+	if (iovcnt > IOV_MAX_STACK) {
+		iovsize = iovcnt * sizeof (struct iovec);
+		aiov = kmem_alloc(iovsize, KM_SLEEP);
+	}
+
 #ifdef _SYSCALL32_IMPL
 	/*
 	 * 32-bit callers need to have their iovec expanded, while ensuring
@@ -1076,12 +1075,22 @@
 	 * that they can't move more than 2Gbytes of data in a single call.
 	 */
 	if (model == DATAMODEL_ILP32) {
-		struct iovec32 aiov32[MSG_MAXIOVLEN];
+		struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
+		ssize_t iov32size;
 		ssize32_t count32;
 
-		if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
-		    iovcnt * sizeof (struct iovec32)))
+		iov32size = iovcnt * sizeof (struct iovec32);
+		if (iovsize != 0)
+			aiov32 = kmem_alloc(iov32size, KM_SLEEP);
+
+		if (copyin((struct iovec32 *)lmsg.msg_iov, aiov32, iov32size)) {
+			if (iovsize != 0) {
+				kmem_free(aiov32, iov32size);
+				kmem_free(aiov, iovsize);
+			}
+
 			return (set_errno(EFAULT));
+		}
 
 		count32 = 0;
 		for (i = 0; i < iovcnt; i++) {
@@ -1089,15 +1098,28 @@
 
 			iovlen32 = aiov32[i].iov_len;
 			count32 += iovlen32;
-			if (iovlen32 < 0 || count32 < 0)
+			if (iovlen32 < 0 || count32 < 0) {
+				if (iovsize != 0) {
+					kmem_free(aiov32, iov32size);
+					kmem_free(aiov, iovsize);
+				}
+
 				return (set_errno(EINVAL));
+			}
+
 			aiov[i].iov_len = iovlen32;
 			aiov[i].iov_base =
 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
 		}
+
+		if (iovsize != 0)
+			kmem_free(aiov32, iov32size);
 	} else
 #endif /* _SYSCALL32_IMPL */
 	if (copyin(lmsg.msg_iov, aiov, iovcnt * sizeof (struct iovec))) {
+		if (iovsize != 0)
+			kmem_free(aiov, iovsize);
+
 		return (set_errno(EFAULT));
 	}
 	len = 0;
@@ -1105,6 +1127,9 @@
 		ssize_t iovlen = aiov[i].iov_len;
 		len += iovlen;
 		if (iovlen < 0 || len < 0) {
+			if (iovsize != 0)
+				kmem_free(aiov, iovsize);
+
 			return (set_errno(EINVAL));
 		}
 	}
@@ -1119,12 +1144,20 @@
 	    (do_useracc == 0 ||
 	    useracc(lmsg.msg_control, lmsg.msg_controllen,
 	    B_WRITE) != 0)) {
+		if (iovsize != 0)
+			kmem_free(aiov, iovsize);
+
 		return (set_errno(EFAULT));
 	}
 
-	return (recvit(sock, &lmsg, &auio, flags,
+	rval = recvit(sock, &lmsg, &auio, flags,
 	    STRUCT_FADDR(umsgptr, msg_namelen),
-	    STRUCT_FADDR(umsgptr, msg_controllen), flagsp));
+	    STRUCT_FADDR(umsgptr, msg_controllen), flagsp);
+
+	if (iovsize != 0)
+		kmem_free(aiov, iovsize);
+
+	return (rval);
 }
 
 /*
@@ -1262,9 +1295,10 @@
 	struct nmsghdr lmsg;
 	STRUCT_DECL(nmsghdr, u_lmsg);
 	struct uio auio;
-	struct iovec aiov[MSG_MAXIOVLEN];
+	struct iovec buf[IOV_MAX_STACK], *aiov = buf;
+	ssize_t iovsize = 0;
 	int iovcnt;
-	ssize_t len;
+	ssize_t len, rval;
 	int i;
 	model_t	model;
 
@@ -1307,7 +1341,7 @@
 
 	iovcnt = lmsg.msg_iovlen;
 
-	if (iovcnt <= 0 || iovcnt > MSG_MAXIOVLEN) {
+	if (iovcnt <= 0 || iovcnt > IOV_MAX) {
 		/*
 		 * Unless this is XPG 4.2 we allow iovcnt == 0 to
 		 * be compatible with SunOS 4.X and 4.4BSD.
@@ -1316,6 +1350,11 @@
 			return (set_errno(EMSGSIZE));
 	}
 
+	if (iovcnt > IOV_MAX_STACK) {
+		iovsize = iovcnt * sizeof (struct iovec);
+		aiov = kmem_alloc(iovsize, KM_SLEEP);
+	}
+
 #ifdef _SYSCALL32_IMPL
 	/*
 	 * 32-bit callers need to have their iovec expanded, while ensuring
@@ -1322,13 +1361,23 @@
 	 * that they can't move more than 2Gbytes of data in a single call.
 	 */
 	if (model == DATAMODEL_ILP32) {
-		struct iovec32 aiov32[MSG_MAXIOVLEN];
+		struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
+		ssize_t iov32size;
 		ssize32_t count32;
 
+		iov32size = iovcnt * sizeof (struct iovec32);
+		if (iovsize != 0)
+			aiov32 = kmem_alloc(iov32size, KM_SLEEP);
+
 		if (iovcnt != 0 &&
-		    copyin((struct iovec32 *)lmsg.msg_iov, aiov32,
-		    iovcnt * sizeof (struct iovec32)))
+		    copyin((struct iovec32 *)lmsg.msg_iov, aiov32, iov32size)) {
+			if (iovsize != 0) {
+				kmem_free(aiov32, iov32size);
+				kmem_free(aiov, iovsize);
+			}
+
 			return (set_errno(EFAULT));
+		}
 
 		count32 = 0;
 		for (i = 0; i < iovcnt; i++) {
@@ -1336,17 +1385,30 @@
 
 			iovlen32 = aiov32[i].iov_len;
 			count32 += iovlen32;
-			if (iovlen32 < 0 || count32 < 0)
+			if (iovlen32 < 0 || count32 < 0) {
+				if (iovsize != 0) {
+					kmem_free(aiov32, iov32size);
+					kmem_free(aiov, iovsize);
+				}
+
 				return (set_errno(EINVAL));
+			}
+
 			aiov[i].iov_len = iovlen32;
 			aiov[i].iov_base =
 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
 		}
+
+		if (iovsize != 0)
+			kmem_free(aiov32, iov32size);
 	} else
 #endif /* _SYSCALL32_IMPL */
 	if (iovcnt != 0 &&
 	    copyin(lmsg.msg_iov, aiov,
 	    (unsigned)iovcnt * sizeof (struct iovec))) {
+		if (iovsize != 0)
+			kmem_free(aiov, iovsize);
+
 		return (set_errno(EFAULT));
 	}
 	len = 0;
@@ -1354,6 +1416,9 @@
 		ssize_t iovlen = aiov[i].iov_len;
 		len += iovlen;
 		if (iovlen < 0 || len < 0) {
+			if (iovsize != 0)
+				kmem_free(aiov, iovsize);
+
 			return (set_errno(EINVAL));
 		}
 	}
@@ -1364,7 +1429,12 @@
 	auio.uio_segflg = UIO_USERSPACE;
 	auio.uio_limit = 0;
 
-	return (sendit(sock, &lmsg, &auio, flags));
+	rval = sendit(sock, &lmsg, &auio, flags);
+
+	if (iovsize != 0)
+		kmem_free(aiov, iovsize);
+
+	return (rval);
 }
 
 ssize_t
--- old/usr/src/uts/common/io/cons.c	Fri Feb 28 07:08:15 2020
+++ new/usr/src/uts/common/io/cons.c	Fri Feb 28 07:08:15 2020
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 1982, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc. All rights reserved.
  */
 
 /*
@@ -53,6 +54,7 @@
 #include <sys/vnode.h>
 #include <sys/uio.h>
 #include <sys/stat.h>
+#include <sys/limits.h>
 
 #include <sys/console.h>
 #include <sys/consdev.h>
@@ -414,14 +416,24 @@
 	 */
 	if (vsconsvp != NULL && vsconsvp->v_stream != NULL) {
 		struiod_t uiod;
+		struct iovec buf[IOV_MAX_STACK];
+		int iovlen = 0;
 
+		if (uio->uio_iovcnt > IOV_MAX_STACK) {
+			iovlen = uio->uio_iovcnt * sizeof (iovec_t);
+			uiod.d_iov = kmem_alloc(iovlen, KM_SLEEP);
+		} else {
+			uiod.d_iov = buf;
+		}
+
 		/*
 		 * strwrite modifies uio so need to make copy.
 		 */
-		(void) uiodup(uio, &uiod.d_uio, uiod.d_iov,
-		    sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
+		(void) uiodup(uio, &uiod.d_uio, uiod.d_iov, uio->uio_iovcnt);
 
 		(void) strwrite(vsconsvp, &uiod.d_uio, cred);
+		if (iovlen != 0)
+			kmem_free(uiod.d_iov, iovlen);
 	}
 
 	if (rconsvp->v_stream != NULL)
--- old/usr/src/uts/common/os/streamio.c	Fri Feb 28 07:08:15 2020
+++ new/usr/src/uts/common/os/streamio.c	Fri Feb 28 07:08:15 2020
@@ -78,6 +78,7 @@
 #include <sys/policy.h>
 #include <sys/dld.h>
 #include <sys/zone.h>
+#include <sys/limits.h>
 #include <c2/audit.h>
 
 /*
@@ -987,12 +988,20 @@
 		 * (registered in sd_wakeq).
 		 */
 		struiod_t uiod;
+		struct iovec buf[IOV_MAX_STACK];
+		int iovlen = 0;
 
 		if (first)
 			stp->sd_wakeq &= ~RSLEEP;
 
-		(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov,
-		    sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
+		if (uiop->uio_iovcnt > IOV_MAX_STACK) {
+			iovlen = uiop->uio_iovcnt * sizeof (iovec_t);
+			uiod.d_iov = kmem_alloc(iovlen, KM_SLEEP);
+		} else {
+			uiod.d_iov = buf;
+		}
+
+		(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov, uiop->uio_iovcnt);
 		uiod.d_mp = 0;
 		/*
 		 * Mark that a thread is in rwnext on the read side
@@ -1031,6 +1040,8 @@
 			if ((bp = uiod.d_mp) != NULL) {
 				*errorp = 0;
 				ASSERT(MUTEX_HELD(&stp->sd_lock));
+				if (iovlen != 0)
+					kmem_free(uiod.d_iov, iovlen);
 				return (bp);
 			}
 			error = 0;
@@ -1050,8 +1061,14 @@
 		} else {
 			*errorp = error;
 			ASSERT(MUTEX_HELD(&stp->sd_lock));
+			if (iovlen != 0)
+				kmem_free(uiod.d_iov, iovlen);
 			return (NULL);
 		}
+
+		if (iovlen != 0)
+			kmem_free(uiod.d_iov, iovlen);
+
 		/*
 		 * Try a getq in case a rwnext() generated mblk
 		 * has bubbled up via strrput().
@@ -2546,6 +2563,8 @@
     int b_flag, int pri, int flags)
 {
 	struiod_t uiod;
+	struct iovec buf[IOV_MAX_STACK];
+	int iovlen = 0;
 	mblk_t *mp;
 	queue_t *wqp = stp->sd_wrq;
 	int error = 0;
@@ -2637,13 +2656,21 @@
 	mp->b_flag |= b_flag;
 	mp->b_band = (uchar_t)pri;
 
-	(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov,
-	    sizeof (uiod.d_iov) / sizeof (*uiod.d_iov));
+	if (uiop->uio_iovcnt > IOV_MAX_STACK) {
+		iovlen = uiop->uio_iovcnt * sizeof (iovec_t);
+		uiod.d_iov = (struct iovec *)kmem_alloc(iovlen, KM_SLEEP);
+	} else {
+		uiod.d_iov = buf;
+	}
+
+	(void) uiodup(uiop, &uiod.d_uio, uiod.d_iov, uiop->uio_iovcnt);
 	uiod.d_uio.uio_offset = 0;
 	uiod.d_mp = mp;
 	error = rwnext(wqp, &uiod);
 	if (! uiod.d_mp) {
 		uioskip(uiop, *iosize);
+		if (iovlen != 0)
+			kmem_free(uiod.d_iov, iovlen);
 		return (error);
 	}
 	ASSERT(mp == uiod.d_mp);
@@ -2661,6 +2688,8 @@
 		error = 0;
 	} else {
 		freemsg(mp);
+		if (iovlen != 0)
+			kmem_free(uiod.d_iov, iovlen);
 		return (error);
 	}
 	/* Have to check canput before consuming data from the uio */
@@ -2667,11 +2696,15 @@
 	if (pri == 0) {
 		if (!canputnext(wqp) && !(flags & MSG_IGNFLOW)) {
 			freemsg(mp);
+			if (iovlen != 0)
+				kmem_free(uiod.d_iov, iovlen);
 			return (EWOULDBLOCK);
 		}
 	} else {
 		if (!bcanputnext(wqp, pri) && !(flags & MSG_IGNFLOW)) {
 			freemsg(mp);
+			if (iovlen != 0)
+				kmem_free(uiod.d_iov, iovlen);
 			return (EWOULDBLOCK);
 		}
 	}
@@ -2679,6 +2712,8 @@
 	/* Copyin data from the uio */
 	if ((error = struioget(wqp, mp, &uiod, 0)) != 0) {
 		freemsg(mp);
+		if (iovlen != 0)
+			kmem_free(uiod.d_iov, iovlen);
 		return (error);
 	}
 	uioskip(uiop, *iosize);
@@ -2695,6 +2730,8 @@
 		putnext(wqp, mp);
 		stream_runservice(stp);
 	}
+	if (iovlen != 0)
+		kmem_free(uiod.d_iov, iovlen);
 	return (0);
 }
 
--- old/usr/src/uts/common/sys/Makefile	Fri Feb 28 07:08:16 2020
+++ new/usr/src/uts/common/sys/Makefile	Fri Feb 28 07:08:16 2020
@@ -28,6 +28,7 @@
 # Copyright 2017 Nexenta Systems, Inc.
 # Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
 # Copyright 2019 Peter Tribble.
+# Copyright 2015, Joyent, Inc. All rights reserved.
 #
 
 include $(SRC)/uts/Makefile.uts
@@ -348,6 +349,7 @@
 	lgrp.h			\
 	lgrp_user.h		\
 	libc_kernel.h		\
+	limits.h		\
 	link.h			\
 	linker_set.h		\
 	list.h			\
--- /dev/null	Fri Feb 28 07:08:16 2020
+++ new/usr/src/uts/common/sys/limits.h	Fri Feb 28 07:08:16 2020
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright 2015 Joyent, Inc.  All rights reserved.
+ */
+
+#ifndef _SYS_LIMITS_H
+#define	_SYS_LIMITS_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define	IOV_MAX	1024
+
+#ifdef _KERNEL
+#define	IOV_MAX_STACK	16	/* max. IOV on-stack allocation */
+#endif /* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SYS_LIMITS_H */
--- old/usr/src/uts/common/sys/socket.h	Fri Feb 28 07:08:16 2020
+++ new/usr/src/uts/common/sys/socket.h	Fri Feb 28 07:08:16 2020
@@ -22,6 +22,7 @@
  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
  *
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc. All rights reserved.
  */
 
 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
@@ -429,6 +430,7 @@
 					/* with left over data */
 #define	MSG_XPG4_2	0x8000		/* Private: XPG4.2 flag */
 
+/* Obsolete but kept for compilation compatability. Use IOV_MAX. */
 #define	MSG_MAXIOVLEN	16
 
 #ifdef _KERNEL
--- old/usr/src/uts/common/sys/stream.h	Fri Feb 28 07:08:16 2020
+++ new/usr/src/uts/common/sys/stream.h	Fri Feb 28 07:08:16 2020
@@ -22,6 +22,7 @@
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2015 Joyent, Inc.  All rights reserved.
  */
 
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
@@ -644,16 +645,11 @@
 /*
  * Structure for rw (read/write) procedure calls. A pointer
  * to a struiod_t is passed as a parameter to the rwnext() call.
- *
- * Note: DEF_IOV_MAX is defined and used as it is in "fs/vncalls.c"
- *	 as there isn't a formal definition of IOV_MAX ???
  */
-#define	DEF_IOV_MAX	16
-
 struct struiod {
 	mblk_t		*d_mp;		/* pointer to mblk (chain) */
 	uio_t		d_uio;		/* uio info */
-	iovec_t d_iov[DEF_IOV_MAX];	/* iov referenced by uio */
+	iovec_t		*d_iov;		/* iov referenced by uio */
 };
 
 /*
--- old/usr/src/uts/common/syscall/rw.c	Fri Feb 28 07:08:16 2020
+++ new/usr/src/uts/common/syscall/rw.c	Fri Feb 28 07:08:16 2020
@@ -22,7 +22,7 @@
 /*
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
- * Copyright (c) 2015, Joyent, Inc.  All rights reserved.
+ * Copyright 2015, Joyent, Inc.  All rights reserved.
  */
 
 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
@@ -50,6 +50,7 @@
 #include <sys/debug.h>
 #include <sys/rctl.h>
 #include <sys/nbmlock.h>
+#include <sys/limits.h>
 
 #define	COPYOUT_MAX_CACHE	(1<<17)		/* 128K */
 
@@ -607,19 +608,12 @@
 	return (bcount);
 }
 
-/*
- * XXX -- The SVID refers to IOV_MAX, but doesn't define it.  Grrrr....
- * XXX -- However, SVVS expects readv() and writev() to fail if
- * XXX -- iovcnt > 16 (yes, it's hard-coded in the SVVS source),
- * XXX -- so I guess that's the "interface".
- */
-#define	DEF_IOV_MAX	16
-
 ssize_t
 readv(int fdes, struct iovec *iovp, int iovcnt)
 {
 	struct uio auio;
-	struct iovec aiov[DEF_IOV_MAX];
+	struct iovec buf[IOV_MAX_STACK], *aiov = buf;
+	int aiovlen = 0;
 	file_t *fp;
 	register vnode_t *vp;
 	struct cpu *cp;
@@ -630,9 +624,14 @@
 	u_offset_t fileoff;
 	int in_crit = 0;
 
-	if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX)
+	if (iovcnt <= 0 || iovcnt > IOV_MAX)
 		return (set_errno(EINVAL));
 
+	if (iovcnt > IOV_MAX_STACK) {
+		aiovlen = iovcnt * sizeof (iovec_t);
+		aiov = kmem_alloc(aiovlen, KM_SLEEP);
+	}
+
 #ifdef _SYSCALL32_IMPL
 	/*
 	 * 32-bit callers need to have their iovec expanded,
@@ -640,36 +639,63 @@
 	 * of data in a single call.
 	 */
 	if (get_udatamodel() == DATAMODEL_ILP32) {
-		struct iovec32 aiov32[DEF_IOV_MAX];
+		struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
+		int aiov32len;
 		ssize32_t count32;
 
-		if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32)))
+		aiov32len = iovcnt * sizeof (iovec32_t);
+		if (aiovlen != 0)
+			aiov32 = kmem_alloc(aiov32len, KM_SLEEP);
+
+		if (copyin(iovp, aiov32, aiov32len)) {
+			if (aiovlen != 0) {
+				kmem_free(aiov32, aiov32len);
+				kmem_free(aiov, aiovlen);
+			}
 			return (set_errno(EFAULT));
+		}
 
 		count32 = 0;
 		for (i = 0; i < iovcnt; i++) {
 			ssize32_t iovlen32 = aiov32[i].iov_len;
 			count32 += iovlen32;
-			if (iovlen32 < 0 || count32 < 0)
+			if (iovlen32 < 0 || count32 < 0) {
+				if (aiovlen != 0) {
+					kmem_free(aiov32, aiov32len);
+					kmem_free(aiov, aiovlen);
+				}
 				return (set_errno(EINVAL));
+			}
 			aiov[i].iov_len = iovlen32;
 			aiov[i].iov_base =
 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
 		}
+
+		if (aiovlen != 0)
+			kmem_free(aiov32, aiov32len);
 	} else
 #endif
-	if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec)))
+	if (copyin(iovp, aiov, iovcnt * sizeof (iovec_t))) {
+		if (aiovlen != 0)
+			kmem_free(aiov, aiovlen);
 		return (set_errno(EFAULT));
+	}
 
 	count = 0;
 	for (i = 0; i < iovcnt; i++) {
 		ssize_t iovlen = aiov[i].iov_len;
 		count += iovlen;
-		if (iovlen < 0 || count < 0)
+		if (iovlen < 0 || count < 0) {
+			if (aiovlen != 0)
+				kmem_free(aiov, aiovlen);
 			return (set_errno(EINVAL));
+		}
 	}
-	if ((fp = getf(fdes)) == NULL)
+	if ((fp = getf(fdes)) == NULL) {
+		if (aiovlen != 0)
+			kmem_free(aiov, aiovlen);
 		return (set_errno(EBADF));
+	}
 	if (((fflag = fp->f_flag) & FREAD) == 0) {
 		error = EBADF;
 		goto out;
@@ -768,6 +794,8 @@
 	if (in_crit)
 		nbl_end_crit(vp);
 	releasef(fdes);
+	if (aiovlen != 0)
+		kmem_free(aiov, aiovlen);
 	if (error)
 		return (set_errno(error));
 	return (count);
@@ -777,7 +805,8 @@
 writev(int fdes, struct iovec *iovp, int iovcnt)
 {
 	struct uio auio;
-	struct iovec aiov[DEF_IOV_MAX];
+	struct iovec buf[IOV_MAX_STACK], *aiov = buf;
+	int aiovlen = 0;
 	file_t *fp;
 	register vnode_t *vp;
 	struct cpu *cp;
@@ -788,9 +817,14 @@
 	u_offset_t fileoff;
 	int in_crit = 0;
 
-	if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX)
+	if (iovcnt <= 0 || iovcnt > IOV_MAX)
 		return (set_errno(EINVAL));
 
+	if (iovcnt > IOV_MAX_STACK) {
+		aiovlen = iovcnt * sizeof (iovec_t);
+		aiov = kmem_alloc(aiovlen, KM_SLEEP);
+	}
+
 #ifdef _SYSCALL32_IMPL
 	/*
 	 * 32-bit callers need to have their iovec expanded,
@@ -798,36 +832,62 @@
 	 * of data in a single call.
 	 */
 	if (get_udatamodel() == DATAMODEL_ILP32) {
-		struct iovec32 aiov32[DEF_IOV_MAX];
+		struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
+		int aiov32len;
 		ssize32_t count32;
 
-		if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32)))
+		aiov32len = iovcnt * sizeof (iovec32_t);
+		if (aiovlen != 0)
+			aiov32 = kmem_alloc(aiov32len, KM_SLEEP);
+
+		if (copyin(iovp, aiov32, aiov32len)) {
+			if (aiovlen != 0) {
+				kmem_free(aiov32, aiov32len);
+				kmem_free(aiov, aiovlen);
+			}
 			return (set_errno(EFAULT));
+		}
 
 		count32 = 0;
 		for (i = 0; i < iovcnt; i++) {
 			ssize32_t iovlen = aiov32[i].iov_len;
 			count32 += iovlen;
-			if (iovlen < 0 || count32 < 0)
+			if (iovlen < 0 || count32 < 0) {
+				if (aiovlen != 0) {
+					kmem_free(aiov32, aiov32len);
+					kmem_free(aiov, aiovlen);
+				}
 				return (set_errno(EINVAL));
+			}
 			aiov[i].iov_len = iovlen;
 			aiov[i].iov_base =
 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
 		}
+		if (aiovlen != 0)
+			kmem_free(aiov32, aiov32len);
 	} else
 #endif
-	if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec)))
+	if (copyin(iovp, aiov, iovcnt * sizeof (iovec_t))) {
+		if (aiovlen != 0)
+			kmem_free(aiov, aiovlen);
 		return (set_errno(EFAULT));
+	}
 
 	count = 0;
 	for (i = 0; i < iovcnt; i++) {
 		ssize_t iovlen = aiov[i].iov_len;
 		count += iovlen;
-		if (iovlen < 0 || count < 0)
+		if (iovlen < 0 || count < 0) {
+			if (aiovlen != 0)
+				kmem_free(aiov, aiovlen);
 			return (set_errno(EINVAL));
+		}
 	}
-	if ((fp = getf(fdes)) == NULL)
+	if ((fp = getf(fdes)) == NULL) {
+		if (aiovlen != 0)
+			kmem_free(aiov, aiovlen);
 		return (set_errno(EBADF));
+	}
 	if (((fflag = fp->f_flag) & FWRITE) == 0) {
 		error = EBADF;
 		goto out;
@@ -917,6 +977,8 @@
 	if (in_crit)
 		nbl_end_crit(vp);
 	releasef(fdes);
+	if (aiovlen != 0)
+		kmem_free(aiov, aiovlen);
 	if (error)
 		return (set_errno(error));
 	return (count);
@@ -927,7 +989,8 @@
     off_t extended_offset)
 {
 	struct uio auio;
-	struct iovec aiov[DEF_IOV_MAX];
+	struct iovec buf[IOV_MAX_STACK], *aiov = buf;
+	int aiovlen = 0;
 	file_t *fp;
 	register vnode_t *vp;
 	struct cpu *cp;
@@ -952,9 +1015,14 @@
 
 	int in_crit = 0;
 
-	if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX)
+	if (iovcnt <= 0 || iovcnt > IOV_MAX)
 		return (set_errno(EINVAL));
 
+	if (iovcnt > IOV_MAX_STACK) {
+		aiovlen = iovcnt * sizeof (iovec_t);
+		aiov = kmem_alloc(aiovlen, KM_SLEEP);
+	}
+
 #ifdef _SYSCALL32_IMPL
 	/*
 	 * 32-bit callers need to have their iovec expanded,
@@ -962,39 +1030,68 @@
 	 * of data in a single call.
 	 */
 	if (get_udatamodel() == DATAMODEL_ILP32) {
-		struct iovec32 aiov32[DEF_IOV_MAX];
+		struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
+		int aiov32len;
 		ssize32_t count32;
 
-		if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32)))
+		aiov32len = iovcnt * sizeof (iovec32_t);
+		if (aiovlen != 0)
+			aiov32 = kmem_alloc(aiov32len, KM_SLEEP);
+
+		if (copyin(iovp, aiov32, aiov32len)) {
+			if (aiovlen != 0) {
+				kmem_free(aiov32, aiov32len);
+				kmem_free(aiov, aiovlen);
+			}
 			return (set_errno(EFAULT));
+		}
 
 		count32 = 0;
 		for (i = 0; i < iovcnt; i++) {
 			ssize32_t iovlen32 = aiov32[i].iov_len;
 			count32 += iovlen32;
-			if (iovlen32 < 0 || count32 < 0)
+			if (iovlen32 < 0 || count32 < 0) {
+				if (aiovlen != 0) {
+					kmem_free(aiov32, aiov32len);
+					kmem_free(aiov, aiovlen);
+				}
 				return (set_errno(EINVAL));
+			}
 			aiov[i].iov_len = iovlen32;
 			aiov[i].iov_base =
 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
 		}
+		if (aiovlen != 0)
+			kmem_free(aiov32, aiov32len);
 	} else
 #endif /* _SYSCALL32_IMPL */
-		if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec)))
+		if (copyin(iovp, aiov, iovcnt * sizeof (iovec_t))) {
+			if (aiovlen != 0)
+				kmem_free(aiov, aiovlen);
 			return (set_errno(EFAULT));
+		}
 
 	count = 0;
 	for (i = 0; i < iovcnt; i++) {
 		ssize_t iovlen = aiov[i].iov_len;
 		count += iovlen;
-		if (iovlen < 0 || count < 0)
+		if (iovlen < 0 || count < 0) {
+			if (aiovlen != 0)
+				kmem_free(aiov, aiovlen);
 			return (set_errno(EINVAL));
+		}
 	}
 
-	if ((bcount = (ssize_t)count) < 0)
+	if ((bcount = (ssize_t)count) < 0) {
+		if (aiovlen != 0)
+			kmem_free(aiov, aiovlen);
 		return (set_errno(EINVAL));
-	if ((fp = getf(fdes)) == NULL)
+	}
+	if ((fp = getf(fdes)) == NULL) {
+		if (aiovlen != 0)
+			kmem_free(aiov, aiovlen);
 		return (set_errno(EBADF));
+	}
 	if (((fflag = fp->f_flag) & FREAD) == 0) {
 		error = EBADF;
 		goto out;
@@ -1099,6 +1196,8 @@
 	if (in_crit)
 		nbl_end_crit(vp);
 	releasef(fdes);
+	if (aiovlen != 0)
+		kmem_free(aiov, aiovlen);
 	if (error)
 		return (set_errno(error));
 	return (count);
@@ -1109,7 +1208,8 @@
     off_t extended_offset)
 {
 	struct uio auio;
-	struct iovec aiov[DEF_IOV_MAX];
+	struct iovec buf[IOV_MAX_STACK], *aiov = buf;
+	int aiovlen = 0;
 	file_t *fp;
 	register vnode_t *vp;
 	struct cpu *cp;
@@ -1134,9 +1234,14 @@
 
 	int in_crit = 0;
 
-	if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX)
+	if (iovcnt <= 0 || iovcnt > IOV_MAX)
 		return (set_errno(EINVAL));
 
+	if (iovcnt > IOV_MAX_STACK) {
+		aiovlen = iovcnt * sizeof (iovec_t);
+		aiov = kmem_alloc(aiovlen, KM_SLEEP);
+	}
+
 #ifdef _SYSCALL32_IMPL
 	/*
 	 * 32-bit callers need to have their iovec expanded,
@@ -1144,39 +1249,68 @@
 	 * of data in a single call.
 	 */
 	if (get_udatamodel() == DATAMODEL_ILP32) {
-		struct iovec32 aiov32[DEF_IOV_MAX];
+		struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
+		int aiov32len;
 		ssize32_t count32;
 
-		if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32)))
+		aiov32len = iovcnt * sizeof (iovec32_t);
+		if (aiovlen != 0)
+			aiov32 = kmem_alloc(aiov32len, KM_SLEEP);
+
+		if (copyin(iovp, aiov32, aiov32len)) {
+			if (aiovlen != 0) {
+				kmem_free(aiov32, aiov32len);
+				kmem_free(aiov, aiovlen);
+			}
 			return (set_errno(EFAULT));
+		}
 
 		count32 = 0;
 		for (i = 0; i < iovcnt; i++) {
 			ssize32_t iovlen32 = aiov32[i].iov_len;
 			count32 += iovlen32;
-			if (iovlen32 < 0 || count32 < 0)
+			if (iovlen32 < 0 || count32 < 0) {
+				if (aiovlen != 0) {
+					kmem_free(aiov32, aiov32len);
+					kmem_free(aiov, aiovlen);
+				}
 				return (set_errno(EINVAL));
+			}
 			aiov[i].iov_len = iovlen32;
 			aiov[i].iov_base =
 			    (caddr_t)(uintptr_t)aiov32[i].iov_base;
 		}
+		if (aiovlen != 0)
+			kmem_free(aiov32, aiov32len);
 	} else
 #endif /* _SYSCALL32_IMPL */
-		if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec)))
+		if (copyin(iovp, aiov, iovcnt * sizeof (iovec_t))) {
+			if (aiovlen != 0)
+				kmem_free(aiov, aiovlen);
 			return (set_errno(EFAULT));
+		}
 
 	count = 0;
 	for (i = 0; i < iovcnt; i++) {
 		ssize_t iovlen = aiov[i].iov_len;
 		count += iovlen;
-		if (iovlen < 0 || count < 0)
+		if (iovlen < 0 || count < 0) {
+			if (aiovlen != 0)
+				kmem_free(aiov, aiovlen);
 			return (set_errno(EINVAL));
+		}
 	}
 
-	if ((bcount = (ssize_t)count) < 0)
+	if ((bcount = (ssize_t)count) < 0) {
+		if (aiovlen != 0)
+			kmem_free(aiov, aiovlen);
 		return (set_errno(EINVAL));
-	if ((fp = getf(fdes)) == NULL)
+	}
+	if ((fp = getf(fdes)) == NULL) {
+		if (aiovlen != 0)
+			kmem_free(aiov, aiovlen);
 		return (set_errno(EBADF));
+	}
 	if (((fflag = fp->f_flag) & FWRITE) == 0) {
 		error = EBADF;
 		goto out;
@@ -1308,6 +1442,8 @@
 	if (in_crit)
 		nbl_end_crit(vp);
 	releasef(fdes);
+	if (aiovlen != 0)
+		kmem_free(aiov, aiovlen);
 	if (error)
 		return (set_errno(error));
 	return (count);
