17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 513506d1eSmaybee * Common Development and Distribution License (the "License"). 613506d1eSmaybee * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*da6c28aaSamw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 317c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <sys/param.h> 377c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 397c478bd9Sstevel@tonic-gate #include <sys/inttypes.h> 407c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 417c478bd9Sstevel@tonic-gate #include <sys/cred.h> 427c478bd9Sstevel@tonic-gate #include <sys/user.h> 437c478bd9Sstevel@tonic-gate #include <sys/systm.h> 447c478bd9Sstevel@tonic-gate #include <sys/errno.h> 457c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 467c478bd9Sstevel@tonic-gate #include <sys/file.h> 477c478bd9Sstevel@tonic-gate #include <sys/proc.h> 487c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 497c478bd9Sstevel@tonic-gate #include <sys/uio.h> 507c478bd9Sstevel@tonic-gate #include <sys/debug.h> 517c478bd9Sstevel@tonic-gate #include <sys/rctl.h> 527c478bd9Sstevel@tonic-gate #include <sys/nbmlock.h> 537c478bd9Sstevel@tonic-gate 5413506d1eSmaybee #define COPYOUT_MAX_CACHE (1<<17) /* 128K */ 557c478bd9Sstevel@tonic-gate 5613506d1eSmaybee size_t copyout_max_cached = COPYOUT_MAX_CACHE; /* global so it's patchable */ 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * read, write, pread, pwrite, readv, and writev syscalls. 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * 64-bit open: all open's are large file opens. 627c478bd9Sstevel@tonic-gate * Large Files: the behaviour of read depends on whether the fd 637c478bd9Sstevel@tonic-gate * corresponds to large open or not. 647c478bd9Sstevel@tonic-gate * 32-bit open: FOFFMAX flag not set. 657c478bd9Sstevel@tonic-gate * read until MAXOFF32_T - 1 and read at MAXOFF32_T returns 667c478bd9Sstevel@tonic-gate * EOVERFLOW if count is non-zero and if size of file 677c478bd9Sstevel@tonic-gate * is > MAXOFF32_T. If size of file is <= MAXOFF32_T read 687c478bd9Sstevel@tonic-gate * at >= MAXOFF32_T returns EOF. 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * Native system call 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate ssize_t 757c478bd9Sstevel@tonic-gate read(int fdes, void *cbuf, size_t count) 767c478bd9Sstevel@tonic-gate { 777c478bd9Sstevel@tonic-gate struct uio auio; 787c478bd9Sstevel@tonic-gate struct iovec aiov; 797c478bd9Sstevel@tonic-gate file_t *fp; 807c478bd9Sstevel@tonic-gate register vnode_t *vp; 817c478bd9Sstevel@tonic-gate struct cpu *cp; 827c478bd9Sstevel@tonic-gate int fflag, ioflag, rwflag; 837c478bd9Sstevel@tonic-gate ssize_t cnt, bcount; 847c478bd9Sstevel@tonic-gate int error = 0; 857c478bd9Sstevel@tonic-gate u_offset_t fileoff; 867c478bd9Sstevel@tonic-gate int in_crit = 0; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate if ((cnt = (ssize_t)count) < 0) 897c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 907c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 917c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); 927c478bd9Sstevel@tonic-gate if (((fflag = fp->f_flag) & FREAD) == 0) { 937c478bd9Sstevel@tonic-gate error = EBADF; 947c478bd9Sstevel@tonic-gate goto out; 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && cnt == 0) { 997c478bd9Sstevel@tonic-gate goto out; 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate rwflag = 0; 1037c478bd9Sstevel@tonic-gate aiov.iov_base = cbuf; 1047c478bd9Sstevel@tonic-gate aiov.iov_len = cnt; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 1087c478bd9Sstevel@tonic-gate * to avoid a deadlock with write() calls. 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 1117c478bd9Sstevel@tonic-gate int svmand; 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 1147c478bd9Sstevel@tonic-gate in_crit = 1; 1157c478bd9Sstevel@tonic-gate error = nbl_svmand(vp, fp->f_cred, &svmand); 1167c478bd9Sstevel@tonic-gate if (error != 0) 1177c478bd9Sstevel@tonic-gate goto out; 118*da6c28aaSamw if (nbl_conflict(vp, NBL_READ, fp->f_offset, cnt, svmand, 119*da6c28aaSamw NULL)) { 1207c478bd9Sstevel@tonic-gate error = EACCES; 1217c478bd9Sstevel@tonic-gate goto out; 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * We do the following checks inside VOP_RWLOCK so as to 1297c478bd9Sstevel@tonic-gate * prevent file size from changing while these checks are 1307c478bd9Sstevel@tonic-gate * being done. Also, we load fp's offset to the local 1317c478bd9Sstevel@tonic-gate * variable fileoff because we can have a parallel lseek 1327c478bd9Sstevel@tonic-gate * going on (f_offset is not protected by any lock) which 1337c478bd9Sstevel@tonic-gate * could change f_offset. We need to see the value only 1347c478bd9Sstevel@tonic-gate * once here and take a decision. Seeing it more than once 1357c478bd9Sstevel@tonic-gate * can lead to incorrect functionality. 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate fileoff = (u_offset_t)fp->f_offset; 1397c478bd9Sstevel@tonic-gate if (fileoff >= OFFSET_MAX(fp) && (vp->v_type == VREG)) { 1407c478bd9Sstevel@tonic-gate struct vattr va; 1417c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE; 142*da6c28aaSamw if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred, NULL))) { 1437c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 1447c478bd9Sstevel@tonic-gate goto out; 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate if (fileoff >= va.va_size) { 1477c478bd9Sstevel@tonic-gate cnt = 0; 1487c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 1497c478bd9Sstevel@tonic-gate goto out; 1507c478bd9Sstevel@tonic-gate } else { 1517c478bd9Sstevel@tonic-gate error = EOVERFLOW; 1527c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 1537c478bd9Sstevel@tonic-gate goto out; 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate if ((vp->v_type == VREG) && 1577c478bd9Sstevel@tonic-gate (fileoff + cnt > OFFSET_MAX(fp))) { 1587c478bd9Sstevel@tonic-gate cnt = (ssize_t)(OFFSET_MAX(fp) - fileoff); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 1617c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 1627c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 1637c478bd9Sstevel@tonic-gate auio.uio_resid = bcount = cnt; 1647c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 1657c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 1667c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 1677c478bd9Sstevel@tonic-gate /* 1687c478bd9Sstevel@tonic-gate * Only use bypass caches when the count is large enough 1697c478bd9Sstevel@tonic-gate */ 17013506d1eSmaybee if (bcount <= copyout_max_cached) 1717c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 1727c478bd9Sstevel@tonic-gate else 1737c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_DEFAULT; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */ 1787c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 1797c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 1807c478bd9Sstevel@tonic-gate error = VOP_READ(vp, &auio, ioflag, fp->f_cred, NULL); 1817c478bd9Sstevel@tonic-gate cnt -= auio.uio_resid; 1827c478bd9Sstevel@tonic-gate CPU_STATS_ENTER_K(); 1837c478bd9Sstevel@tonic-gate cp = CPU; 1847c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, sysread, 1); 1857c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, readch, (ulong_t)cnt); 1867c478bd9Sstevel@tonic-gate CPU_STATS_EXIT_K(); 1877c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)cnt; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate if (vp->v_type == VFIFO) /* Backward compatibility */ 1907c478bd9Sstevel@tonic-gate fp->f_offset = cnt; 1917c478bd9Sstevel@tonic-gate else if (((fp->f_flag & FAPPEND) == 0) || 1927c478bd9Sstevel@tonic-gate (vp->v_type != VREG) || (bcount != 0)) /* POSIX */ 1937c478bd9Sstevel@tonic-gate fp->f_offset = auio.uio_loffset; 1947c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate if (error == EINTR && cnt != 0) 1977c478bd9Sstevel@tonic-gate error = 0; 1987c478bd9Sstevel@tonic-gate out: 1997c478bd9Sstevel@tonic-gate if (in_crit) 2007c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 2017c478bd9Sstevel@tonic-gate releasef(fdes); 2027c478bd9Sstevel@tonic-gate if (error) 2037c478bd9Sstevel@tonic-gate return (set_errno(error)); 2047c478bd9Sstevel@tonic-gate return (cnt); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * Native system call 2097c478bd9Sstevel@tonic-gate */ 2107c478bd9Sstevel@tonic-gate ssize_t 2117c478bd9Sstevel@tonic-gate write(int fdes, void *cbuf, size_t count) 2127c478bd9Sstevel@tonic-gate { 2137c478bd9Sstevel@tonic-gate struct uio auio; 2147c478bd9Sstevel@tonic-gate struct iovec aiov; 2157c478bd9Sstevel@tonic-gate file_t *fp; 2167c478bd9Sstevel@tonic-gate register vnode_t *vp; 2177c478bd9Sstevel@tonic-gate struct cpu *cp; 2187c478bd9Sstevel@tonic-gate int fflag, ioflag, rwflag; 2197c478bd9Sstevel@tonic-gate ssize_t cnt, bcount; 2207c478bd9Sstevel@tonic-gate int error = 0; 2217c478bd9Sstevel@tonic-gate u_offset_t fileoff; 2227c478bd9Sstevel@tonic-gate int in_crit = 0; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if ((cnt = (ssize_t)count) < 0) 2257c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 2267c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 2277c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); 2287c478bd9Sstevel@tonic-gate if (((fflag = fp->f_flag) & FWRITE) == 0) { 2297c478bd9Sstevel@tonic-gate error = EBADF; 2307c478bd9Sstevel@tonic-gate goto out; 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && cnt == 0) { 2357c478bd9Sstevel@tonic-gate goto out; 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate rwflag = 1; 2397c478bd9Sstevel@tonic-gate aiov.iov_base = cbuf; 2407c478bd9Sstevel@tonic-gate aiov.iov_len = cnt; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* 2437c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 2447c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 2477c478bd9Sstevel@tonic-gate int svmand; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 2507c478bd9Sstevel@tonic-gate in_crit = 1; 2517c478bd9Sstevel@tonic-gate error = nbl_svmand(vp, fp->f_cred, &svmand); 2527c478bd9Sstevel@tonic-gate if (error != 0) 2537c478bd9Sstevel@tonic-gate goto out; 254*da6c28aaSamw if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, cnt, svmand, 255*da6c28aaSamw NULL)) { 2567c478bd9Sstevel@tonic-gate error = EACCES; 2577c478bd9Sstevel@tonic-gate goto out; 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate fileoff = fp->f_offset; 2647c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) { 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* 2677c478bd9Sstevel@tonic-gate * We raise psignal if write for >0 bytes causes 2687c478bd9Sstevel@tonic-gate * it to exceed the ulimit. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate if (fileoff >= curproc->p_fsz_ctl) { 2717c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 2747c478bd9Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], 2757c478bd9Sstevel@tonic-gate curproc->p_rctls, curproc, RCA_UNSAFE_SIGINFO); 2767c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate error = EFBIG; 2797c478bd9Sstevel@tonic-gate goto out; 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * We return EFBIG if write is done at an offset 2837c478bd9Sstevel@tonic-gate * greater than the offset maximum for this file structure. 2847c478bd9Sstevel@tonic-gate */ 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate if (fileoff >= OFFSET_MAX(fp)) { 2877c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 2887c478bd9Sstevel@tonic-gate error = EFBIG; 2897c478bd9Sstevel@tonic-gate goto out; 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate /* 2927c478bd9Sstevel@tonic-gate * Limit the bytes to be written upto offset maximum for 2937c478bd9Sstevel@tonic-gate * this open file structure. 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate if (fileoff + cnt > OFFSET_MAX(fp)) 2967c478bd9Sstevel@tonic-gate cnt = (ssize_t)(OFFSET_MAX(fp) - fileoff); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 2997c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 3007c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 3017c478bd9Sstevel@tonic-gate auio.uio_resid = bcount = cnt; 3027c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 3037c478bd9Sstevel@tonic-gate auio.uio_llimit = curproc->p_fsz_ctl; 3047c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 3057c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_DEFAULT; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate error = VOP_WRITE(vp, &auio, ioflag, fp->f_cred, NULL); 3107c478bd9Sstevel@tonic-gate cnt -= auio.uio_resid; 3117c478bd9Sstevel@tonic-gate CPU_STATS_ENTER_K(); 3127c478bd9Sstevel@tonic-gate cp = CPU; 3137c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, syswrite, 1); 3147c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, writech, (ulong_t)cnt); 3157c478bd9Sstevel@tonic-gate CPU_STATS_EXIT_K(); 3167c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)cnt; 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate if (vp->v_type == VFIFO) /* Backward compatibility */ 3197c478bd9Sstevel@tonic-gate fp->f_offset = cnt; 3207c478bd9Sstevel@tonic-gate else if (((fp->f_flag & FAPPEND) == 0) || 3217c478bd9Sstevel@tonic-gate (vp->v_type != VREG) || (bcount != 0)) /* POSIX */ 3227c478bd9Sstevel@tonic-gate fp->f_offset = auio.uio_loffset; 3237c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (error == EINTR && cnt != 0) 3267c478bd9Sstevel@tonic-gate error = 0; 3277c478bd9Sstevel@tonic-gate out: 3287c478bd9Sstevel@tonic-gate if (in_crit) 3297c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 3307c478bd9Sstevel@tonic-gate releasef(fdes); 3317c478bd9Sstevel@tonic-gate if (error) 3327c478bd9Sstevel@tonic-gate return (set_errno(error)); 3337c478bd9Sstevel@tonic-gate return (cnt); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate ssize_t 3377c478bd9Sstevel@tonic-gate pread(int fdes, void *cbuf, size_t count, off_t offset) 3387c478bd9Sstevel@tonic-gate { 3397c478bd9Sstevel@tonic-gate struct uio auio; 3407c478bd9Sstevel@tonic-gate struct iovec aiov; 3417c478bd9Sstevel@tonic-gate file_t *fp; 3427c478bd9Sstevel@tonic-gate register vnode_t *vp; 3437c478bd9Sstevel@tonic-gate struct cpu *cp; 3447c478bd9Sstevel@tonic-gate int fflag, ioflag, rwflag; 3457c478bd9Sstevel@tonic-gate ssize_t bcount; 3467c478bd9Sstevel@tonic-gate int error = 0; 3477c478bd9Sstevel@tonic-gate u_offset_t fileoff = (u_offset_t)(ulong_t)offset; 3487c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 3497c478bd9Sstevel@tonic-gate u_offset_t maxoff = get_udatamodel() == DATAMODEL_ILP32 ? 3507c478bd9Sstevel@tonic-gate MAXOFF32_T : MAXOFFSET_T; 3517c478bd9Sstevel@tonic-gate #else 3527c478bd9Sstevel@tonic-gate const u_offset_t maxoff = MAXOFF32_T; 3537c478bd9Sstevel@tonic-gate #endif 3547c478bd9Sstevel@tonic-gate int in_crit = 0; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate if ((bcount = (ssize_t)count) < 0) 3577c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 3607c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); 3617c478bd9Sstevel@tonic-gate if (((fflag = fp->f_flag) & (FREAD)) == 0) { 3627c478bd9Sstevel@tonic-gate error = EBADF; 3637c478bd9Sstevel@tonic-gate goto out; 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate rwflag = 0; 3677c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) { 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate if (bcount == 0) 3727c478bd9Sstevel@tonic-gate goto out; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * Return EINVAL if an invalid offset comes to pread. 3767c478bd9Sstevel@tonic-gate * Negative offset from user will cause this error. 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate if (fileoff > maxoff) { 3807c478bd9Sstevel@tonic-gate error = EINVAL; 3817c478bd9Sstevel@tonic-gate goto out; 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Limit offset such that we don't read or write 3857c478bd9Sstevel@tonic-gate * a file beyond the maximum offset representable in 3867c478bd9Sstevel@tonic-gate * an off_t structure. 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate if (fileoff + bcount > maxoff) 3897c478bd9Sstevel@tonic-gate bcount = (ssize_t)((offset_t)maxoff - fileoff); 3907c478bd9Sstevel@tonic-gate } else if (vp->v_type == VFIFO) { 3917c478bd9Sstevel@tonic-gate error = ESPIPE; 3927c478bd9Sstevel@tonic-gate goto out; 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate /* 3967c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 3977c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 3987c478bd9Sstevel@tonic-gate */ 3997c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 4007c478bd9Sstevel@tonic-gate int svmand; 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 4037c478bd9Sstevel@tonic-gate in_crit = 1; 4047c478bd9Sstevel@tonic-gate error = nbl_svmand(vp, fp->f_cred, &svmand); 4057c478bd9Sstevel@tonic-gate if (error != 0) 4067c478bd9Sstevel@tonic-gate goto out; 407*da6c28aaSamw if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand, 408*da6c28aaSamw NULL)) { 4097c478bd9Sstevel@tonic-gate error = EACCES; 4107c478bd9Sstevel@tonic-gate goto out; 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate aiov.iov_base = cbuf; 4157c478bd9Sstevel@tonic-gate aiov.iov_len = bcount; 4167c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 4177c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && fileoff == (u_offset_t)maxoff) { 4187c478bd9Sstevel@tonic-gate struct vattr va; 4197c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE; 420*da6c28aaSamw if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred, NULL))) { 4217c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 4227c478bd9Sstevel@tonic-gate goto out; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate /* 4277c478bd9Sstevel@tonic-gate * We have to return EOF if fileoff is >= file size. 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate if (fileoff >= va.va_size) { 4307c478bd9Sstevel@tonic-gate bcount = 0; 4317c478bd9Sstevel@tonic-gate goto out; 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* 4357c478bd9Sstevel@tonic-gate * File is greater than or equal to maxoff and therefore 4367c478bd9Sstevel@tonic-gate * we return EOVERFLOW. 4377c478bd9Sstevel@tonic-gate */ 4387c478bd9Sstevel@tonic-gate error = EOVERFLOW; 4397c478bd9Sstevel@tonic-gate goto out; 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 4427c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 4437c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 4447c478bd9Sstevel@tonic-gate auio.uio_resid = bcount; 4457c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 4467c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 4477c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 4487c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */ 4537c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 4547c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 4557c478bd9Sstevel@tonic-gate error = VOP_READ(vp, &auio, ioflag, fp->f_cred, NULL); 4567c478bd9Sstevel@tonic-gate bcount -= auio.uio_resid; 4577c478bd9Sstevel@tonic-gate CPU_STATS_ENTER_K(); 4587c478bd9Sstevel@tonic-gate cp = CPU; 4597c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, sysread, 1); 4607c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, readch, (ulong_t)bcount); 4617c478bd9Sstevel@tonic-gate CPU_STATS_EXIT_K(); 4627c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)bcount; 4637c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate if (error == EINTR && bcount != 0) 4667c478bd9Sstevel@tonic-gate error = 0; 4677c478bd9Sstevel@tonic-gate out: 4687c478bd9Sstevel@tonic-gate if (in_crit) 4697c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 4707c478bd9Sstevel@tonic-gate releasef(fdes); 4717c478bd9Sstevel@tonic-gate if (error) 4727c478bd9Sstevel@tonic-gate return (set_errno(error)); 4737c478bd9Sstevel@tonic-gate return (bcount); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate ssize_t 4777c478bd9Sstevel@tonic-gate pwrite(int fdes, void *cbuf, size_t count, off_t offset) 4787c478bd9Sstevel@tonic-gate { 4797c478bd9Sstevel@tonic-gate struct uio auio; 4807c478bd9Sstevel@tonic-gate struct iovec aiov; 4817c478bd9Sstevel@tonic-gate file_t *fp; 4827c478bd9Sstevel@tonic-gate register vnode_t *vp; 4837c478bd9Sstevel@tonic-gate struct cpu *cp; 4847c478bd9Sstevel@tonic-gate int fflag, ioflag, rwflag; 4857c478bd9Sstevel@tonic-gate ssize_t bcount; 4867c478bd9Sstevel@tonic-gate int error = 0; 4877c478bd9Sstevel@tonic-gate u_offset_t fileoff = (u_offset_t)(ulong_t)offset; 4887c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 4897c478bd9Sstevel@tonic-gate u_offset_t maxoff = get_udatamodel() == DATAMODEL_ILP32 ? 4907c478bd9Sstevel@tonic-gate MAXOFF32_T : MAXOFFSET_T; 4917c478bd9Sstevel@tonic-gate #else 4927c478bd9Sstevel@tonic-gate const u_offset_t maxoff = MAXOFF32_T; 4937c478bd9Sstevel@tonic-gate #endif 4947c478bd9Sstevel@tonic-gate int in_crit = 0; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate if ((bcount = (ssize_t)count) < 0) 4977c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 4987c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 4997c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); 5007c478bd9Sstevel@tonic-gate if (((fflag = fp->f_flag) & (FWRITE)) == 0) { 5017c478bd9Sstevel@tonic-gate error = EBADF; 5027c478bd9Sstevel@tonic-gate goto out; 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate rwflag = 1; 5067c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) { 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate if (bcount == 0) 5117c478bd9Sstevel@tonic-gate goto out; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * return EINVAL for offsets that cannot be 5157c478bd9Sstevel@tonic-gate * represented in an off_t. 5167c478bd9Sstevel@tonic-gate */ 5177c478bd9Sstevel@tonic-gate if (fileoff > maxoff) { 5187c478bd9Sstevel@tonic-gate error = EINVAL; 5197c478bd9Sstevel@tonic-gate goto out; 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * Take appropriate action if we are trying to write above the 5237c478bd9Sstevel@tonic-gate * resource limit. 5247c478bd9Sstevel@tonic-gate */ 5257c478bd9Sstevel@tonic-gate if (fileoff >= curproc->p_fsz_ctl) { 5267c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 5277c478bd9Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], 5287c478bd9Sstevel@tonic-gate curproc->p_rctls, curproc, RCA_UNSAFE_SIGINFO); 5297c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate error = EFBIG; 5327c478bd9Sstevel@tonic-gate goto out; 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate /* 5357c478bd9Sstevel@tonic-gate * Don't allow pwrite to cause file sizes to exceed 5367c478bd9Sstevel@tonic-gate * maxoff. 5377c478bd9Sstevel@tonic-gate */ 5387c478bd9Sstevel@tonic-gate if (fileoff == maxoff) { 5397c478bd9Sstevel@tonic-gate error = EFBIG; 5407c478bd9Sstevel@tonic-gate goto out; 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate if (fileoff + count > maxoff) 5437c478bd9Sstevel@tonic-gate bcount = (ssize_t)((u_offset_t)maxoff - fileoff); 5447c478bd9Sstevel@tonic-gate } else if (vp->v_type == VFIFO) { 5457c478bd9Sstevel@tonic-gate error = ESPIPE; 5467c478bd9Sstevel@tonic-gate goto out; 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 5517c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 5547c478bd9Sstevel@tonic-gate int svmand; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 5577c478bd9Sstevel@tonic-gate in_crit = 1; 5587c478bd9Sstevel@tonic-gate error = nbl_svmand(vp, fp->f_cred, &svmand); 5597c478bd9Sstevel@tonic-gate if (error != 0) 5607c478bd9Sstevel@tonic-gate goto out; 561*da6c28aaSamw if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand, 562*da6c28aaSamw NULL)) { 5637c478bd9Sstevel@tonic-gate error = EACCES; 5647c478bd9Sstevel@tonic-gate goto out; 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate aiov.iov_base = cbuf; 5697c478bd9Sstevel@tonic-gate aiov.iov_len = bcount; 5707c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 5717c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 5727c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 5737c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 5747c478bd9Sstevel@tonic-gate auio.uio_resid = bcount; 5757c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 5767c478bd9Sstevel@tonic-gate auio.uio_llimit = curproc->p_fsz_ctl; 5777c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 5787c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate error = VOP_WRITE(vp, &auio, ioflag, fp->f_cred, NULL); 5837c478bd9Sstevel@tonic-gate bcount -= auio.uio_resid; 5847c478bd9Sstevel@tonic-gate CPU_STATS_ENTER_K(); 5857c478bd9Sstevel@tonic-gate cp = CPU; 5867c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, syswrite, 1); 5877c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, writech, (ulong_t)bcount); 5887c478bd9Sstevel@tonic-gate CPU_STATS_EXIT_K(); 5897c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)bcount; 5907c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate if (error == EINTR && bcount != 0) 5937c478bd9Sstevel@tonic-gate error = 0; 5947c478bd9Sstevel@tonic-gate out: 5957c478bd9Sstevel@tonic-gate if (in_crit) 5967c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 5977c478bd9Sstevel@tonic-gate releasef(fdes); 5987c478bd9Sstevel@tonic-gate if (error) 5997c478bd9Sstevel@tonic-gate return (set_errno(error)); 6007c478bd9Sstevel@tonic-gate return (bcount); 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* 6047c478bd9Sstevel@tonic-gate * XXX -- The SVID refers to IOV_MAX, but doesn't define it. Grrrr.... 6057c478bd9Sstevel@tonic-gate * XXX -- However, SVVS expects readv() and writev() to fail if 6067c478bd9Sstevel@tonic-gate * XXX -- iovcnt > 16 (yes, it's hard-coded in the SVVS source), 6077c478bd9Sstevel@tonic-gate * XXX -- so I guess that's the "interface". 6087c478bd9Sstevel@tonic-gate */ 6097c478bd9Sstevel@tonic-gate #define DEF_IOV_MAX 16 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate ssize_t 6127c478bd9Sstevel@tonic-gate readv(int fdes, struct iovec *iovp, int iovcnt) 6137c478bd9Sstevel@tonic-gate { 6147c478bd9Sstevel@tonic-gate struct uio auio; 6157c478bd9Sstevel@tonic-gate struct iovec aiov[DEF_IOV_MAX]; 6167c478bd9Sstevel@tonic-gate file_t *fp; 6177c478bd9Sstevel@tonic-gate register vnode_t *vp; 6187c478bd9Sstevel@tonic-gate struct cpu *cp; 6197c478bd9Sstevel@tonic-gate int fflag, ioflag, rwflag; 6207c478bd9Sstevel@tonic-gate ssize_t count, bcount; 6217c478bd9Sstevel@tonic-gate int error = 0; 6227c478bd9Sstevel@tonic-gate int i; 6237c478bd9Sstevel@tonic-gate u_offset_t fileoff; 6247c478bd9Sstevel@tonic-gate int in_crit = 0; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX) 6277c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 6307c478bd9Sstevel@tonic-gate /* 6317c478bd9Sstevel@tonic-gate * 32-bit callers need to have their iovec expanded, 6327c478bd9Sstevel@tonic-gate * while ensuring that they can't move more than 2Gbytes 6337c478bd9Sstevel@tonic-gate * of data in a single call. 6347c478bd9Sstevel@tonic-gate */ 6357c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_ILP32) { 6367c478bd9Sstevel@tonic-gate struct iovec32 aiov32[DEF_IOV_MAX]; 6377c478bd9Sstevel@tonic-gate ssize32_t count32; 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32))) 6407c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate count32 = 0; 6437c478bd9Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) { 6447c478bd9Sstevel@tonic-gate ssize32_t iovlen32 = aiov32[i].iov_len; 6457c478bd9Sstevel@tonic-gate count32 += iovlen32; 6467c478bd9Sstevel@tonic-gate if (iovlen32 < 0 || count32 < 0) 6477c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 6487c478bd9Sstevel@tonic-gate aiov[i].iov_len = iovlen32; 6497c478bd9Sstevel@tonic-gate aiov[i].iov_base = 6507c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)aiov32[i].iov_base; 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate } else 6537c478bd9Sstevel@tonic-gate #endif 6547c478bd9Sstevel@tonic-gate if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec))) 6557c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate count = 0; 6587c478bd9Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) { 6597c478bd9Sstevel@tonic-gate ssize_t iovlen = aiov[i].iov_len; 6607c478bd9Sstevel@tonic-gate count += iovlen; 6617c478bd9Sstevel@tonic-gate if (iovlen < 0 || count < 0) 6627c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 6657c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); 6667c478bd9Sstevel@tonic-gate if (((fflag = fp->f_flag) & FREAD) == 0) { 6677c478bd9Sstevel@tonic-gate error = EBADF; 6687c478bd9Sstevel@tonic-gate goto out; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 6717c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && count == 0) { 6727c478bd9Sstevel@tonic-gate goto out; 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate rwflag = 0; 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 6797c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 6807c478bd9Sstevel@tonic-gate */ 6817c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 6827c478bd9Sstevel@tonic-gate int svmand; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 6857c478bd9Sstevel@tonic-gate in_crit = 1; 6867c478bd9Sstevel@tonic-gate error = nbl_svmand(vp, fp->f_cred, &svmand); 6877c478bd9Sstevel@tonic-gate if (error != 0) 6887c478bd9Sstevel@tonic-gate goto out; 689*da6c28aaSamw if (nbl_conflict(vp, NBL_READ, fp->f_offset, count, svmand, 690*da6c28aaSamw NULL)) { 6917c478bd9Sstevel@tonic-gate error = EACCES; 6927c478bd9Sstevel@tonic-gate goto out; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 6977c478bd9Sstevel@tonic-gate fileoff = fp->f_offset; 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /* 7007c478bd9Sstevel@tonic-gate * Behaviour is same as read. Please see comments in read. 7017c478bd9Sstevel@tonic-gate */ 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate if ((vp->v_type == VREG) && (fileoff >= OFFSET_MAX(fp))) { 7047c478bd9Sstevel@tonic-gate struct vattr va; 7057c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE; 706*da6c28aaSamw if ((error = VOP_GETATTR(vp, &va, 0, fp->f_cred, NULL))) { 7077c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 7087c478bd9Sstevel@tonic-gate goto out; 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate if (fileoff >= va.va_size) { 7117c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 7127c478bd9Sstevel@tonic-gate count = 0; 7137c478bd9Sstevel@tonic-gate goto out; 7147c478bd9Sstevel@tonic-gate } else { 7157c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 7167c478bd9Sstevel@tonic-gate error = EOVERFLOW; 7177c478bd9Sstevel@tonic-gate goto out; 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate if ((vp->v_type == VREG) && (fileoff + count > OFFSET_MAX(fp))) { 7217c478bd9Sstevel@tonic-gate count = (ssize_t)(OFFSET_MAX(fp) - fileoff); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 7247c478bd9Sstevel@tonic-gate auio.uio_iov = aiov; 7257c478bd9Sstevel@tonic-gate auio.uio_iovcnt = iovcnt; 7267c478bd9Sstevel@tonic-gate auio.uio_resid = bcount = count; 7277c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 7287c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 7297c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 73013506d1eSmaybee if (bcount <= copyout_max_cached) 7317c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 7327c478bd9Sstevel@tonic-gate else 7337c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_DEFAULT; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */ 7397c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 7407c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 7417c478bd9Sstevel@tonic-gate error = VOP_READ(vp, &auio, ioflag, fp->f_cred, NULL); 7427c478bd9Sstevel@tonic-gate count -= auio.uio_resid; 7437c478bd9Sstevel@tonic-gate CPU_STATS_ENTER_K(); 7447c478bd9Sstevel@tonic-gate cp = CPU; 7457c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, sysread, 1); 7467c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, readch, (ulong_t)count); 7477c478bd9Sstevel@tonic-gate CPU_STATS_EXIT_K(); 7487c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)count; 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate if (vp->v_type == VFIFO) /* Backward compatibility */ 7517c478bd9Sstevel@tonic-gate fp->f_offset = count; 7527c478bd9Sstevel@tonic-gate else if (((fp->f_flag & FAPPEND) == 0) || 7537c478bd9Sstevel@tonic-gate (vp->v_type != VREG) || (bcount != 0)) /* POSIX */ 7547c478bd9Sstevel@tonic-gate fp->f_offset = auio.uio_loffset; 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate if (error == EINTR && count != 0) 7597c478bd9Sstevel@tonic-gate error = 0; 7607c478bd9Sstevel@tonic-gate out: 7617c478bd9Sstevel@tonic-gate if (in_crit) 7627c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 7637c478bd9Sstevel@tonic-gate releasef(fdes); 7647c478bd9Sstevel@tonic-gate if (error) 7657c478bd9Sstevel@tonic-gate return (set_errno(error)); 7667c478bd9Sstevel@tonic-gate return (count); 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate ssize_t 7707c478bd9Sstevel@tonic-gate writev(int fdes, struct iovec *iovp, int iovcnt) 7717c478bd9Sstevel@tonic-gate { 7727c478bd9Sstevel@tonic-gate struct uio auio; 7737c478bd9Sstevel@tonic-gate struct iovec aiov[DEF_IOV_MAX]; 7747c478bd9Sstevel@tonic-gate file_t *fp; 7757c478bd9Sstevel@tonic-gate register vnode_t *vp; 7767c478bd9Sstevel@tonic-gate struct cpu *cp; 7777c478bd9Sstevel@tonic-gate int fflag, ioflag, rwflag; 7787c478bd9Sstevel@tonic-gate ssize_t count, bcount; 7797c478bd9Sstevel@tonic-gate int error = 0; 7807c478bd9Sstevel@tonic-gate int i; 7817c478bd9Sstevel@tonic-gate u_offset_t fileoff; 7827c478bd9Sstevel@tonic-gate int in_crit = 0; 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate if (iovcnt <= 0 || iovcnt > DEF_IOV_MAX) 7857c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * 32-bit callers need to have their iovec expanded, 7907c478bd9Sstevel@tonic-gate * while ensuring that they can't move more than 2Gbytes 7917c478bd9Sstevel@tonic-gate * of data in a single call. 7927c478bd9Sstevel@tonic-gate */ 7937c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_ILP32) { 7947c478bd9Sstevel@tonic-gate struct iovec32 aiov32[DEF_IOV_MAX]; 7957c478bd9Sstevel@tonic-gate ssize32_t count32; 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate if (copyin(iovp, aiov32, iovcnt * sizeof (struct iovec32))) 7987c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate count32 = 0; 8017c478bd9Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) { 8027c478bd9Sstevel@tonic-gate ssize32_t iovlen = aiov32[i].iov_len; 8037c478bd9Sstevel@tonic-gate count32 += iovlen; 8047c478bd9Sstevel@tonic-gate if (iovlen < 0 || count32 < 0) 8057c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 8067c478bd9Sstevel@tonic-gate aiov[i].iov_len = iovlen; 8077c478bd9Sstevel@tonic-gate aiov[i].iov_base = 8087c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)aiov32[i].iov_base; 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate } else 8117c478bd9Sstevel@tonic-gate #endif 8127c478bd9Sstevel@tonic-gate if (copyin(iovp, aiov, iovcnt * sizeof (struct iovec))) 8137c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate count = 0; 8167c478bd9Sstevel@tonic-gate for (i = 0; i < iovcnt; i++) { 8177c478bd9Sstevel@tonic-gate ssize_t iovlen = aiov[i].iov_len; 8187c478bd9Sstevel@tonic-gate count += iovlen; 8197c478bd9Sstevel@tonic-gate if (iovlen < 0 || count < 0) 8207c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 8237c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); 8247c478bd9Sstevel@tonic-gate if (((fflag = fp->f_flag) & FWRITE) == 0) { 8257c478bd9Sstevel@tonic-gate error = EBADF; 8267c478bd9Sstevel@tonic-gate goto out; 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 8297c478bd9Sstevel@tonic-gate if (vp->v_type == VREG && count == 0) { 8307c478bd9Sstevel@tonic-gate goto out; 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate rwflag = 1; 8347c478bd9Sstevel@tonic-gate 8357c478bd9Sstevel@tonic-gate /* 8367c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 8377c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 8387c478bd9Sstevel@tonic-gate */ 8397c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 8407c478bd9Sstevel@tonic-gate int svmand; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 8437c478bd9Sstevel@tonic-gate in_crit = 1; 8447c478bd9Sstevel@tonic-gate error = nbl_svmand(vp, fp->f_cred, &svmand); 8457c478bd9Sstevel@tonic-gate if (error != 0) 8467c478bd9Sstevel@tonic-gate goto out; 847*da6c28aaSamw if (nbl_conflict(vp, NBL_WRITE, fp->f_offset, count, svmand, 848*da6c28aaSamw NULL)) { 8497c478bd9Sstevel@tonic-gate error = EACCES; 8507c478bd9Sstevel@tonic-gate goto out; 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate } 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate fileoff = fp->f_offset; 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate /* 8597c478bd9Sstevel@tonic-gate * Behaviour is same as write. Please see comments for write. 8607c478bd9Sstevel@tonic-gate */ 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) { 8637c478bd9Sstevel@tonic-gate if (fileoff >= curproc->p_fsz_ctl) { 8647c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 8657c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 8667c478bd9Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], 8677c478bd9Sstevel@tonic-gate curproc->p_rctls, curproc, RCA_UNSAFE_SIGINFO); 8687c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 8697c478bd9Sstevel@tonic-gate error = EFBIG; 8707c478bd9Sstevel@tonic-gate goto out; 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate if (fileoff >= OFFSET_MAX(fp)) { 8737c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 8747c478bd9Sstevel@tonic-gate error = EFBIG; 8757c478bd9Sstevel@tonic-gate goto out; 8767c478bd9Sstevel@tonic-gate } 8777c478bd9Sstevel@tonic-gate if (fileoff + count > OFFSET_MAX(fp)) 8787c478bd9Sstevel@tonic-gate count = (ssize_t)(OFFSET_MAX(fp) - fileoff); 8797c478bd9Sstevel@tonic-gate } 8807c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 8817c478bd9Sstevel@tonic-gate auio.uio_iov = aiov; 8827c478bd9Sstevel@tonic-gate auio.uio_iovcnt = iovcnt; 8837c478bd9Sstevel@tonic-gate auio.uio_resid = bcount = count; 8847c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 8857c478bd9Sstevel@tonic-gate auio.uio_llimit = curproc->p_fsz_ctl; 8867c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 8877c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_DEFAULT; 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate error = VOP_WRITE(vp, &auio, ioflag, fp->f_cred, NULL); 8927c478bd9Sstevel@tonic-gate count -= auio.uio_resid; 8937c478bd9Sstevel@tonic-gate CPU_STATS_ENTER_K(); 8947c478bd9Sstevel@tonic-gate cp = CPU; 8957c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, syswrite, 1); 8967c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, writech, (ulong_t)count); 8977c478bd9Sstevel@tonic-gate CPU_STATS_EXIT_K(); 8987c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)count; 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate if (vp->v_type == VFIFO) /* Backward compatibility */ 9017c478bd9Sstevel@tonic-gate fp->f_offset = count; 9027c478bd9Sstevel@tonic-gate else if (((fp->f_flag & FAPPEND) == 0) || 9037c478bd9Sstevel@tonic-gate (vp->v_type != VREG) || (bcount != 0)) /* POSIX */ 9047c478bd9Sstevel@tonic-gate fp->f_offset = auio.uio_loffset; 9057c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate if (error == EINTR && count != 0) 9087c478bd9Sstevel@tonic-gate error = 0; 9097c478bd9Sstevel@tonic-gate out: 9107c478bd9Sstevel@tonic-gate if (in_crit) 9117c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 9127c478bd9Sstevel@tonic-gate releasef(fdes); 9137c478bd9Sstevel@tonic-gate if (error) 9147c478bd9Sstevel@tonic-gate return (set_errno(error)); 9157c478bd9Sstevel@tonic-gate return (count); 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) || defined(_ILP32) 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate /* 9217c478bd9Sstevel@tonic-gate * This syscall supplies 64-bit file offsets to 32-bit applications only. 9227c478bd9Sstevel@tonic-gate */ 9237c478bd9Sstevel@tonic-gate ssize32_t 9247c478bd9Sstevel@tonic-gate pread64(int fdes, void *cbuf, size32_t count, uint32_t offset_1, 9257c478bd9Sstevel@tonic-gate uint32_t offset_2) 9267c478bd9Sstevel@tonic-gate { 9277c478bd9Sstevel@tonic-gate struct uio auio; 9287c478bd9Sstevel@tonic-gate struct iovec aiov; 9297c478bd9Sstevel@tonic-gate file_t *fp; 9307c478bd9Sstevel@tonic-gate register vnode_t *vp; 9317c478bd9Sstevel@tonic-gate struct cpu *cp; 9327c478bd9Sstevel@tonic-gate int fflag, ioflag, rwflag; 9337c478bd9Sstevel@tonic-gate ssize_t bcount; 9347c478bd9Sstevel@tonic-gate int error = 0; 9357c478bd9Sstevel@tonic-gate u_offset_t fileoff; 9367c478bd9Sstevel@tonic-gate int in_crit = 0; 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN) 9397c478bd9Sstevel@tonic-gate fileoff = ((u_offset_t)offset_2 << 32) | (u_offset_t)offset_1; 9407c478bd9Sstevel@tonic-gate #else 9417c478bd9Sstevel@tonic-gate fileoff = ((u_offset_t)offset_1 << 32) | (u_offset_t)offset_2; 9427c478bd9Sstevel@tonic-gate #endif 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate if ((bcount = (ssize_t)count) < 0 || bcount > INT32_MAX) 9457c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 9487c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); 9497c478bd9Sstevel@tonic-gate if (((fflag = fp->f_flag) & (FREAD)) == 0) { 9507c478bd9Sstevel@tonic-gate error = EBADF; 9517c478bd9Sstevel@tonic-gate goto out; 9527c478bd9Sstevel@tonic-gate } 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate rwflag = 0; 9557c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) { 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate if (bcount == 0) 9607c478bd9Sstevel@tonic-gate goto out; 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate /* 9637c478bd9Sstevel@tonic-gate * Same as pread. See comments in pread. 9647c478bd9Sstevel@tonic-gate */ 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate if (fileoff > MAXOFFSET_T) { 9677c478bd9Sstevel@tonic-gate error = EINVAL; 9687c478bd9Sstevel@tonic-gate goto out; 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate if (fileoff + bcount > MAXOFFSET_T) 9717c478bd9Sstevel@tonic-gate bcount = (ssize_t)(MAXOFFSET_T - fileoff); 9727c478bd9Sstevel@tonic-gate } else if (vp->v_type == VFIFO) { 9737c478bd9Sstevel@tonic-gate error = ESPIPE; 9747c478bd9Sstevel@tonic-gate goto out; 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate /* 9787c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 9797c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 9807c478bd9Sstevel@tonic-gate */ 9817c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 9827c478bd9Sstevel@tonic-gate int svmand; 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 9857c478bd9Sstevel@tonic-gate in_crit = 1; 9867c478bd9Sstevel@tonic-gate error = nbl_svmand(vp, fp->f_cred, &svmand); 9877c478bd9Sstevel@tonic-gate if (error != 0) 9887c478bd9Sstevel@tonic-gate goto out; 989*da6c28aaSamw if (nbl_conflict(vp, NBL_READ, fileoff, bcount, svmand, 990*da6c28aaSamw NULL)) { 9917c478bd9Sstevel@tonic-gate error = EACCES; 9927c478bd9Sstevel@tonic-gate goto out; 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate } 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate aiov.iov_base = cbuf; 9977c478bd9Sstevel@tonic-gate aiov.iov_len = bcount; 9987c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 9997c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* 10027c478bd9Sstevel@tonic-gate * Note: File size can never be greater than MAXOFFSET_T. 10037c478bd9Sstevel@tonic-gate * If ever we start supporting 128 bit files the code 10047c478bd9Sstevel@tonic-gate * similar to the one in pread at this place should be here. 10057c478bd9Sstevel@tonic-gate * Here we avoid the unnecessary VOP_GETATTR() when we 10067c478bd9Sstevel@tonic-gate * know that fileoff == MAXOFFSET_T implies that it is always 10077c478bd9Sstevel@tonic-gate * greater than or equal to file size. 10087c478bd9Sstevel@tonic-gate */ 10097c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 10107c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 10117c478bd9Sstevel@tonic-gate auio.uio_resid = bcount; 10127c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 10137c478bd9Sstevel@tonic-gate auio.uio_llimit = MAXOFFSET_T; 10147c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 10157c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 10167c478bd9Sstevel@tonic-gate 10177c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* If read sync is not asked for, filter sync flags */ 10207c478bd9Sstevel@tonic-gate if ((ioflag & FRSYNC) == 0) 10217c478bd9Sstevel@tonic-gate ioflag &= ~(FSYNC|FDSYNC); 10227c478bd9Sstevel@tonic-gate error = VOP_READ(vp, &auio, ioflag, fp->f_cred, NULL); 10237c478bd9Sstevel@tonic-gate bcount -= auio.uio_resid; 10247c478bd9Sstevel@tonic-gate CPU_STATS_ENTER_K(); 10257c478bd9Sstevel@tonic-gate cp = CPU; 10267c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, sysread, 1); 10277c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, readch, (ulong_t)bcount); 10287c478bd9Sstevel@tonic-gate CPU_STATS_EXIT_K(); 10297c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)bcount; 10307c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate if (error == EINTR && bcount != 0) 10337c478bd9Sstevel@tonic-gate error = 0; 10347c478bd9Sstevel@tonic-gate out: 10357c478bd9Sstevel@tonic-gate if (in_crit) 10367c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 10377c478bd9Sstevel@tonic-gate releasef(fdes); 10387c478bd9Sstevel@tonic-gate if (error) 10397c478bd9Sstevel@tonic-gate return (set_errno(error)); 10407c478bd9Sstevel@tonic-gate return (bcount); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate /* 10447c478bd9Sstevel@tonic-gate * This syscall supplies 64-bit file offsets to 32-bit applications only. 10457c478bd9Sstevel@tonic-gate */ 10467c478bd9Sstevel@tonic-gate ssize32_t 10477c478bd9Sstevel@tonic-gate pwrite64(int fdes, void *cbuf, size32_t count, uint32_t offset_1, 10487c478bd9Sstevel@tonic-gate uint32_t offset_2) 10497c478bd9Sstevel@tonic-gate { 10507c478bd9Sstevel@tonic-gate struct uio auio; 10517c478bd9Sstevel@tonic-gate struct iovec aiov; 10527c478bd9Sstevel@tonic-gate file_t *fp; 10537c478bd9Sstevel@tonic-gate register vnode_t *vp; 10547c478bd9Sstevel@tonic-gate struct cpu *cp; 10557c478bd9Sstevel@tonic-gate int fflag, ioflag, rwflag; 10567c478bd9Sstevel@tonic-gate ssize_t bcount; 10577c478bd9Sstevel@tonic-gate int error = 0; 10587c478bd9Sstevel@tonic-gate u_offset_t fileoff; 10597c478bd9Sstevel@tonic-gate int in_crit = 0; 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate #if defined(_LITTLE_ENDIAN) 10627c478bd9Sstevel@tonic-gate fileoff = ((u_offset_t)offset_2 << 32) | (u_offset_t)offset_1; 10637c478bd9Sstevel@tonic-gate #else 10647c478bd9Sstevel@tonic-gate fileoff = ((u_offset_t)offset_1 << 32) | (u_offset_t)offset_2; 10657c478bd9Sstevel@tonic-gate #endif 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate if ((bcount = (ssize_t)count) < 0 || bcount > INT32_MAX) 10687c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 10697c478bd9Sstevel@tonic-gate if ((fp = getf(fdes)) == NULL) 10707c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); 10717c478bd9Sstevel@tonic-gate if (((fflag = fp->f_flag) & (FWRITE)) == 0) { 10727c478bd9Sstevel@tonic-gate error = EBADF; 10737c478bd9Sstevel@tonic-gate goto out; 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate rwflag = 1; 10777c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate if (vp->v_type == VREG) { 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate if (bcount == 0) 10827c478bd9Sstevel@tonic-gate goto out; 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate /* 10857c478bd9Sstevel@tonic-gate * See comments in pwrite. 10867c478bd9Sstevel@tonic-gate */ 10877c478bd9Sstevel@tonic-gate if (fileoff > MAXOFFSET_T) { 10887c478bd9Sstevel@tonic-gate error = EINVAL; 10897c478bd9Sstevel@tonic-gate goto out; 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate if (fileoff >= curproc->p_fsz_ctl) { 10927c478bd9Sstevel@tonic-gate mutex_enter(&curproc->p_lock); 10937c478bd9Sstevel@tonic-gate (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], 10947c478bd9Sstevel@tonic-gate curproc->p_rctls, curproc, RCA_SAFE); 10957c478bd9Sstevel@tonic-gate mutex_exit(&curproc->p_lock); 10967c478bd9Sstevel@tonic-gate error = EFBIG; 10977c478bd9Sstevel@tonic-gate goto out; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate if (fileoff == MAXOFFSET_T) { 11007c478bd9Sstevel@tonic-gate error = EFBIG; 11017c478bd9Sstevel@tonic-gate goto out; 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate if (fileoff + bcount > MAXOFFSET_T) 11047c478bd9Sstevel@tonic-gate bcount = (ssize_t)((u_offset_t)MAXOFFSET_T - fileoff); 11057c478bd9Sstevel@tonic-gate } else if (vp->v_type == VFIFO) { 11067c478bd9Sstevel@tonic-gate error = ESPIPE; 11077c478bd9Sstevel@tonic-gate goto out; 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate /* 11117c478bd9Sstevel@tonic-gate * We have to enter the critical region before calling VOP_RWLOCK 11127c478bd9Sstevel@tonic-gate * to avoid a deadlock with ufs. 11137c478bd9Sstevel@tonic-gate */ 11147c478bd9Sstevel@tonic-gate if (nbl_need_check(vp)) { 11157c478bd9Sstevel@tonic-gate int svmand; 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate nbl_start_crit(vp, RW_READER); 11187c478bd9Sstevel@tonic-gate in_crit = 1; 11197c478bd9Sstevel@tonic-gate error = nbl_svmand(vp, fp->f_cred, &svmand); 11207c478bd9Sstevel@tonic-gate if (error != 0) 11217c478bd9Sstevel@tonic-gate goto out; 1122*da6c28aaSamw if (nbl_conflict(vp, NBL_WRITE, fileoff, bcount, svmand, 1123*da6c28aaSamw NULL)) { 11247c478bd9Sstevel@tonic-gate error = EACCES; 11257c478bd9Sstevel@tonic-gate goto out; 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate aiov.iov_base = cbuf; 11307c478bd9Sstevel@tonic-gate aiov.iov_len = bcount; 11317c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, rwflag, NULL); 11327c478bd9Sstevel@tonic-gate auio.uio_loffset = fileoff; 11337c478bd9Sstevel@tonic-gate auio.uio_iov = &aiov; 11347c478bd9Sstevel@tonic-gate auio.uio_iovcnt = 1; 11357c478bd9Sstevel@tonic-gate auio.uio_resid = bcount; 11367c478bd9Sstevel@tonic-gate auio.uio_segflg = UIO_USERSPACE; 11377c478bd9Sstevel@tonic-gate auio.uio_llimit = curproc->p_fsz_ctl; 11387c478bd9Sstevel@tonic-gate auio.uio_fmode = fflag; 11397c478bd9Sstevel@tonic-gate auio.uio_extflg = UIO_COPY_CACHED; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate ioflag = auio.uio_fmode & (FAPPEND|FSYNC|FDSYNC|FRSYNC); 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate error = VOP_WRITE(vp, &auio, ioflag, fp->f_cred, NULL); 11447c478bd9Sstevel@tonic-gate bcount -= auio.uio_resid; 11457c478bd9Sstevel@tonic-gate CPU_STATS_ENTER_K(); 11467c478bd9Sstevel@tonic-gate cp = CPU; 11477c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, syswrite, 1); 11487c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(cp, sys, writech, (ulong_t)bcount); 11497c478bd9Sstevel@tonic-gate CPU_STATS_EXIT_K(); 11507c478bd9Sstevel@tonic-gate ttolwp(curthread)->lwp_ru.ioch += (ulong_t)bcount; 11517c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, rwflag, NULL); 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate if (error == EINTR && bcount != 0) 11547c478bd9Sstevel@tonic-gate error = 0; 11557c478bd9Sstevel@tonic-gate out: 11567c478bd9Sstevel@tonic-gate if (in_crit) 11577c478bd9Sstevel@tonic-gate nbl_end_crit(vp); 11587c478bd9Sstevel@tonic-gate releasef(fdes); 11597c478bd9Sstevel@tonic-gate if (error) 11607c478bd9Sstevel@tonic-gate return (set_errno(error)); 11617c478bd9Sstevel@tonic-gate return (bcount); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL || _ILP32 */ 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 11677c478bd9Sstevel@tonic-gate /* 11687c478bd9Sstevel@tonic-gate * Tail-call elimination of xxx32() down to xxx() 11697c478bd9Sstevel@tonic-gate * 11707c478bd9Sstevel@tonic-gate * A number of xxx32 system calls take a len (or count) argument and 11717c478bd9Sstevel@tonic-gate * return a number in the range [0,len] or -1 on error. 11727c478bd9Sstevel@tonic-gate * Given an ssize32_t input len, the downcall xxx() will return 11737c478bd9Sstevel@tonic-gate * a 64-bit value that is -1 or in the range [0,len] which actually 11747c478bd9Sstevel@tonic-gate * is a proper return value for the xxx32 call. So even if the xxx32 11757c478bd9Sstevel@tonic-gate * calls can be considered as returning a ssize32_t, they are currently 11767c478bd9Sstevel@tonic-gate * declared as returning a ssize_t as this enables tail-call elimination. 11777c478bd9Sstevel@tonic-gate * 11787c478bd9Sstevel@tonic-gate * The cast of len (or count) to ssize32_t is needed to ensure we pass 11797c478bd9Sstevel@tonic-gate * down negative input values as such and let the downcall handle error 11807c478bd9Sstevel@tonic-gate * reporting. Functions covered by this comments are: 11817c478bd9Sstevel@tonic-gate * 11827c478bd9Sstevel@tonic-gate * rw.c: read32, write32, pread32, pwrite32, readv32, writev32. 11837c478bd9Sstevel@tonic-gate * socksyscall.c: recv32, recvfrom32, send32, sendto32. 11847c478bd9Sstevel@tonic-gate * readlink.c: readlink32. 11857c478bd9Sstevel@tonic-gate */ 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate ssize_t 11887c478bd9Sstevel@tonic-gate read32(int32_t fdes, caddr32_t cbuf, size32_t count) 11897c478bd9Sstevel@tonic-gate { 11907c478bd9Sstevel@tonic-gate return (read(fdes, 11917c478bd9Sstevel@tonic-gate (void *)(uintptr_t)cbuf, (ssize32_t)count)); 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate ssize_t 11957c478bd9Sstevel@tonic-gate write32(int32_t fdes, caddr32_t cbuf, size32_t count) 11967c478bd9Sstevel@tonic-gate { 11977c478bd9Sstevel@tonic-gate return (write(fdes, 11987c478bd9Sstevel@tonic-gate (void *)(uintptr_t)cbuf, (ssize32_t)count)); 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate ssize_t 12027c478bd9Sstevel@tonic-gate pread32(int32_t fdes, caddr32_t cbuf, size32_t count, off32_t offset) 12037c478bd9Sstevel@tonic-gate { 12047c478bd9Sstevel@tonic-gate return (pread(fdes, 12057c478bd9Sstevel@tonic-gate (void *)(uintptr_t)cbuf, (ssize32_t)count, 12067c478bd9Sstevel@tonic-gate (off_t)(uint32_t)offset)); 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate ssize_t 12107c478bd9Sstevel@tonic-gate pwrite32(int32_t fdes, caddr32_t cbuf, size32_t count, off32_t offset) 12117c478bd9Sstevel@tonic-gate { 12127c478bd9Sstevel@tonic-gate return (pwrite(fdes, 12137c478bd9Sstevel@tonic-gate (void *)(uintptr_t)cbuf, (ssize32_t)count, 12147c478bd9Sstevel@tonic-gate (off_t)(uint32_t)offset)); 12157c478bd9Sstevel@tonic-gate } 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate ssize_t 12187c478bd9Sstevel@tonic-gate readv32(int32_t fdes, caddr32_t iovp, int32_t iovcnt) 12197c478bd9Sstevel@tonic-gate { 12207c478bd9Sstevel@tonic-gate return (readv(fdes, (void *)(uintptr_t)iovp, iovcnt)); 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate ssize_t 12247c478bd9Sstevel@tonic-gate writev32(int32_t fdes, caddr32_t iovp, int32_t iovcnt) 12257c478bd9Sstevel@tonic-gate { 12267c478bd9Sstevel@tonic-gate return (writev(fdes, (void *)(uintptr_t)iovp, iovcnt)); 12277c478bd9Sstevel@tonic-gate } 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1230