Print this page
5880 Increase IOV_MAX to at least 1024
Portions contributed by: Jerry Jelinek <jerry.jelinek@joyent.com>

@@ -76,10 +76,11 @@
 #include <sys/sunldi_impl.h>
 #include <sys/autoconf.h>
 #include <sys/policy.h>
 #include <sys/dld.h>
 #include <sys/zone.h>
+#include <sys/limits.h>
 #include <c2/audit.h>
 
 /*
  * This define helps improve the readability of streams code while
  * still maintaining a very old streams performance enhancement.  The

@@ -985,16 +986,24 @@
                  * If this is the first time we're called by e.g. strread
                  * only do the downcall if there is a deferred wakeup
                  * (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
                  * to prevent strrput from nacking ioctls immediately.
                  * When the last concurrent rwnext returns

@@ -1029,10 +1038,12 @@
                 ASSERT(MUTEX_HELD(&stp->sd_lock));
                 if (error == 0 || error == EWOULDBLOCK) {
                         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;
                 } else if (error == EINVAL) {
                         /*

@@ -1048,12 +1059,18 @@
                          */
                         error = 0;
                 } 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().
                  */
         }

@@ -2544,10 +2561,12 @@
 static int
 strput(struct stdata *stp, mblk_t *mctl, struct uio *uiop, ssize_t *iosize,
     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;
         ssize_t count = *iosize;
 

@@ -2635,17 +2654,25 @@
         }
 
         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);
         if (error == EINVAL) {
                 /*

@@ -2659,28 +2686,36 @@
                  * so fall-back to putnext().
                  */
                 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 */
         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);
                 }
         }
         ASSERT(mp == uiod.d_mp);
         /* 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);
         if (flags & MSG_IGNFLOW) {
                 /*

@@ -2693,10 +2728,12 @@
         } else {
                 stream_willservice(stp);
                 putnext(wqp, mp);
                 stream_runservice(stp);
         }
+        if (iovlen != 0)
+                kmem_free(uiod.d_iov, iovlen);
         return (0);
 }
 
 /*
  * Write attempts to break the write request into messages conforming