diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index d94941f3b5a0..9dccd954429a 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -1,4 +1,4 @@ -/* $NetBSD: sys_generic.c,v 1.101 2007/06/02 13:38:31 dsl Exp $ */ +/* $NetBSD: sys_generic.c,v 1.102 2007/06/16 20:48:03 dsl Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -37,7 +37,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: sys_generic.c,v 1.101 2007/06/02 13:38:31 dsl Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_generic.c,v 1.102 2007/06/16 20:48:03 dsl Exp $"); #include "opt_ktrace.h" @@ -53,6 +53,7 @@ __KERNEL_RCSID(0, "$NetBSD: sys_generic.c,v 1.101 2007/06/02 13:38:31 dsl Exp $" #include #include #include +#include #include #ifdef KTRACE #include @@ -174,80 +175,91 @@ sys_readv(struct lwp *l, void *v, register_t *retval) syscallarg(const struct iovec *) iovp; syscallarg(int) iovcnt; } */ *uap = v; - struct filedesc *fdp; - struct file *fp; - struct proc *p; - int fd; - fd = SCARG(uap, fd); - p = l->l_proc; - fdp = p->p_fd; - - if ((fp = fd_getfile(fdp, fd)) == NULL) - return (EBADF); - - if ((fp->f_flag & FREAD) == 0) { - simple_unlock(&fp->f_slock); - return (EBADF); - } - - FILE_USE(fp); - - /* dofilereadv() will unuse the descriptor for us */ - return (dofilereadv(l, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), - &fp->f_offset, FOF_UPDATE_OFFSET, retval)); + return do_filereadv(l, SCARG(uap, fd), SCARG(uap, iovp), + SCARG(uap, iovcnt), NULL, FOF_UPDATE_OFFSET, retval); } int -dofilereadv(struct lwp *l, int fd, struct file *fp, const struct iovec *iovp, - int iovcnt, off_t *offset, int flags, register_t *retval) +do_filereadv(struct lwp *l, int fd, const struct iovec *iovp, int iovcnt, + off_t *offset, int flags, register_t *retval) { - struct proc *p; + struct proc *p; struct uio auio; - struct iovec *iov, *needfree, aiov[UIO_SMALLIOV]; + struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; struct vmspace *vm; int i, error; size_t cnt; u_int iovlen; + struct file *fp; + struct filedesc *fdp; #ifdef KTRACE - struct iovec *ktriov; + struct iovec *ktriov = NULL; #endif + if (iovcnt == 0) + return EINVAL; + p = l->l_proc; - error = proc_vmspace_getref(p, &vm); - if (error) { - goto out; + fdp = p->p_fd; + + if ((fp = fd_getfile(fdp, fd)) == NULL) + return EBADF; + + if ((fp->f_flag & FREAD) == 0) { + simple_unlock(&fp->f_slock); + return EBADF; } -#ifdef KTRACE - ktriov = NULL; -#endif - /* note: can't use iovlen until iovcnt is validated */ - iovlen = iovcnt * sizeof(struct iovec); - if ((u_int)iovcnt > UIO_SMALLIOV) { - if ((u_int)iovcnt > IOV_MAX) { - error = EINVAL; + FILE_USE(fp); + + if (offset == NULL) + offset = &fp->f_offset; + else { + struct vnode *vp = fp->f_data; + if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { + error = ESPIPE; goto out; } - iov = malloc(iovlen, M_IOV, M_WAITOK); - needfree = iov; - } else if ((u_int)iovcnt > 0) { - iov = aiov; - needfree = NULL; - } else { - error = EINVAL; + /* + * Test that the device is seekable ? + * XXX This works because no file systems actually + * XXX take any action on the seek operation. + */ + error = VOP_SEEK(vp, fp->f_offset, *offset, fp->f_cred); + if (error != 0) + goto out; + } + + error = proc_vmspace_getref(p, &vm); + if (error) goto out; + + iovlen = iovcnt * sizeof(struct iovec); + if (flags & FOF_IOV_SYSSPACE) + iov = __UNCONST(iovp); + else { + iov = aiov; + if ((u_int)iovcnt > UIO_SMALLIOV) { + if ((u_int)iovcnt > IOV_MAX) { + error = EINVAL; + goto out; + } + iov = malloc(iovlen, M_IOV, M_WAITOK); + needfree = iov; + } + error = copyin(iovp, iov, iovlen); + if (error) + goto done; } auio.uio_iov = iov; auio.uio_iovcnt = iovcnt; auio.uio_rw = UIO_READ; auio.uio_vmspace = vm; - error = copyin(iovp, iov, iovlen); - if (error) - goto done; + auio.uio_resid = 0; - for (i = 0; i < iovcnt; i++) { + for (i = 0; i < iovcnt; i++, iov++) { auio.uio_resid += iov->iov_len; /* * Reads return ssize_t because -1 is returned on error. @@ -258,17 +270,18 @@ dofilereadv(struct lwp *l, int fd, struct file *fp, const struct iovec *iovp, error = EINVAL; goto done; } - iov++; } + #ifdef KTRACE /* * if tracing, save a copy of iovec */ if (KTRPOINT(p, KTR_GENIO)) { ktriov = malloc(iovlen, M_TEMP, M_WAITOK); - memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); + memcpy(ktriov, auio.uio_iov, iovlen); } #endif + cnt = auio.uio_resid; error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags); if (error) @@ -276,6 +289,8 @@ dofilereadv(struct lwp *l, int fd, struct file *fp, const struct iovec *iovp, error == EINTR || error == EWOULDBLOCK)) error = 0; cnt -= auio.uio_resid; + *retval = cnt; + #ifdef KTRACE if (ktriov != NULL) { if (KTRPOINT(p, KTR_GENIO) && (error == 0)) @@ -283,7 +298,7 @@ dofilereadv(struct lwp *l, int fd, struct file *fp, const struct iovec *iovp, free(ktriov, M_TEMP); } #endif - *retval = cnt; + done: if (needfree) free(needfree, M_IOV); @@ -404,79 +419,91 @@ sys_writev(struct lwp *l, void *v, register_t *retval) syscallarg(const struct iovec *) iovp; syscallarg(int) iovcnt; } */ *uap = v; - int fd; - struct file *fp; - struct proc *p; - struct filedesc *fdp; - fd = SCARG(uap, fd); - p = l->l_proc; - fdp = p->p_fd; - - if ((fp = fd_getfile(fdp, fd)) == NULL) - return (EBADF); - - if ((fp->f_flag & FWRITE) == 0) { - simple_unlock(&fp->f_slock); - return (EBADF); - } - - FILE_USE(fp); - - /* dofilewritev() will unuse the descriptor for us */ - return (dofilewritev(l, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), - &fp->f_offset, FOF_UPDATE_OFFSET, retval)); + return do_filewritev(l, SCARG(uap, fd), SCARG(uap, iovp), + SCARG(uap, iovcnt), NULL, FOF_UPDATE_OFFSET, retval); } int -dofilewritev(struct lwp *l, int fd, struct file *fp, const struct iovec *iovp, - int iovcnt, off_t *offset, int flags, register_t *retval) +do_filewritev(struct lwp *l, int fd, const struct iovec *iovp, int iovcnt, + off_t *offset, int flags, register_t *retval) { struct proc *p; struct uio auio; - struct iovec *iov, *needfree, aiov[UIO_SMALLIOV]; + struct iovec *iov, *needfree = NULL, aiov[UIO_SMALLIOV]; struct vmspace *vm; int i, error; size_t cnt; u_int iovlen; + struct file *fp; + struct filedesc *fdp; #ifdef KTRACE - struct iovec *ktriov; + struct iovec *ktriov = NULL; #endif + if (iovcnt == 0) + return EINVAL; + p = l->l_proc; - error = proc_vmspace_getref(p, &vm); - if (error) { - goto out; + fdp = p->p_fd; + + if ((fp = fd_getfile(fdp, fd)) == NULL) + return EBADF; + + if ((fp->f_flag & FWRITE) == 0) { + simple_unlock(&fp->f_slock); + return EBADF; } -#ifdef KTRACE - ktriov = NULL; -#endif - /* note: can't use iovlen until iovcnt is validated */ - iovlen = iovcnt * sizeof(struct iovec); - if ((u_int)iovcnt > UIO_SMALLIOV) { - if ((u_int)iovcnt > IOV_MAX) { - error = EINVAL; + + FILE_USE(fp); + + if (offset == NULL) + offset = &fp->f_offset; + else { + struct vnode *vp = fp->f_data; + if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { + error = ESPIPE; goto out; } - iov = malloc(iovlen, M_IOV, M_WAITOK); - needfree = iov; - } else if ((u_int)iovcnt > 0) { - iov = aiov; - needfree = NULL; - } else { - error = EINVAL; + /* + * Test that the device is seekable ? + * XXX This works because no file systems actually + * XXX take any action on the seek operation. + */ + error = VOP_SEEK(vp, fp->f_offset, *offset, fp->f_cred); + if (error != 0) + goto out; + } + + error = proc_vmspace_getref(p, &vm); + if (error) goto out; + + iovlen = iovcnt * sizeof(struct iovec); + if (flags & FOF_IOV_SYSSPACE) + iov = __UNCONST(iovp); + else { + iov = aiov; + if ((u_int)iovcnt > UIO_SMALLIOV) { + if ((u_int)iovcnt > IOV_MAX) { + error = EINVAL; + goto out; + } + iov = malloc(iovlen, M_IOV, M_WAITOK); + needfree = iov; + } + error = copyin(iovp, iov, iovlen); + if (error) + goto done; } auio.uio_iov = iov; auio.uio_iovcnt = iovcnt; auio.uio_rw = UIO_WRITE; auio.uio_vmspace = vm; - error = copyin(iovp, iov, iovlen); - if (error) - goto done; + auio.uio_resid = 0; - for (i = 0; i < iovcnt; i++) { + for (i = 0; i < iovcnt; i++, iov++) { auio.uio_resid += iov->iov_len; /* * Writes return ssize_t because -1 is returned on error. @@ -487,15 +514,15 @@ dofilewritev(struct lwp *l, int fd, struct file *fp, const struct iovec *iovp, error = EINVAL; goto done; } - iov++; } + #ifdef KTRACE /* * if tracing, save a copy of iovec */ if (KTRPOINT(p, KTR_GENIO)) { ktriov = malloc(iovlen, M_TEMP, M_WAITOK); - memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); + memcpy(ktriov, auio.uio_iov, iovlen); } #endif cnt = auio.uio_resid; @@ -511,6 +538,8 @@ dofilewritev(struct lwp *l, int fd, struct file *fp, const struct iovec *iovp, } } cnt -= auio.uio_resid; + *retval = cnt; + #ifdef KTRACE if (ktriov != NULL) { if (KTRPOINT(p, KTR_GENIO) && (error == 0)) @@ -518,7 +547,7 @@ dofilewritev(struct lwp *l, int fd, struct file *fp, const struct iovec *iovp, free(ktriov, M_TEMP); } #endif - *retval = cnt; + done: if (needfree) free(needfree, M_IOV); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 123dce6f642d..0a27850db148 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_syscalls.c,v 1.318 2007/06/07 10:03:12 hannken Exp $ */ +/* $NetBSD: vfs_syscalls.c,v 1.319 2007/06/16 20:48:04 dsl Exp $ */ /* * Copyright (c) 1989, 1993 @@ -37,7 +37,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.318 2007/06/07 10:03:12 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.319 2007/06/16 20:48:04 dsl Exp $"); #include "opt_compat_netbsd.h" #include "opt_compat_43.h" @@ -2185,45 +2185,9 @@ sys_preadv(struct lwp *l, void *v, register_t *retval) syscallarg(int) iovcnt; syscallarg(off_t) offset; } */ *uap = v; - struct proc *p = l->l_proc; - struct filedesc *fdp = p->p_fd; - struct file *fp; - struct vnode *vp; - off_t offset; - int error, fd = SCARG(uap, fd); - if ((fp = fd_getfile(fdp, fd)) == NULL) - return (EBADF); - - if ((fp->f_flag & FREAD) == 0) { - simple_unlock(&fp->f_slock); - return (EBADF); - } - - FILE_USE(fp); - - vp = (struct vnode *)fp->f_data; - if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { - error = ESPIPE; - goto out; - } - - offset = SCARG(uap, offset); - - /* - * XXX This works because no file systems actually - * XXX take any action on the seek operation. - */ - if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) - goto out; - - /* dofilereadv() will unuse the descriptor for us */ - return (dofilereadv(l, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), - &offset, 0, retval)); - - out: - FILE_UNUSE(fp, l); - return (error); + return do_filereadv(l, SCARG(uap, fd), SCARG(uap, iovp), + SCARG(uap, iovcnt), &SCARG(uap, offset), 0, retval); } /* @@ -2291,45 +2255,9 @@ sys_pwritev(struct lwp *l, void *v, register_t *retval) syscallarg(int) iovcnt; syscallarg(off_t) offset; } */ *uap = v; - struct proc *p = l->l_proc; - struct filedesc *fdp = p->p_fd; - struct file *fp; - struct vnode *vp; - off_t offset; - int error, fd = SCARG(uap, fd); - if ((fp = fd_getfile(fdp, fd)) == NULL) - return (EBADF); - - if ((fp->f_flag & FWRITE) == 0) { - simple_unlock(&fp->f_slock); - return (EBADF); - } - - FILE_USE(fp); - - vp = (struct vnode *)fp->f_data; - if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { - error = ESPIPE; - goto out; - } - - offset = SCARG(uap, offset); - - /* - * XXX This works because no file systems actually - * XXX take any action on the seek operation. - */ - if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) - goto out; - - /* dofilewritev() will unuse the descriptor for us */ - return (dofilewritev(l, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), - &offset, 0, retval)); - - out: - FILE_UNUSE(fp, l); - return (error); + return do_filewritev(l, SCARG(uap, fd), SCARG(uap, iovp), + SCARG(uap, iovcnt), &SCARG(uap, offset), 0, retval); } /* diff --git a/sys/sys/file.h b/sys/sys/file.h index 0939c08640ae..933ef4092c1b 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -1,4 +1,4 @@ -/* $NetBSD: file.h,v 1.56 2006/05/14 21:38:18 elad Exp $ */ +/* $NetBSD: file.h,v 1.57 2007/06/16 20:48:04 dsl Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -146,9 +146,10 @@ do { \ #define FILE_UNUSE_HAVELOCK(fp, l) FILE_UNUSE_WLOCK(fp, l, 1) /* - * Flags for fo_read and fo_write. + * Flags for fo_read and fo_write and do_fileread/write/v */ -#define FOF_UPDATE_OFFSET 0x01 /* update the file offset */ +#define FOF_UPDATE_OFFSET 0x0001 /* update the file offset */ +#define FOF_IOV_SYSSPACE 0x0100 /* iov structure in kernel memory */ LIST_HEAD(filelist, file); extern struct filelist filehead; /* head of list of open files */ @@ -162,10 +163,10 @@ int dofileread(struct lwp *, int, struct file *, void *, size_t, int dofilewrite(struct lwp *, int, struct file *, const void *, size_t, off_t *, int, register_t *); -int dofilereadv(struct lwp *, int, struct file *, - const struct iovec *, int, off_t *, int, register_t *); -int dofilewritev(struct lwp *, int, struct file *, - const struct iovec *, int, off_t *, int, register_t *); +int do_filereadv(struct lwp *, int, const struct iovec *, int, off_t *, + int, register_t *); +int do_filewritev(struct lwp *, int, const struct iovec *, int, off_t *, + int, register_t *); int fsetown(struct proc *, pid_t *, int, const void *); int fgetown(struct proc *, pid_t, int, void *);