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); }