1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/buf.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/conf.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/cred.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/debug.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/open.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/user.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/termios.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/esunddi.h> 50*7c478bd9Sstevel@tonic-gate #include <sys/flock.h> 51*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h> 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 56*7c478bd9Sstevel@tonic-gate #include <sys/socketvar.h> 57*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/sendfile.h> 59*7c478bd9Sstevel@tonic-gate #include <sys/un.h> 60*7c478bd9Sstevel@tonic-gate #include <inet/nca/ncadoorhdr.h> 61*7c478bd9Sstevel@tonic-gate #include <inet/nca/ncaio.h> 62*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 63*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate #include <inet/common.h> 66*7c478bd9Sstevel@tonic-gate #include <inet/ip.h> 67*7c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 68*7c478bd9Sstevel@tonic-gate #include <inet/tcp.h> 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate extern int nca_sendfilev(file_t *, struct sendfilevec *, int, ssize_t *); 71*7c478bd9Sstevel@tonic-gate extern int sosendfile64(file_t *, file_t *, const struct ksendfilevec64 *, 72*7c478bd9Sstevel@tonic-gate ssize32_t *); 73*7c478bd9Sstevel@tonic-gate extern void nl7c_sendfilev(struct sonode *, u_offset_t, struct sendfilevec *, 74*7c478bd9Sstevel@tonic-gate int); 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate #define SEND_MAX_CHUNK 16 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) || defined(_ILP32) 79*7c478bd9Sstevel@tonic-gate /* 80*7c478bd9Sstevel@tonic-gate * 64 bit offsets for 32 bit applications only running either on 81*7c478bd9Sstevel@tonic-gate * 64 bit kernel or 32 bit kernel. For 32 bit apps, we can't transfer 82*7c478bd9Sstevel@tonic-gate * more than 2GB of data. 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate int 85*7c478bd9Sstevel@tonic-gate sendvec_chunk64(file_t *fp, u_offset_t *fileoff, struct ksendfilevec64 *sfv, 86*7c478bd9Sstevel@tonic-gate int copy_cnt, ssize32_t *count) 87*7c478bd9Sstevel@tonic-gate { 88*7c478bd9Sstevel@tonic-gate struct vnode *vp; 89*7c478bd9Sstevel@tonic-gate ushort_t fflag; 90*7c478bd9Sstevel@tonic-gate int ioflag; 91*7c478bd9Sstevel@tonic-gate size32_t cnt; 92*7c478bd9Sstevel@tonic-gate ssize32_t sfv_len; 93*7c478bd9Sstevel@tonic-gate ssize32_t tmpcount; 94*7c478bd9Sstevel@tonic-gate u_offset_t sfv_off; 95*7c478bd9Sstevel@tonic-gate struct uio auio; 96*7c478bd9Sstevel@tonic-gate struct iovec aiov; 97*7c478bd9Sstevel@tonic-gate int i, error; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate fflag = fp->f_flag; 100*7c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 101*7c478bd9Sstevel@tonic-gate for (i = 0; i < copy_cnt; i++) { 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) 104*7c478bd9Sstevel@tonic-gate return (EINTR); 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate /* 107*7c478bd9Sstevel@tonic-gate * Do similar checks as "write" as we are writing 108*7c478bd9Sstevel@tonic-gate * sfv_len bytes into "vp". 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate sfv_len = (ssize32_t)sfv->sfv_len; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate if (sfv_len == 0) 113*7c478bd9Sstevel@tonic-gate continue; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate if (sfv_len < 0) 116*7c478bd9Sstevel@tonic-gate return (EINVAL); 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) { 119*7c478bd9Sstevel@tonic-gate if (*fileoff >= curproc->p_fsz_ctl) { 120*7c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 121*7c478bd9Sstevel@tonic-gate (void) rctl_action( 122*7c478bd9Sstevel@tonic-gate rctlproc_legacy[RLIMIT_FSIZE], 123*7c478bd9Sstevel@tonic-gate curproc->p_rctls, curproc, RCA_SAFE); 124*7c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 125*7c478bd9Sstevel@tonic-gate return (EFBIG); 126*7c478bd9Sstevel@tonic-gate } 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate if (*fileoff >= OFFSET_MAX(fp)) 129*7c478bd9Sstevel@tonic-gate return (EFBIG); 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate if (*fileoff + sfv_len > OFFSET_MAX(fp)) 132*7c478bd9Sstevel@tonic-gate return (EINVAL); 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate tmpcount = *count + sfv_len; 136*7c478bd9Sstevel@tonic-gate if (tmpcount < 0) 137*7c478bd9Sstevel@tonic-gate return (EINVAL); 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate sfv_off = sfv->sfv_off; 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_DEFAULT; 142*7c478bd9Sstevel@tonic-gate if (sfv->sfv_fd == SFV_FD_SELF) { 143*7c478bd9Sstevel@tonic-gate aiov.iov_len = sfv_len; 144*7c478bd9Sstevel@tonic-gate aiov.iov_base = (caddr_t)(uintptr_t)sfv_off; 145*7c478bd9Sstevel@tonic-gate auio.uio_loffset = *fileoff; 146*7c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 147*7c478bd9Sstevel@tonic-gate auio.uio_resid = sfv_len; 148*7c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 149*7c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 150*7c478bd9Sstevel@tonic-gate auio.uio_llimit = curproc->p_fsz_ctl; 151*7c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 152*7c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 153*7c478bd9Sstevel@tonic-gate while (sfv_len > 0) { 154*7c478bd9Sstevel@tonic-gate error = VOP_WRITE(vp, &auio, ioflag, 155*7c478bd9Sstevel@tonic-gate fp->f_cred, NULL); 156*7c478bd9Sstevel@tonic-gate cnt = sfv_len - auio.uio_resid; 157*7c478bd9Sstevel@tonic-gate sfv_len -= cnt; 158*7c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)cnt; 159*7c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) 160*7c478bd9Sstevel@tonic-gate *fileoff += cnt; 161*7c478bd9Sstevel@tonic-gate *count += cnt; 162*7c478bd9Sstevel@tonic-gate if (error != 0) 163*7c478bd9Sstevel@tonic-gate return (error); 164*7c478bd9Sstevel@tonic-gate } 165*7c478bd9Sstevel@tonic-gate } else { 166*7c478bd9Sstevel@tonic-gate file_t *ffp; 167*7c478bd9Sstevel@tonic-gate vnode_t *readvp; 168*7c478bd9Sstevel@tonic-gate int readflg = 0; 169*7c478bd9Sstevel@tonic-gate size_t size; 170*7c478bd9Sstevel@tonic-gate caddr_t ptr; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate if ((ffp = getf(sfv->sfv_fd)) == NULL) 173*7c478bd9Sstevel@tonic-gate return (EBADF); 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate if ((ffp->f_flag & FREAD) == 0) { 176*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 177*7c478bd9Sstevel@tonic-gate return (EBADF); 178*7c478bd9Sstevel@tonic-gate } 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate readvp = ffp->f_vnode; 181*7c478bd9Sstevel@tonic-gate if (readvp->v_type != VREG) { 182*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 183*7c478bd9Sstevel@tonic-gate return (EINVAL); 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* 187*7c478bd9Sstevel@tonic-gate * No point reading and writing to same vp, 188*7c478bd9Sstevel@tonic-gate * as long as both are regular files. readvp is not 189*7c478bd9Sstevel@tonic-gate * locked; but since we got it from an open file the 190*7c478bd9Sstevel@tonic-gate * contents will be valid during the time of access. 191*7c478bd9Sstevel@tonic-gate */ 192*7c478bd9Sstevel@tonic-gate if (VN_CMP(vp, readvp)) { 193*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 194*7c478bd9Sstevel@tonic-gate return (EINVAL); 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate /* 198*7c478bd9Sstevel@tonic-gate * Note: we assume readvp != vp. "vp" is already 199*7c478bd9Sstevel@tonic-gate * locked, and "readvp" must not be. 200*7c478bd9Sstevel@tonic-gate */ 201*7c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(readvp, readflg, NULL); 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * Same checks as in pread64. 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate if (sfv_off > MAXOFFSET_T) { 207*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 208*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 209*7c478bd9Sstevel@tonic-gate return (EINVAL); 210*7c478bd9Sstevel@tonic-gate } 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate if (sfv_off + sfv_len > MAXOFFSET_T) 213*7c478bd9Sstevel@tonic-gate sfv_len = (ssize32_t)(MAXOFFSET_T - sfv_off); 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate /* Find the native blocksize to transfer data */ 216*7c478bd9Sstevel@tonic-gate size = MIN(vp->v_vfsp->vfs_bsize, 217*7c478bd9Sstevel@tonic-gate readvp->v_vfsp->vfs_bsize); 218*7c478bd9Sstevel@tonic-gate size = sfv_len < size ? sfv_len : size; 219*7c478bd9Sstevel@tonic-gate ptr = kmem_alloc(size, KM_SLEEP); 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate while (sfv_len > 0) { 222*7c478bd9Sstevel@tonic-gate size_t iov_len; 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate iov_len = MIN(size, sfv_len); 225*7c478bd9Sstevel@tonic-gate aiov.iov_base = ptr; 226*7c478bd9Sstevel@tonic-gate aiov.iov_len = iov_len; 227*7c478bd9Sstevel@tonic-gate auio.uio_loffset = sfv_off; 228*7c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 229*7c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 230*7c478bd9Sstevel@tonic-gate auio.uio_resid = iov_len; 231*7c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 232*7c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 233*7c478bd9Sstevel@tonic-gate auio.uio_fmode = ffp->f_flag; 234*7c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & 235*7c478bd9Sstevel@tonic-gate (FAPPEND|FSYNC|FDSYNC|FRSYNC); 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * If read sync is not asked for, 239*7c478bd9Sstevel@tonic-gate * filter sync flags 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 242*7c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 243*7c478bd9Sstevel@tonic-gate error = VOP_READ(readvp, &auio, ioflag, 244*7c478bd9Sstevel@tonic-gate fp->f_cred, NULL); 245*7c478bd9Sstevel@tonic-gate if (error) { 246*7c478bd9Sstevel@tonic-gate kmem_free(ptr, size); 247*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 248*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 249*7c478bd9Sstevel@tonic-gate return (error); 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate /* 253*7c478bd9Sstevel@tonic-gate * Check how must data was really read. 254*7c478bd9Sstevel@tonic-gate * Decrement the 'len' and increment the 255*7c478bd9Sstevel@tonic-gate * 'off' appropriately. 256*7c478bd9Sstevel@tonic-gate */ 257*7c478bd9Sstevel@tonic-gate cnt = iov_len - auio.uio_resid; 258*7c478bd9Sstevel@tonic-gate if (cnt == 0) { 259*7c478bd9Sstevel@tonic-gate /* 260*7c478bd9Sstevel@tonic-gate * If we were reading a pipe (currently 261*7c478bd9Sstevel@tonic-gate * not implemented), we may now lose 262*7c478bd9Sstevel@tonic-gate * data. 263*7c478bd9Sstevel@tonic-gate */ 264*7c478bd9Sstevel@tonic-gate kmem_free(ptr, size); 265*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 266*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 267*7c478bd9Sstevel@tonic-gate return (EINVAL); 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate sfv_len -= cnt; 270*7c478bd9Sstevel@tonic-gate sfv_off += cnt; 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate aiov.iov_base = ptr; 273*7c478bd9Sstevel@tonic-gate aiov.iov_len = cnt; 274*7c478bd9Sstevel@tonic-gate auio.uio_loffset = *fileoff; 275*7c478bd9Sstevel@tonic-gate auio.uio_resid = cnt; 276*7c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 277*7c478bd9Sstevel@tonic-gate auio.uio_llimit = curproc->p_fsz_ctl; 278*7c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 279*7c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & 280*7c478bd9Sstevel@tonic-gate (FAPPEND|FSYNC|FDSYNC|FRSYNC); 281*7c478bd9Sstevel@tonic-gate error = VOP_WRITE(vp, &auio, ioflag, 282*7c478bd9Sstevel@tonic-gate fp->f_cred, NULL); 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate /* 285*7c478bd9Sstevel@tonic-gate * Check how much data was written. Increment 286*7c478bd9Sstevel@tonic-gate * the 'len' and decrement the 'off' if all 287*7c478bd9Sstevel@tonic-gate * the data was not written. 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate cnt -= auio.uio_resid; 290*7c478bd9Sstevel@tonic-gate sfv_len += auio.uio_resid; 291*7c478bd9Sstevel@tonic-gate sfv_off -= auio.uio_resid; 292*7c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)cnt; 293*7c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) 294*7c478bd9Sstevel@tonic-gate *fileoff += cnt; 295*7c478bd9Sstevel@tonic-gate *count += cnt; 296*7c478bd9Sstevel@tonic-gate if (error != 0) { 297*7c478bd9Sstevel@tonic-gate kmem_free(ptr, size); 298*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 299*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 300*7c478bd9Sstevel@tonic-gate return (error); 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 304*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 305*7c478bd9Sstevel@tonic-gate kmem_free(ptr, size); 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate sfv++; 308*7c478bd9Sstevel@tonic-gate } 309*7c478bd9Sstevel@tonic-gate return (0); 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate ssize32_t 313*7c478bd9Sstevel@tonic-gate sendvec64(file_t *fp, const struct ksendfilevec64 *vec, int sfvcnt, 314*7c478bd9Sstevel@tonic-gate size32_t *xferred, int fildes) 315*7c478bd9Sstevel@tonic-gate { 316*7c478bd9Sstevel@tonic-gate int rwflag; 317*7c478bd9Sstevel@tonic-gate u_offset_t fileoff; 318*7c478bd9Sstevel@tonic-gate int copy_cnt; 319*7c478bd9Sstevel@tonic-gate const struct ksendfilevec64 *copy_vec; 320*7c478bd9Sstevel@tonic-gate struct ksendfilevec64 sfv[SEND_MAX_CHUNK]; 321*7c478bd9Sstevel@tonic-gate struct vnode *vp; 322*7c478bd9Sstevel@tonic-gate int error; 323*7c478bd9Sstevel@tonic-gate ssize32_t count = 0; 324*7c478bd9Sstevel@tonic-gate int osfvcnt; 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate rwflag = 1; 327*7c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 328*7c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate copy_vec = vec; 331*7c478bd9Sstevel@tonic-gate fileoff = fp->f_offset; 332*7c478bd9Sstevel@tonic-gate osfvcnt = sfvcnt; 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate do { 335*7c478bd9Sstevel@tonic-gate copy_cnt = MIN(sfvcnt, SEND_MAX_CHUNK); 336*7c478bd9Sstevel@tonic-gate if (copyin(copy_vec, sfv, copy_cnt * 337*7c478bd9Sstevel@tonic-gate sizeof (struct ksendfilevec64))) { 338*7c478bd9Sstevel@tonic-gate error = EFAULT; 339*7c478bd9Sstevel@tonic-gate break; 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate /* 343*7c478bd9Sstevel@tonic-gate * Optimize the single regular file over 344*7c478bd9Sstevel@tonic-gate * the socket case. 345*7c478bd9Sstevel@tonic-gate */ 346*7c478bd9Sstevel@tonic-gate if (vp->v_type == VSOCK && osfvcnt == 1 && 347*7c478bd9Sstevel@tonic-gate sfv->sfv_fd != SFV_FD_SELF) { 348*7c478bd9Sstevel@tonic-gate file_t *rfp; 349*7c478bd9Sstevel@tonic-gate vnode_t *rvp; 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate if ((rfp = getf(sfv->sfv_fd)) == NULL) { 352*7c478bd9Sstevel@tonic-gate error = EBADF; 353*7c478bd9Sstevel@tonic-gate break; 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate if ((rfp->f_flag & FREAD) == 0) { 356*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 357*7c478bd9Sstevel@tonic-gate error = EBADF; 358*7c478bd9Sstevel@tonic-gate break; 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate rvp = rfp->f_vnode; 361*7c478bd9Sstevel@tonic-gate if (rvp->v_type == VREG) { 362*7c478bd9Sstevel@tonic-gate error = sosendfile64(fp, rfp, sfv, &count); 363*7c478bd9Sstevel@tonic-gate break; 364*7c478bd9Sstevel@tonic-gate } 365*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate error = sendvec_chunk64(fp, &fileoff, sfv, copy_cnt, &count); 368*7c478bd9Sstevel@tonic-gate if (error != 0) 369*7c478bd9Sstevel@tonic-gate break; 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate copy_vec += copy_cnt; 372*7c478bd9Sstevel@tonic-gate sfvcnt -= copy_cnt; 373*7c478bd9Sstevel@tonic-gate } while (sfvcnt > 0); 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) 376*7c478bd9Sstevel@tonic-gate fp->f_offset += count; 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 379*7c478bd9Sstevel@tonic-gate if (copyout(&count, xferred, sizeof (count))) 380*7c478bd9Sstevel@tonic-gate error = EFAULT; 381*7c478bd9Sstevel@tonic-gate releasef(fildes); 382*7c478bd9Sstevel@tonic-gate if (error != 0) 383*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 384*7c478bd9Sstevel@tonic-gate return (count); 385*7c478bd9Sstevel@tonic-gate } 386*7c478bd9Sstevel@tonic-gate #endif 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate int 389*7c478bd9Sstevel@tonic-gate sendvec_small_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv, 390*7c478bd9Sstevel@tonic-gate int copy_cnt, ssize_t total_size, int maxblk, ssize_t *count) 391*7c478bd9Sstevel@tonic-gate { 392*7c478bd9Sstevel@tonic-gate struct vnode *vp; 393*7c478bd9Sstevel@tonic-gate struct uio auio; 394*7c478bd9Sstevel@tonic-gate struct iovec aiov; 395*7c478bd9Sstevel@tonic-gate ushort_t fflag; 396*7c478bd9Sstevel@tonic-gate int ioflag; 397*7c478bd9Sstevel@tonic-gate int i, error; 398*7c478bd9Sstevel@tonic-gate size_t cnt; 399*7c478bd9Sstevel@tonic-gate ssize_t sfv_len; 400*7c478bd9Sstevel@tonic-gate u_offset_t sfv_off; 401*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 402*7c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 403*7c478bd9Sstevel@tonic-gate u_offset_t maxoff = (model == DATAMODEL_ILP32) ? 404*7c478bd9Sstevel@tonic-gate MAXOFF32_T : MAXOFFSET_T; 405*7c478bd9Sstevel@tonic-gate #else 406*7c478bd9Sstevel@tonic-gate const u_offset_t maxoff = MAXOFF32_T; 407*7c478bd9Sstevel@tonic-gate #endif 408*7c478bd9Sstevel@tonic-gate mblk_t *dmp = NULL; 409*7c478bd9Sstevel@tonic-gate int wroff; 410*7c478bd9Sstevel@tonic-gate int buf_left = 0; 411*7c478bd9Sstevel@tonic-gate size_t iov_len; 412*7c478bd9Sstevel@tonic-gate mblk_t *head, *tmp; 413*7c478bd9Sstevel@tonic-gate size_t size = total_size; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate fflag = fp->f_flag; 416*7c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VSOCK); 419*7c478bd9Sstevel@tonic-gate ASSERT(maxblk > 0); 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate wroff = (int)vp->v_stream->sd_wroff; 422*7c478bd9Sstevel@tonic-gate buf_left = MIN(total_size, maxblk); 423*7c478bd9Sstevel@tonic-gate head = dmp = allocb(buf_left + wroff, BPRI_HI); 424*7c478bd9Sstevel@tonic-gate if (head == NULL) 425*7c478bd9Sstevel@tonic-gate return (ENOMEM); 426*7c478bd9Sstevel@tonic-gate head->b_wptr = head->b_rptr = head->b_rptr + wroff; 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_DEFAULT; 429*7c478bd9Sstevel@tonic-gate for (i = 0; i < copy_cnt; i++) { 430*7c478bd9Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) 431*7c478bd9Sstevel@tonic-gate return (EINTR); 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate /* 434*7c478bd9Sstevel@tonic-gate * Do similar checks as "write" as we are writing 435*7c478bd9Sstevel@tonic-gate * sfv_len bytes into "vp". 436*7c478bd9Sstevel@tonic-gate */ 437*7c478bd9Sstevel@tonic-gate sfv_len = (ssize_t)sfv->sfv_len; 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate if (sfv_len == 0) { 440*7c478bd9Sstevel@tonic-gate sfv++; 441*7c478bd9Sstevel@tonic-gate continue; 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate /* Make sure sfv_len is not negative */ 445*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 446*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32) { 447*7c478bd9Sstevel@tonic-gate if ((ssize32_t)sfv_len < 0) 448*7c478bd9Sstevel@tonic-gate return (EINVAL); 449*7c478bd9Sstevel@tonic-gate } else 450*7c478bd9Sstevel@tonic-gate #endif 451*7c478bd9Sstevel@tonic-gate if (sfv_len < 0) 452*7c478bd9Sstevel@tonic-gate return (EINVAL); 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate /* Check for overflow */ 455*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 456*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32) { 457*7c478bd9Sstevel@tonic-gate if (((ssize32_t)(*count + sfv_len)) < 0) 458*7c478bd9Sstevel@tonic-gate return (EINVAL); 459*7c478bd9Sstevel@tonic-gate } else 460*7c478bd9Sstevel@tonic-gate #endif 461*7c478bd9Sstevel@tonic-gate if ((*count + sfv_len) < 0) 462*7c478bd9Sstevel@tonic-gate return (EINVAL); 463*7c478bd9Sstevel@tonic-gate 464*7c478bd9Sstevel@tonic-gate sfv_off = (u_offset_t)(ulong_t)sfv->sfv_off; 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate if (sfv->sfv_fd == SFV_FD_SELF) { 467*7c478bd9Sstevel@tonic-gate while (sfv_len > 0) { 468*7c478bd9Sstevel@tonic-gate if (buf_left == 0) { 469*7c478bd9Sstevel@tonic-gate tmp = dmp; 470*7c478bd9Sstevel@tonic-gate buf_left = MIN(total_size, maxblk); 471*7c478bd9Sstevel@tonic-gate iov_len = MIN(buf_left, sfv_len); 472*7c478bd9Sstevel@tonic-gate dmp = allocb(buf_left + wroff, BPRI_HI); 473*7c478bd9Sstevel@tonic-gate if (dmp == NULL) { 474*7c478bd9Sstevel@tonic-gate freemsg(head); 475*7c478bd9Sstevel@tonic-gate return (ENOMEM); 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate dmp->b_wptr = dmp->b_rptr = 478*7c478bd9Sstevel@tonic-gate dmp->b_rptr + wroff; 479*7c478bd9Sstevel@tonic-gate tmp->b_cont = dmp; 480*7c478bd9Sstevel@tonic-gate } else { 481*7c478bd9Sstevel@tonic-gate iov_len = MIN(buf_left, sfv_len); 482*7c478bd9Sstevel@tonic-gate } 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate aiov.iov_len = iov_len; 485*7c478bd9Sstevel@tonic-gate aiov.iov_base = (caddr_t)(uintptr_t)sfv_off; 486*7c478bd9Sstevel@tonic-gate auio.uio_loffset = *fileoff; 487*7c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 488*7c478bd9Sstevel@tonic-gate auio.uio_resid = iov_len; 489*7c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 490*7c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 491*7c478bd9Sstevel@tonic-gate auio.uio_llimit = curproc->p_fsz_ctl; 492*7c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate buf_left -= iov_len; 495*7c478bd9Sstevel@tonic-gate total_size -= iov_len; 496*7c478bd9Sstevel@tonic-gate sfv_len -= iov_len; 497*7c478bd9Sstevel@tonic-gate sfv_off += iov_len; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate error = uiomove((caddr_t)dmp->b_wptr, 500*7c478bd9Sstevel@tonic-gate iov_len, UIO_WRITE, &auio); 501*7c478bd9Sstevel@tonic-gate if (error != 0) { 502*7c478bd9Sstevel@tonic-gate freemsg(head); 503*7c478bd9Sstevel@tonic-gate return (error); 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate dmp->b_wptr += iov_len; 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate } else { 508*7c478bd9Sstevel@tonic-gate file_t *ffp; 509*7c478bd9Sstevel@tonic-gate vnode_t *readvp; 510*7c478bd9Sstevel@tonic-gate int readflg = 0; 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate if ((ffp = getf(sfv->sfv_fd)) == NULL) { 513*7c478bd9Sstevel@tonic-gate freemsg(head); 514*7c478bd9Sstevel@tonic-gate return (EBADF); 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate if ((ffp->f_flag & FREAD) == 0) { 518*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 519*7c478bd9Sstevel@tonic-gate freemsg(head); 520*7c478bd9Sstevel@tonic-gate return (EACCES); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate 523*7c478bd9Sstevel@tonic-gate readvp = ffp->f_vnode; 524*7c478bd9Sstevel@tonic-gate if (readvp->v_type != VREG) { 525*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 526*7c478bd9Sstevel@tonic-gate freemsg(head); 527*7c478bd9Sstevel@tonic-gate return (EINVAL); 528*7c478bd9Sstevel@tonic-gate } 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate /* 531*7c478bd9Sstevel@tonic-gate * No point reading and writing to same vp, 532*7c478bd9Sstevel@tonic-gate * as long as both are regular files. readvp is not 533*7c478bd9Sstevel@tonic-gate * locked; but since we got it from an open file the 534*7c478bd9Sstevel@tonic-gate * contents will be valid during the time of access. 535*7c478bd9Sstevel@tonic-gate */ 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate if (VN_CMP(vp, readvp)) { 538*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 539*7c478bd9Sstevel@tonic-gate freemsg(head); 540*7c478bd9Sstevel@tonic-gate return (EINVAL); 541*7c478bd9Sstevel@tonic-gate } 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate /* 544*7c478bd9Sstevel@tonic-gate * Note: we assume readvp != vp. "vp" is already 545*7c478bd9Sstevel@tonic-gate * locked, and "readvp" must not be. 546*7c478bd9Sstevel@tonic-gate */ 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(readvp, readflg, NULL); 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate /* Same checks as in pread */ 551*7c478bd9Sstevel@tonic-gate if (sfv_off > maxoff) { 552*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 553*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 554*7c478bd9Sstevel@tonic-gate freemsg(head); 555*7c478bd9Sstevel@tonic-gate return (EINVAL); 556*7c478bd9Sstevel@tonic-gate } 557*7c478bd9Sstevel@tonic-gate if (sfv_off + sfv_len > maxoff) { 558*7c478bd9Sstevel@tonic-gate sfv_len = (ssize_t)((offset_t)maxoff - 559*7c478bd9Sstevel@tonic-gate sfv_off); 560*7c478bd9Sstevel@tonic-gate } 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate while (sfv_len > 0) { 563*7c478bd9Sstevel@tonic-gate if (buf_left == 0) { 564*7c478bd9Sstevel@tonic-gate tmp = dmp; 565*7c478bd9Sstevel@tonic-gate buf_left = MIN(total_size, maxblk); 566*7c478bd9Sstevel@tonic-gate iov_len = MIN(buf_left, sfv_len); 567*7c478bd9Sstevel@tonic-gate dmp = allocb(buf_left + wroff, BPRI_HI); 568*7c478bd9Sstevel@tonic-gate if (dmp == NULL) { 569*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, 570*7c478bd9Sstevel@tonic-gate NULL); 571*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 572*7c478bd9Sstevel@tonic-gate freemsg(head); 573*7c478bd9Sstevel@tonic-gate return (ENOMEM); 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate dmp->b_wptr = dmp->b_rptr = 576*7c478bd9Sstevel@tonic-gate dmp->b_rptr + wroff; 577*7c478bd9Sstevel@tonic-gate tmp->b_cont = dmp; 578*7c478bd9Sstevel@tonic-gate } else { 579*7c478bd9Sstevel@tonic-gate iov_len = MIN(buf_left, sfv_len); 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate aiov.iov_base = (caddr_t)dmp->b_wptr; 582*7c478bd9Sstevel@tonic-gate aiov.iov_len = iov_len; 583*7c478bd9Sstevel@tonic-gate auio.uio_loffset = sfv_off; 584*7c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 585*7c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 586*7c478bd9Sstevel@tonic-gate auio.uio_resid = iov_len; 587*7c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 588*7c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 589*7c478bd9Sstevel@tonic-gate auio.uio_fmode = ffp->f_flag; 590*7c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & 591*7c478bd9Sstevel@tonic-gate (FAPPEND|FSYNC|FDSYNC|FRSYNC); 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate /* 594*7c478bd9Sstevel@tonic-gate * If read sync is not asked for, 595*7c478bd9Sstevel@tonic-gate * filter sync flags 596*7c478bd9Sstevel@tonic-gate */ 597*7c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 598*7c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 599*7c478bd9Sstevel@tonic-gate error = VOP_READ(readvp, &auio, ioflag, 600*7c478bd9Sstevel@tonic-gate fp->f_cred, NULL); 601*7c478bd9Sstevel@tonic-gate if (error != 0) { 602*7c478bd9Sstevel@tonic-gate /* 603*7c478bd9Sstevel@tonic-gate * If we were reading a pipe (currently 604*7c478bd9Sstevel@tonic-gate * not implemented), we may now loose 605*7c478bd9Sstevel@tonic-gate * data. 606*7c478bd9Sstevel@tonic-gate */ 607*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 608*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 609*7c478bd9Sstevel@tonic-gate freemsg(head); 610*7c478bd9Sstevel@tonic-gate return (error); 611*7c478bd9Sstevel@tonic-gate } 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate /* 614*7c478bd9Sstevel@tonic-gate * Check how much data was really read. 615*7c478bd9Sstevel@tonic-gate * Decrement the 'len' and increment the 616*7c478bd9Sstevel@tonic-gate * 'off' appropriately. 617*7c478bd9Sstevel@tonic-gate */ 618*7c478bd9Sstevel@tonic-gate cnt = iov_len - auio.uio_resid; 619*7c478bd9Sstevel@tonic-gate if (cnt == 0) { 620*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 621*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 622*7c478bd9Sstevel@tonic-gate freemsg(head); 623*7c478bd9Sstevel@tonic-gate return (EINVAL); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate sfv_len -= cnt; 626*7c478bd9Sstevel@tonic-gate sfv_off += cnt; 627*7c478bd9Sstevel@tonic-gate total_size -= cnt; 628*7c478bd9Sstevel@tonic-gate buf_left -= cnt; 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate dmp->b_wptr += cnt; 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 633*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 634*7c478bd9Sstevel@tonic-gate } 635*7c478bd9Sstevel@tonic-gate sfv++; 636*7c478bd9Sstevel@tonic-gate } 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate ASSERT(total_size == 0); 639*7c478bd9Sstevel@tonic-gate error = kstrwritemp(vp, head, fflag); 640*7c478bd9Sstevel@tonic-gate if (error != 0) { 641*7c478bd9Sstevel@tonic-gate freemsg(head); 642*7c478bd9Sstevel@tonic-gate return (error); 643*7c478bd9Sstevel@tonic-gate } 644*7c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)size; 645*7c478bd9Sstevel@tonic-gate *count += size; 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate return (0); 648*7c478bd9Sstevel@tonic-gate } 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate 651*7c478bd9Sstevel@tonic-gate int 652*7c478bd9Sstevel@tonic-gate sendvec_chunk(file_t *fp, u_offset_t *fileoff, struct sendfilevec *sfv, 653*7c478bd9Sstevel@tonic-gate int copy_cnt, ssize_t *count) 654*7c478bd9Sstevel@tonic-gate { 655*7c478bd9Sstevel@tonic-gate struct vnode *vp; 656*7c478bd9Sstevel@tonic-gate struct uio auio; 657*7c478bd9Sstevel@tonic-gate struct iovec aiov; 658*7c478bd9Sstevel@tonic-gate ushort_t fflag; 659*7c478bd9Sstevel@tonic-gate int ioflag; 660*7c478bd9Sstevel@tonic-gate int i, error; 661*7c478bd9Sstevel@tonic-gate size_t cnt; 662*7c478bd9Sstevel@tonic-gate ssize_t sfv_len; 663*7c478bd9Sstevel@tonic-gate u_offset_t sfv_off; 664*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 665*7c478bd9Sstevel@tonic-gate model_t model = get_udatamodel(); 666*7c478bd9Sstevel@tonic-gate u_offset_t maxoff = (model == DATAMODEL_ILP32) ? 667*7c478bd9Sstevel@tonic-gate MAXOFF32_T : MAXOFFSET_T; 668*7c478bd9Sstevel@tonic-gate #else 669*7c478bd9Sstevel@tonic-gate const u_offset_t maxoff = MAXOFF32_T; 670*7c478bd9Sstevel@tonic-gate #endif 671*7c478bd9Sstevel@tonic-gate mblk_t *dmp; 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate fflag = fp->f_flag; 674*7c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 675*7c478bd9Sstevel@tonic-gate 676*7c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_DEFAULT; 677*7c478bd9Sstevel@tonic-gate for (i = 0; i < copy_cnt; i++) { 678*7c478bd9Sstevel@tonic-gate if (ISSIG(curthread, JUSTLOOKING)) 679*7c478bd9Sstevel@tonic-gate return (EINTR); 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate /* 682*7c478bd9Sstevel@tonic-gate * Do similar checks as "write" as we are writing 683*7c478bd9Sstevel@tonic-gate * sfv_len bytes into "vp". 684*7c478bd9Sstevel@tonic-gate */ 685*7c478bd9Sstevel@tonic-gate sfv_len = (ssize_t)sfv->sfv_len; 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate if (sfv_len == 0) { 688*7c478bd9Sstevel@tonic-gate sfv++; 689*7c478bd9Sstevel@tonic-gate continue; 690*7c478bd9Sstevel@tonic-gate } 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* Make sure sfv_len is not negative */ 693*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 694*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32) { 695*7c478bd9Sstevel@tonic-gate if ((ssize32_t)sfv_len < 0) 696*7c478bd9Sstevel@tonic-gate return (EINVAL); 697*7c478bd9Sstevel@tonic-gate } else 698*7c478bd9Sstevel@tonic-gate #endif 699*7c478bd9Sstevel@tonic-gate if (sfv_len < 0) 700*7c478bd9Sstevel@tonic-gate return (EINVAL); 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) { 703*7c478bd9Sstevel@tonic-gate if (*fileoff >= curproc->p_fsz_ctl) { 704*7c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 705*7c478bd9Sstevel@tonic-gate (void) rctl_action( 706*7c478bd9Sstevel@tonic-gate rctlproc_legacy[RLIMIT_FSIZE], 707*7c478bd9Sstevel@tonic-gate curproc->p_rctls, curproc, RCA_SAFE); 708*7c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate return (EFBIG); 711*7c478bd9Sstevel@tonic-gate } 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate if (*fileoff >= maxoff) 714*7c478bd9Sstevel@tonic-gate return (EFBIG); 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate if (*fileoff + sfv_len > maxoff) 717*7c478bd9Sstevel@tonic-gate return (EINVAL); 718*7c478bd9Sstevel@tonic-gate } 719*7c478bd9Sstevel@tonic-gate 720*7c478bd9Sstevel@tonic-gate /* Check for overflow */ 721*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 722*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32) { 723*7c478bd9Sstevel@tonic-gate if (((ssize32_t)(*count + sfv_len)) < 0) 724*7c478bd9Sstevel@tonic-gate return (EINVAL); 725*7c478bd9Sstevel@tonic-gate } else 726*7c478bd9Sstevel@tonic-gate #endif 727*7c478bd9Sstevel@tonic-gate if ((*count + sfv_len) < 0) 728*7c478bd9Sstevel@tonic-gate return (EINVAL); 729*7c478bd9Sstevel@tonic-gate 730*7c478bd9Sstevel@tonic-gate sfv_off = (u_offset_t)(ulong_t)sfv->sfv_off; 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate if (sfv->sfv_fd == SFV_FD_SELF) { 733*7c478bd9Sstevel@tonic-gate aiov.iov_len = sfv_len; 734*7c478bd9Sstevel@tonic-gate aiov.iov_base = (caddr_t)(uintptr_t)sfv_off; 735*7c478bd9Sstevel@tonic-gate auio.uio_loffset = *fileoff; 736*7c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 737*7c478bd9Sstevel@tonic-gate auio.uio_resid = sfv_len; 738*7c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 739*7c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 740*7c478bd9Sstevel@tonic-gate auio.uio_llimit = curproc->p_fsz_ctl; 741*7c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate if (vp->v_type == VSOCK) { 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate /* 746*7c478bd9Sstevel@tonic-gate * Optimize for the socket case 747*7c478bd9Sstevel@tonic-gate */ 748*7c478bd9Sstevel@tonic-gate int wroff = (int)vp->v_stream->sd_wroff; 749*7c478bd9Sstevel@tonic-gate 750*7c478bd9Sstevel@tonic-gate dmp = allocb(sfv_len + wroff, BPRI_HI); 751*7c478bd9Sstevel@tonic-gate if (dmp == NULL) 752*7c478bd9Sstevel@tonic-gate return (ENOMEM); 753*7c478bd9Sstevel@tonic-gate dmp->b_wptr = dmp->b_rptr = dmp->b_rptr + wroff; 754*7c478bd9Sstevel@tonic-gate error = uiomove((caddr_t)dmp->b_wptr, 755*7c478bd9Sstevel@tonic-gate sfv_len, UIO_WRITE, &auio); 756*7c478bd9Sstevel@tonic-gate if (error != 0) { 757*7c478bd9Sstevel@tonic-gate freeb(dmp); 758*7c478bd9Sstevel@tonic-gate return (error); 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate dmp->b_wptr += sfv_len; 761*7c478bd9Sstevel@tonic-gate error = kstrwritemp(vp, dmp, fflag); 762*7c478bd9Sstevel@tonic-gate if (error != 0) { 763*7c478bd9Sstevel@tonic-gate freeb(dmp); 764*7c478bd9Sstevel@tonic-gate return (error); 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += 767*7c478bd9Sstevel@tonic-gate (ulong_t)sfv_len; 768*7c478bd9Sstevel@tonic-gate *count += sfv_len; 769*7c478bd9Sstevel@tonic-gate } else { 770*7c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & 771*7c478bd9Sstevel@tonic-gate (FAPPEND|FSYNC|FDSYNC|FRSYNC); 772*7c478bd9Sstevel@tonic-gate while (sfv_len > 0) { 773*7c478bd9Sstevel@tonic-gate error = VOP_WRITE(vp, &auio, ioflag, 774*7c478bd9Sstevel@tonic-gate fp->f_cred, NULL); 775*7c478bd9Sstevel@tonic-gate cnt = sfv_len - auio.uio_resid; 776*7c478bd9Sstevel@tonic-gate sfv_len -= cnt; 777*7c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += 778*7c478bd9Sstevel@tonic-gate (ulong_t)cnt; 779*7c478bd9Sstevel@tonic-gate *fileoff += cnt; 780*7c478bd9Sstevel@tonic-gate *count += cnt; 781*7c478bd9Sstevel@tonic-gate if (error != 0) 782*7c478bd9Sstevel@tonic-gate return (error); 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate } else { 786*7c478bd9Sstevel@tonic-gate file_t *ffp; 787*7c478bd9Sstevel@tonic-gate vnode_t *readvp; 788*7c478bd9Sstevel@tonic-gate int readflg = 0; 789*7c478bd9Sstevel@tonic-gate size_t size; 790*7c478bd9Sstevel@tonic-gate caddr_t ptr; 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate if ((ffp = getf(sfv->sfv_fd)) == NULL) 793*7c478bd9Sstevel@tonic-gate return (EBADF); 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate if ((ffp->f_flag & FREAD) == 0) { 796*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 797*7c478bd9Sstevel@tonic-gate return (EBADF); 798*7c478bd9Sstevel@tonic-gate } 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate readvp = ffp->f_vnode; 801*7c478bd9Sstevel@tonic-gate if (readvp->v_type != VREG) { 802*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 803*7c478bd9Sstevel@tonic-gate return (EINVAL); 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate /* 807*7c478bd9Sstevel@tonic-gate * No point reading and writing to same vp, 808*7c478bd9Sstevel@tonic-gate * as long as both are regular files. readvp is not 809*7c478bd9Sstevel@tonic-gate * locked; but since we got it from an open file the 810*7c478bd9Sstevel@tonic-gate * contents will be valid during the time of access. 811*7c478bd9Sstevel@tonic-gate */ 812*7c478bd9Sstevel@tonic-gate if (VN_CMP(vp, readvp)) { 813*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 814*7c478bd9Sstevel@tonic-gate return (EINVAL); 815*7c478bd9Sstevel@tonic-gate } 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate /* 818*7c478bd9Sstevel@tonic-gate * Note: we assume readvp != vp. "vp" is already 819*7c478bd9Sstevel@tonic-gate * locked, and "readvp" must not be. 820*7c478bd9Sstevel@tonic-gate */ 821*7c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(readvp, readflg, NULL); 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate /* Same checks as in pread */ 824*7c478bd9Sstevel@tonic-gate if (sfv_off > maxoff) { 825*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 826*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 827*7c478bd9Sstevel@tonic-gate return (EINVAL); 828*7c478bd9Sstevel@tonic-gate } 829*7c478bd9Sstevel@tonic-gate if (sfv_off + sfv_len > maxoff) { 830*7c478bd9Sstevel@tonic-gate sfv_len = (ssize_t)((offset_t)maxoff - 831*7c478bd9Sstevel@tonic-gate sfv_off); 832*7c478bd9Sstevel@tonic-gate } 833*7c478bd9Sstevel@tonic-gate /* Find the native blocksize to transfer data */ 834*7c478bd9Sstevel@tonic-gate size = MIN(vp->v_vfsp->vfs_bsize, 835*7c478bd9Sstevel@tonic-gate readvp->v_vfsp->vfs_bsize); 836*7c478bd9Sstevel@tonic-gate size = sfv_len < size ? sfv_len : size; 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate while (sfv_len > 0) { 839*7c478bd9Sstevel@tonic-gate size_t iov_len; 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate iov_len = MIN(size, sfv_len); 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate dmp = allocb(iov_len, BPRI_HI); 844*7c478bd9Sstevel@tonic-gate if (dmp == NULL) { 845*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 846*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 847*7c478bd9Sstevel@tonic-gate return (ENOMEM); 848*7c478bd9Sstevel@tonic-gate } 849*7c478bd9Sstevel@tonic-gate ptr = (caddr_t)dmp->b_rptr; 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate aiov.iov_base = ptr; 852*7c478bd9Sstevel@tonic-gate aiov.iov_len = iov_len; 853*7c478bd9Sstevel@tonic-gate auio.uio_loffset = sfv_off; 854*7c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 855*7c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 856*7c478bd9Sstevel@tonic-gate auio.uio_resid = iov_len; 857*7c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 858*7c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 859*7c478bd9Sstevel@tonic-gate auio.uio_fmode = ffp->f_flag; 860*7c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & 861*7c478bd9Sstevel@tonic-gate (FAPPEND|FSYNC|FDSYNC|FRSYNC); 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate /* 864*7c478bd9Sstevel@tonic-gate * If read sync is not asked for, 865*7c478bd9Sstevel@tonic-gate * filter sync flags 866*7c478bd9Sstevel@tonic-gate */ 867*7c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 868*7c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 869*7c478bd9Sstevel@tonic-gate error = VOP_READ(readvp, &auio, ioflag, 870*7c478bd9Sstevel@tonic-gate fp->f_cred, NULL); 871*7c478bd9Sstevel@tonic-gate if (error != 0) { 872*7c478bd9Sstevel@tonic-gate /* 873*7c478bd9Sstevel@tonic-gate * If we were reading a pipe (currently 874*7c478bd9Sstevel@tonic-gate * not implemented), we may now lose 875*7c478bd9Sstevel@tonic-gate * data. 876*7c478bd9Sstevel@tonic-gate */ 877*7c478bd9Sstevel@tonic-gate freeb(dmp); 878*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 879*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 880*7c478bd9Sstevel@tonic-gate return (error); 881*7c478bd9Sstevel@tonic-gate } 882*7c478bd9Sstevel@tonic-gate 883*7c478bd9Sstevel@tonic-gate /* 884*7c478bd9Sstevel@tonic-gate * Check how much data was really read. 885*7c478bd9Sstevel@tonic-gate * Decrement the 'len' and increment the 886*7c478bd9Sstevel@tonic-gate * 'off' appropriately. 887*7c478bd9Sstevel@tonic-gate */ 888*7c478bd9Sstevel@tonic-gate cnt = iov_len - auio.uio_resid; 889*7c478bd9Sstevel@tonic-gate if (cnt == 0) { 890*7c478bd9Sstevel@tonic-gate freeb(dmp); 891*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 892*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 893*7c478bd9Sstevel@tonic-gate return (EINVAL); 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate sfv_len -= cnt; 896*7c478bd9Sstevel@tonic-gate sfv_off += cnt; 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate if (vp->v_type == VSOCK) { 899*7c478bd9Sstevel@tonic-gate dmp->b_wptr = dmp->b_rptr + cnt; 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate error = kstrwritemp(vp, dmp, fflag); 902*7c478bd9Sstevel@tonic-gate if (error != 0) { 903*7c478bd9Sstevel@tonic-gate freeb(dmp); 904*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, 905*7c478bd9Sstevel@tonic-gate NULL); 906*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 907*7c478bd9Sstevel@tonic-gate return (error); 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += 911*7c478bd9Sstevel@tonic-gate (ulong_t)cnt; 912*7c478bd9Sstevel@tonic-gate *count += cnt; 913*7c478bd9Sstevel@tonic-gate } else { 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate aiov.iov_base = ptr; 916*7c478bd9Sstevel@tonic-gate aiov.iov_len = cnt; 917*7c478bd9Sstevel@tonic-gate auio.uio_loffset = *fileoff; 918*7c478bd9Sstevel@tonic-gate auio.uio_resid = cnt; 919*7c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_SYSSPACE; 920*7c478bd9Sstevel@tonic-gate auio.uio_llimit = curproc->p_fsz_ctl; 921*7c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 922*7c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & 923*7c478bd9Sstevel@tonic-gate (FAPPEND|FSYNC|FDSYNC|FRSYNC); 924*7c478bd9Sstevel@tonic-gate error = VOP_WRITE(vp, &auio, ioflag, 925*7c478bd9Sstevel@tonic-gate fp->f_cred, NULL); 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate /* 928*7c478bd9Sstevel@tonic-gate * Check how much data was written. 929*7c478bd9Sstevel@tonic-gate * Increment the 'len' and decrement the 930*7c478bd9Sstevel@tonic-gate * 'off' if all the data was not 931*7c478bd9Sstevel@tonic-gate * written. 932*7c478bd9Sstevel@tonic-gate */ 933*7c478bd9Sstevel@tonic-gate cnt -= auio.uio_resid; 934*7c478bd9Sstevel@tonic-gate sfv_len += auio.uio_resid; 935*7c478bd9Sstevel@tonic-gate sfv_off -= auio.uio_resid; 936*7c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += 937*7c478bd9Sstevel@tonic-gate (ulong_t)cnt; 938*7c478bd9Sstevel@tonic-gate *fileoff += cnt; 939*7c478bd9Sstevel@tonic-gate *count += cnt; 940*7c478bd9Sstevel@tonic-gate freeb(dmp); 941*7c478bd9Sstevel@tonic-gate if (error != 0) { 942*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, 943*7c478bd9Sstevel@tonic-gate NULL); 944*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 945*7c478bd9Sstevel@tonic-gate return (error); 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate } 948*7c478bd9Sstevel@tonic-gate } 949*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(readvp, readflg, NULL); 950*7c478bd9Sstevel@tonic-gate releasef(sfv->sfv_fd); 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate sfv++; 953*7c478bd9Sstevel@tonic-gate } 954*7c478bd9Sstevel@tonic-gate return (0); 955*7c478bd9Sstevel@tonic-gate } 956*7c478bd9Sstevel@tonic-gate 957*7c478bd9Sstevel@tonic-gate ssize_t 958*7c478bd9Sstevel@tonic-gate sendfilev(int opcode, int fildes, const struct sendfilevec *vec, int sfvcnt, 959*7c478bd9Sstevel@tonic-gate size_t *xferred) 960*7c478bd9Sstevel@tonic-gate { 961*7c478bd9Sstevel@tonic-gate int error; 962*7c478bd9Sstevel@tonic-gate file_t *fp; 963*7c478bd9Sstevel@tonic-gate struct vnode *vp; 964*7c478bd9Sstevel@tonic-gate struct sonode *so; 965*7c478bd9Sstevel@tonic-gate u_offset_t fileoff; 966*7c478bd9Sstevel@tonic-gate int copy_cnt; 967*7c478bd9Sstevel@tonic-gate const struct sendfilevec *copy_vec; 968*7c478bd9Sstevel@tonic-gate struct sendfilevec sfv[SEND_MAX_CHUNK]; 969*7c478bd9Sstevel@tonic-gate ssize_t count = 0; 970*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 971*7c478bd9Sstevel@tonic-gate struct ksendfilevec32 sfv32[SEND_MAX_CHUNK]; 972*7c478bd9Sstevel@tonic-gate #endif 973*7c478bd9Sstevel@tonic-gate ssize_t total_size = 0; 974*7c478bd9Sstevel@tonic-gate int i; 975*7c478bd9Sstevel@tonic-gate boolean_t is_sock = B_FALSE; 976*7c478bd9Sstevel@tonic-gate int maxblk = 0; 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate if (sfvcnt <= 0) 979*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate if ((fp = getf(fildes)) == NULL) 982*7c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate if (((fp->f_flag) & FWRITE) == 0) { 985*7c478bd9Sstevel@tonic-gate error = EBADF; 986*7c478bd9Sstevel@tonic-gate goto err; 987*7c478bd9Sstevel@tonic-gate } 988*7c478bd9Sstevel@tonic-gate 989*7c478bd9Sstevel@tonic-gate fileoff = fp->f_offset; 990*7c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 991*7c478bd9Sstevel@tonic-gate 992*7c478bd9Sstevel@tonic-gate switch (vp->v_type) { 993*7c478bd9Sstevel@tonic-gate case VSOCK: 994*7c478bd9Sstevel@tonic-gate so = VTOSO(vp); 995*7c478bd9Sstevel@tonic-gate /* sendfile not supported for SCTP */ 996*7c478bd9Sstevel@tonic-gate if (so->so_protocol == IPPROTO_SCTP) { 997*7c478bd9Sstevel@tonic-gate error = EPROTONOSUPPORT; 998*7c478bd9Sstevel@tonic-gate goto err; 999*7c478bd9Sstevel@tonic-gate } 1000*7c478bd9Sstevel@tonic-gate is_sock = B_TRUE; 1001*7c478bd9Sstevel@tonic-gate switch (so->so_family) { 1002*7c478bd9Sstevel@tonic-gate case AF_NCA: 1003*7c478bd9Sstevel@tonic-gate case AF_INET: 1004*7c478bd9Sstevel@tonic-gate case AF_INET6: 1005*7c478bd9Sstevel@tonic-gate /* 1006*7c478bd9Sstevel@tonic-gate * Make similar checks done in SOP_WRITE(). 1007*7c478bd9Sstevel@tonic-gate */ 1008*7c478bd9Sstevel@tonic-gate if (so->so_state & SS_CANTSENDMORE) { 1009*7c478bd9Sstevel@tonic-gate tsignal(curthread, SIGPIPE); 1010*7c478bd9Sstevel@tonic-gate error = EPIPE; 1011*7c478bd9Sstevel@tonic-gate goto err; 1012*7c478bd9Sstevel@tonic-gate } 1013*7c478bd9Sstevel@tonic-gate if (so->so_type != SOCK_STREAM) { 1014*7c478bd9Sstevel@tonic-gate error = EOPNOTSUPP; 1015*7c478bd9Sstevel@tonic-gate goto err; 1016*7c478bd9Sstevel@tonic-gate } 1017*7c478bd9Sstevel@tonic-gate 1018*7c478bd9Sstevel@tonic-gate if ((so->so_state & (SS_ISCONNECTED|SS_ISBOUND)) != 1019*7c478bd9Sstevel@tonic-gate (SS_ISCONNECTED|SS_ISBOUND)) { 1020*7c478bd9Sstevel@tonic-gate error = ENOTCONN; 1021*7c478bd9Sstevel@tonic-gate goto err; 1022*7c478bd9Sstevel@tonic-gate } 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate if ((so->so_state & SS_TCP_FAST_ACCEPT) && 1025*7c478bd9Sstevel@tonic-gate (so->so_priv != NULL)) { 1026*7c478bd9Sstevel@tonic-gate maxblk = ((tcp_t *)so->so_priv)->tcp_mss; 1027*7c478bd9Sstevel@tonic-gate } else { 1028*7c478bd9Sstevel@tonic-gate maxblk = (int)vp->v_stream->sd_maxblk; 1029*7c478bd9Sstevel@tonic-gate } 1030*7c478bd9Sstevel@tonic-gate break; 1031*7c478bd9Sstevel@tonic-gate default: 1032*7c478bd9Sstevel@tonic-gate error = EAFNOSUPPORT; 1033*7c478bd9Sstevel@tonic-gate goto err; 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate break; 1036*7c478bd9Sstevel@tonic-gate case VREG: 1037*7c478bd9Sstevel@tonic-gate break; 1038*7c478bd9Sstevel@tonic-gate default: 1039*7c478bd9Sstevel@tonic-gate error = EINVAL; 1040*7c478bd9Sstevel@tonic-gate goto err; 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate switch (opcode) { 1044*7c478bd9Sstevel@tonic-gate case SENDFILEV : 1045*7c478bd9Sstevel@tonic-gate break; 1046*7c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) || defined(_ILP32) 1047*7c478bd9Sstevel@tonic-gate case SENDFILEV64 : 1048*7c478bd9Sstevel@tonic-gate return (sendvec64(fp, (struct ksendfilevec64 *)vec, sfvcnt, 1049*7c478bd9Sstevel@tonic-gate (size32_t *)xferred, fildes)); 1050*7c478bd9Sstevel@tonic-gate #endif 1051*7c478bd9Sstevel@tonic-gate default : 1052*7c478bd9Sstevel@tonic-gate error = ENOSYS; 1053*7c478bd9Sstevel@tonic-gate break; 1054*7c478bd9Sstevel@tonic-gate } 1055*7c478bd9Sstevel@tonic-gate 1056*7c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 1057*7c478bd9Sstevel@tonic-gate copy_vec = vec; 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate do { 1060*7c478bd9Sstevel@tonic-gate copy_cnt = MIN(sfvcnt, SEND_MAX_CHUNK); 1061*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1062*7c478bd9Sstevel@tonic-gate /* 32-bit callers need to have their iovec expanded. */ 1063*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_ILP32) { 1064*7c478bd9Sstevel@tonic-gate if (copyin(copy_vec, sfv32, 1065*7c478bd9Sstevel@tonic-gate copy_cnt * sizeof (ksendfilevec32_t))) { 1066*7c478bd9Sstevel@tonic-gate error = EFAULT; 1067*7c478bd9Sstevel@tonic-gate break; 1068*7c478bd9Sstevel@tonic-gate } 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate for (i = 0; i < copy_cnt; i++) { 1071*7c478bd9Sstevel@tonic-gate sfv[i].sfv_fd = sfv32[i].sfv_fd; 1072*7c478bd9Sstevel@tonic-gate sfv[i].sfv_off = 1073*7c478bd9Sstevel@tonic-gate (off_t)(uint32_t)sfv32[i].sfv_off; 1074*7c478bd9Sstevel@tonic-gate sfv[i].sfv_len = (size_t)sfv32[i].sfv_len; 1075*7c478bd9Sstevel@tonic-gate total_size += sfv[i].sfv_len; 1076*7c478bd9Sstevel@tonic-gate sfv[i].sfv_flag = sfv32[i].sfv_flag; 1077*7c478bd9Sstevel@tonic-gate } 1078*7c478bd9Sstevel@tonic-gate } else { 1079*7c478bd9Sstevel@tonic-gate #endif 1080*7c478bd9Sstevel@tonic-gate if (copyin(copy_vec, sfv, 1081*7c478bd9Sstevel@tonic-gate copy_cnt * sizeof (sendfilevec_t))) { 1082*7c478bd9Sstevel@tonic-gate error = EFAULT; 1083*7c478bd9Sstevel@tonic-gate break; 1084*7c478bd9Sstevel@tonic-gate } 1085*7c478bd9Sstevel@tonic-gate 1086*7c478bd9Sstevel@tonic-gate for (i = 0; i < copy_cnt; i++) { 1087*7c478bd9Sstevel@tonic-gate total_size += sfv[i].sfv_len; 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1090*7c478bd9Sstevel@tonic-gate } 1091*7c478bd9Sstevel@tonic-gate #endif 1092*7c478bd9Sstevel@tonic-gate 1093*7c478bd9Sstevel@tonic-gate /* 1094*7c478bd9Sstevel@tonic-gate * The task between deciding to use sendvec_small_chunk 1095*7c478bd9Sstevel@tonic-gate * and sendvec_chunk is dependant on multiple things: 1096*7c478bd9Sstevel@tonic-gate * 1097*7c478bd9Sstevel@tonic-gate * i) latency is important for smaller files. So if the 1098*7c478bd9Sstevel@tonic-gate * data is smaller than 'tcp_slow_start_initial' times 1099*7c478bd9Sstevel@tonic-gate * maxblk, then use sendvec_small_chunk which creates 1100*7c478bd9Sstevel@tonic-gate * maxblk size mblks and chains then together and sends 1101*7c478bd9Sstevel@tonic-gate * them to TCP in one shot. It also leaves 'wroff' size 1102*7c478bd9Sstevel@tonic-gate * space for the headers in each mblk. 1103*7c478bd9Sstevel@tonic-gate * 1104*7c478bd9Sstevel@tonic-gate * ii) for total size bigger than 'tcp_slow_start_initial' 1105*7c478bd9Sstevel@tonic-gate * time maxblk, its probably real file data which is 1106*7c478bd9Sstevel@tonic-gate * dominating. So its better to use sendvec_chunk because 1107*7c478bd9Sstevel@tonic-gate * performance goes to dog if we don't do pagesize reads. 1108*7c478bd9Sstevel@tonic-gate * sendvec_chunk will do pagesize reads and write them 1109*7c478bd9Sstevel@tonic-gate * in pagesize mblks to TCP. 1110*7c478bd9Sstevel@tonic-gate * 1111*7c478bd9Sstevel@tonic-gate * Side Notes: A write to file has not been optimized. 1112*7c478bd9Sstevel@tonic-gate * Future zero copy code will plugin into sendvec_chunk 1113*7c478bd9Sstevel@tonic-gate * only because doing zero copy for files smaller then 1114*7c478bd9Sstevel@tonic-gate * pagesize is useless. 1115*7c478bd9Sstevel@tonic-gate * 1116*7c478bd9Sstevel@tonic-gate * Note, if socket has NL7C enabled then call NL7C's 1117*7c478bd9Sstevel@tonic-gate * senfilev() function to give NL7C a chance to copy 1118*7c478bd9Sstevel@tonic-gate * the vec for caching, then continue processing as 1119*7c478bd9Sstevel@tonic-gate * normal. 1120*7c478bd9Sstevel@tonic-gate */ 1121*7c478bd9Sstevel@tonic-gate if (is_sock) { 1122*7c478bd9Sstevel@tonic-gate switch (so->so_family) { 1123*7c478bd9Sstevel@tonic-gate case AF_INET: 1124*7c478bd9Sstevel@tonic-gate case AF_INET6: 1125*7c478bd9Sstevel@tonic-gate if (so->so_nl7c_flags != 0) { 1126*7c478bd9Sstevel@tonic-gate nl7c_sendfilev(so, fileoff, 1127*7c478bd9Sstevel@tonic-gate sfv, copy_cnt); 1128*7c478bd9Sstevel@tonic-gate } 1129*7c478bd9Sstevel@tonic-gate if (total_size <= (4 * maxblk)) 1130*7c478bd9Sstevel@tonic-gate error = sendvec_small_chunk(fp, 1131*7c478bd9Sstevel@tonic-gate &fileoff, sfv, copy_cnt, 1132*7c478bd9Sstevel@tonic-gate total_size, maxblk, &count); 1133*7c478bd9Sstevel@tonic-gate else 1134*7c478bd9Sstevel@tonic-gate error = sendvec_chunk(fp, &fileoff, 1135*7c478bd9Sstevel@tonic-gate sfv, copy_cnt, &count); 1136*7c478bd9Sstevel@tonic-gate break; 1137*7c478bd9Sstevel@tonic-gate case AF_NCA: 1138*7c478bd9Sstevel@tonic-gate error = nca_sendfilev(fp, sfv, copy_cnt, 1139*7c478bd9Sstevel@tonic-gate &count); 1140*7c478bd9Sstevel@tonic-gate break; 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate } else { 1143*7c478bd9Sstevel@tonic-gate ASSERT(vp->v_type == VREG); 1144*7c478bd9Sstevel@tonic-gate error = sendvec_chunk(fp, &fileoff, sfv, copy_cnt, 1145*7c478bd9Sstevel@tonic-gate &count); 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate 1149*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1150*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_ILP32) 1151*7c478bd9Sstevel@tonic-gate copy_vec = (const struct sendfilevec *)((char *)copy_vec + 1152*7c478bd9Sstevel@tonic-gate (copy_cnt * sizeof (ksendfilevec32_t))); 1153*7c478bd9Sstevel@tonic-gate else 1154*7c478bd9Sstevel@tonic-gate #endif 1155*7c478bd9Sstevel@tonic-gate copy_vec += copy_cnt; 1156*7c478bd9Sstevel@tonic-gate sfvcnt -= copy_cnt; 1157*7c478bd9Sstevel@tonic-gate } while (sfvcnt > 0); 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) 1160*7c478bd9Sstevel@tonic-gate fp->f_offset += count; 1161*7c478bd9Sstevel@tonic-gate 1162*7c478bd9Sstevel@tonic-gate 1163*7c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1164*7c478bd9Sstevel@tonic-gate 1165*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1166*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_ILP32) { 1167*7c478bd9Sstevel@tonic-gate ssize32_t count32 = (ssize32_t)count; 1168*7c478bd9Sstevel@tonic-gate if (copyout(&count32, xferred, sizeof (count32))) 1169*7c478bd9Sstevel@tonic-gate error = EFAULT; 1170*7c478bd9Sstevel@tonic-gate releasef(fildes); 1171*7c478bd9Sstevel@tonic-gate if (error != 0) 1172*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 1173*7c478bd9Sstevel@tonic-gate return (count32); 1174*7c478bd9Sstevel@tonic-gate } 1175*7c478bd9Sstevel@tonic-gate #endif 1176*7c478bd9Sstevel@tonic-gate if (copyout(&count, xferred, sizeof (count))) 1177*7c478bd9Sstevel@tonic-gate error = EFAULT; 1178*7c478bd9Sstevel@tonic-gate releasef(fildes); 1179*7c478bd9Sstevel@tonic-gate if (error != 0) 1180*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 1181*7c478bd9Sstevel@tonic-gate return (count); 1182*7c478bd9Sstevel@tonic-gate err: 1183*7c478bd9Sstevel@tonic-gate ASSERT(error != 0); 1184*7c478bd9Sstevel@tonic-gate releasef(fildes); 1185*7c478bd9Sstevel@tonic-gate return (set_errno(error)); 1186*7c478bd9Sstevel@tonic-gate } 1187