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