Print this page
5880 Increase IOV_MAX to at least 1024
Portions contributed by: Jerry Jelinek <jerry.jelinek@joyent.com>
*** 20,30 ****
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
! * Copyright (c) 2015, Joyent, Inc. All rights reserved.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
--- 20,30 ----
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
! * Copyright 2015, Joyent, Inc. All rights reserved.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
*** 48,57 ****
--- 48,58 ----
#include <sys/cpuvar.h>
#include <sys/uio.h>
#include <sys/debug.h>
#include <sys/rctl.h>
#include <sys/nbmlock.h>
+ #include <sys/limits.h>
#define COPYOUT_MAX_CACHE (1<<17) /* 128K */
size_t copyout_max_cached = COPYOUT_MAX_CACHE; /* global so it's patchable */
*** 605,627 ****
if (error)
return (set_errno(error));
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];
file_t *fp;
register vnode_t *vp;
struct cpu *cp;
int fflag, ioflag, rwflag;
ssize_t count, bcount;
--- 606,621 ----
if (error)
return (set_errno(error));
return (bcount);
}
ssize_t
readv(int fdes, struct iovec *iovp, int iovcnt)
{
struct uio auio;
! struct iovec buf[IOV_MAX_STACK], *aiov = buf;
! int aiovlen = 0;
file_t *fp;
register vnode_t *vp;
struct cpu *cp;
int fflag, ioflag, rwflag;
ssize_t count, bcount;
*** 628,677 ****
int error = 0;
int i;
u_offset_t fileoff;
int in_crit = 0;
! if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX)
return (set_errno(EINVAL));
#ifdef _SYSCALL32_IMPL
/*
* 32-bit callers need to have their iovec expanded,
* while ensuring that they can't move more than 2Gbytes
* of data in a single call.
*/
if (get_udatamodel() == DATAMODEL_ILP32) {
! struct iovec32 aiov32[DEF_IOV_MAX];
ssize32_t count32;
! if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32)))
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)
return (set_errno(EINVAL));
aiov[i].iov_len = iovlen32;
aiov[i].iov_base =
(caddr_t)(uintptr_t)aiov32[i].iov_base;
}
} else
#endif
! if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec)))
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)
return (set_errno(EINVAL));
}
! if ((fp = getf(fdes)) == NULL)
return (set_errno(EBADF));
if (((fflag = fp->f_flag) & FREAD) == 0) {
error = EBADF;
goto out;
}
vp = fp->f_vnode;
--- 622,703 ----
int error = 0;
int i;
u_offset_t fileoff;
int in_crit = 0;
! 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,
* while ensuring that they can't move more than 2Gbytes
* of data in a single call.
*/
if (get_udatamodel() == DATAMODEL_ILP32) {
! struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
! int aiov32len;
ssize32_t count32;
! 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 (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 (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 (aiovlen != 0)
! kmem_free(aiov, aiovlen);
return (set_errno(EINVAL));
}
! }
! 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;
}
vp = fp->f_vnode;
*** 766,785 ****
error = 0;
out:
if (in_crit)
nbl_end_crit(vp);
releasef(fdes);
if (error)
return (set_errno(error));
return (count);
}
ssize_t
writev(int fdes, struct iovec *iovp, int iovcnt)
{
struct uio auio;
! struct iovec aiov[DEF_IOV_MAX];
file_t *fp;
register vnode_t *vp;
struct cpu *cp;
int fflag, ioflag, rwflag;
ssize_t count, bcount;
--- 792,814 ----
error = 0;
out:
if (in_crit)
nbl_end_crit(vp);
releasef(fdes);
+ if (aiovlen != 0)
+ kmem_free(aiov, aiovlen);
if (error)
return (set_errno(error));
return (count);
}
ssize_t
writev(int fdes, struct iovec *iovp, int iovcnt)
{
struct uio auio;
! struct iovec buf[IOV_MAX_STACK], *aiov = buf;
! int aiovlen = 0;
file_t *fp;
register vnode_t *vp;
struct cpu *cp;
int fflag, ioflag, rwflag;
ssize_t count, bcount;
*** 786,835 ****
int error = 0;
int i;
u_offset_t fileoff;
int in_crit = 0;
! if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX)
return (set_errno(EINVAL));
#ifdef _SYSCALL32_IMPL
/*
* 32-bit callers need to have their iovec expanded,
* while ensuring that they can't move more than 2Gbytes
* of data in a single call.
*/
if (get_udatamodel() == DATAMODEL_ILP32) {
! struct iovec32 aiov32[DEF_IOV_MAX];
ssize32_t count32;
! if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32)))
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)
return (set_errno(EINVAL));
aiov[i].iov_len = iovlen;
aiov[i].iov_base =
(caddr_t)(uintptr_t)aiov32[i].iov_base;
}
} else
#endif
! if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec)))
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)
return (set_errno(EINVAL));
}
! if ((fp = getf(fdes)) == NULL)
return (set_errno(EBADF));
if (((fflag = fp->f_flag) & FWRITE) == 0) {
error = EBADF;
goto out;
}
vp = fp->f_vnode;
--- 815,895 ----
int error = 0;
int i;
u_offset_t fileoff;
int in_crit = 0;
! 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,
* while ensuring that they can't move more than 2Gbytes
* of data in a single call.
*/
if (get_udatamodel() == DATAMODEL_ILP32) {
! struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
! int aiov32len;
ssize32_t count32;
! 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 (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 (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 (aiovlen != 0)
! kmem_free(aiov, aiovlen);
return (set_errno(EINVAL));
}
! }
! 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;
}
vp = fp->f_vnode;
*** 915,924 ****
--- 975,986 ----
error = 0;
out:
if (in_crit)
nbl_end_crit(vp);
releasef(fdes);
+ if (aiovlen != 0)
+ kmem_free(aiov, aiovlen);
if (error)
return (set_errno(error));
return (count);
}
*** 925,935 ****
ssize_t
preadv(int fdes, struct iovec *iovp, int iovcnt, off_t offset,
off_t extended_offset)
{
struct uio auio;
! struct iovec aiov[DEF_IOV_MAX];
file_t *fp;
register vnode_t *vp;
struct cpu *cp;
int fflag, ioflag, rwflag;
ssize_t count, bcount;
--- 987,998 ----
ssize_t
preadv(int fdes, struct iovec *iovp, int iovcnt, off_t offset,
off_t extended_offset)
{
struct uio auio;
! struct iovec buf[IOV_MAX_STACK], *aiov = buf;
! int aiovlen = 0;
file_t *fp;
register vnode_t *vp;
struct cpu *cp;
int fflag, ioflag, rwflag;
ssize_t count, bcount;
*** 950,1002 ****
const u_offset_t maxoff = MAXOFF32_T;
#endif /* _SYSCALL32_IMPL */
int in_crit = 0;
! if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX)
return (set_errno(EINVAL));
#ifdef _SYSCALL32_IMPL
/*
* 32-bit callers need to have their iovec expanded,
* while ensuring that they can't move more than 2Gbytes
* of data in a single call.
*/
if (get_udatamodel() == DATAMODEL_ILP32) {
! struct iovec32 aiov32[DEF_IOV_MAX];
ssize32_t count32;
! if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32)))
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)
return (set_errno(EINVAL));
aiov[i].iov_len = iovlen32;
aiov[i].iov_base =
(caddr_t)(uintptr_t)aiov32[i].iov_base;
}
} else
#endif /* _SYSCALL32_IMPL */
! if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec)))
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)
return (set_errno(EINVAL));
}
! if ((bcount = (ssize_t)count) < 0)
return (set_errno(EINVAL));
! if ((fp = getf(fdes)) == NULL)
return (set_errno(EBADF));
if (((fflag = fp->f_flag) & FREAD) == 0) {
error = EBADF;
goto out;
}
vp = fp->f_vnode;
--- 1013,1099 ----
const u_offset_t maxoff = MAXOFF32_T;
#endif /* _SYSCALL32_IMPL */
int in_crit = 0;
! 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,
* while ensuring that they can't move more than 2Gbytes
* of data in a single call.
*/
if (get_udatamodel() == DATAMODEL_ILP32) {
! struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
! int aiov32len;
ssize32_t count32;
! 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 (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 (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 (aiovlen != 0)
! kmem_free(aiov, aiovlen);
return (set_errno(EINVAL));
}
+ }
! if ((bcount = (ssize_t)count) < 0) {
! if (aiovlen != 0)
! kmem_free(aiov, aiovlen);
return (set_errno(EINVAL));
! }
! 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;
}
vp = fp->f_vnode;
*** 1097,1106 ****
--- 1194,1205 ----
error = 0;
out:
if (in_crit)
nbl_end_crit(vp);
releasef(fdes);
+ if (aiovlen != 0)
+ kmem_free(aiov, aiovlen);
if (error)
return (set_errno(error));
return (count);
}
*** 1107,1117 ****
ssize_t
pwritev(int fdes, struct iovec *iovp, int iovcnt, off_t offset,
off_t extended_offset)
{
struct uio auio;
! struct iovec aiov[DEF_IOV_MAX];
file_t *fp;
register vnode_t *vp;
struct cpu *cp;
int fflag, ioflag, rwflag;
ssize_t count, bcount;
--- 1206,1217 ----
ssize_t
pwritev(int fdes, struct iovec *iovp, int iovcnt, off_t offset,
off_t extended_offset)
{
struct uio auio;
! struct iovec buf[IOV_MAX_STACK], *aiov = buf;
! int aiovlen = 0;
file_t *fp;
register vnode_t *vp;
struct cpu *cp;
int fflag, ioflag, rwflag;
ssize_t count, bcount;
*** 1132,1184 ****
const u_offset_t maxoff = MAXOFF32_T;
#endif /* _SYSCALL32_IMPL */
int in_crit = 0;
! if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX)
return (set_errno(EINVAL));
#ifdef _SYSCALL32_IMPL
/*
* 32-bit callers need to have their iovec expanded,
* while ensuring that they can't move more than 2Gbytes
* of data in a single call.
*/
if (get_udatamodel() == DATAMODEL_ILP32) {
! struct iovec32 aiov32[DEF_IOV_MAX];
ssize32_t count32;
! if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32)))
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)
return (set_errno(EINVAL));
aiov[i].iov_len = iovlen32;
aiov[i].iov_base =
(caddr_t)(uintptr_t)aiov32[i].iov_base;
}
} else
#endif /* _SYSCALL32_IMPL */
! if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec)))
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)
return (set_errno(EINVAL));
}
! if ((bcount = (ssize_t)count) < 0)
return (set_errno(EINVAL));
! if ((fp = getf(fdes)) == NULL)
return (set_errno(EBADF));
if (((fflag = fp->f_flag) & FWRITE) == 0) {
error = EBADF;
goto out;
}
vp = fp->f_vnode;
--- 1232,1318 ----
const u_offset_t maxoff = MAXOFF32_T;
#endif /* _SYSCALL32_IMPL */
int in_crit = 0;
! 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,
* while ensuring that they can't move more than 2Gbytes
* of data in a single call.
*/
if (get_udatamodel() == DATAMODEL_ILP32) {
! struct iovec32 buf32[IOV_MAX_STACK], *aiov32 = buf32;
! int aiov32len;
ssize32_t count32;
! 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 (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 (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 (aiovlen != 0)
! kmem_free(aiov, aiovlen);
return (set_errno(EINVAL));
}
+ }
! if ((bcount = (ssize_t)count) < 0) {
! if (aiovlen != 0)
! kmem_free(aiov, aiovlen);
return (set_errno(EINVAL));
! }
! 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;
}
vp = fp->f_vnode;
*** 1306,1315 ****
--- 1440,1451 ----
error = 0;
out:
if (in_crit)
nbl_end_crit(vp);
releasef(fdes);
+ if (aiovlen != 0)
+ kmem_free(aiov, aiovlen);
if (error)
return (set_errno(error));
return (count);
}