diff options
-rw-r--r-- | sys/kern/kern_descrip.c | 164 | ||||
-rw-r--r-- | sys/kern/kern_event.c | 12 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 88 | ||||
-rw-r--r-- | sys/kern/uipc_syscalls.c | 22 | ||||
-rw-r--r-- | sys/sys/file.h | 8 |
5 files changed, 176 insertions, 118 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index b0f9e08..1d8d038 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -677,20 +677,14 @@ ofstat(td, uap) struct thread *td; register struct ofstat_args *uap; { - register struct filedesc *fdp = td->td_proc->p_fd; - register struct file *fp; + struct file *fp; struct stat ub; struct ostat oub; int error; mtx_lock(&Giant); - - if ((unsigned)uap->fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[uap->fd]) == NULL) { - error = EBADF; + if ((error = fget(td, uap->fd, &fp)) != 0) goto done2; - } - fhold(fp); error = fo_stat(fp, &ub, td); if (error == 0) { cvtstat(&ub, &oub); @@ -719,22 +713,15 @@ struct fstat_args { int fstat(td, uap) struct thread *td; - register struct fstat_args *uap; + struct fstat_args *uap; { - register struct filedesc *fdp; - register struct file *fp; + struct file *fp; struct stat ub; int error; mtx_lock(&Giant); - fdp = td->td_proc->p_fd; - - if ((unsigned)uap->fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[uap->fd]) == NULL) { - error = EBADF; + if ((error = fget(td, uap->fd, &fp)) != 0) goto done2; - } - fhold(fp); error = fo_stat(fp, &ub, td); if (error == 0) error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); @@ -762,21 +749,14 @@ nfstat(td, uap) struct thread *td; register struct nfstat_args *uap; { - register struct filedesc *fdp; - register struct file *fp; + struct file *fp; struct stat ub; struct nstat nub; int error; mtx_lock(&Giant); - - fdp = td->td_proc->p_fd; - if ((unsigned)uap->fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[uap->fd]) == NULL) { - error = EBADF; + if ((error = fget(td, uap->fd, &fp)) != 0) goto done2; - } - fhold(fp); error = fo_stat(fp, &ub, td); if (error == 0) { cvtnstat(&ub, &nub); @@ -806,21 +786,13 @@ fpathconf(td, uap) struct thread *td; register struct fpathconf_args *uap; { - struct filedesc *fdp; struct file *fp; struct vnode *vp; - int error = 0; + int error; mtx_lock(&Giant); - fdp = td->td_proc->p_fd; - - if ((unsigned)uap->fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[uap->fd]) == NULL) { - error = EBADF; + if ((error = fget(td, uap->fd, &fp)) != 0) goto done2; - } - - fhold(fp); switch (fp->f_type) { case DTYPE_PIPE: @@ -1335,6 +1307,124 @@ closef(fp, td) return (fdrop(fp, td)); } +/* + * Extract the file pointer associated with the specified descriptor for + * the current user process. If no error occured 0 is returned, *fpp + * will be set to the file pointer, and the file pointer's ref count + * will be bumped. Use fdrop() to drop it. If an error occured the + * non-zero error is returned and *fpp is set to NULL. + * + * This routine requires Giant for the moment. Once enough of the + * system is converted over to this and other encapsulated APIs we + * will be able to mutex it and call it without Giant. + */ +static __inline +int +_fget(struct thread *td, int fd, struct file **fpp, int flags) +{ + struct filedesc *fdp; + struct file *fp; + + GIANT_REQUIRED; + fdp = td->td_proc->p_fd; + *fpp = NULL; + if ((u_int)fd >= fdp->fd_nfiles) + return(EBADF); + if ((fp = fdp->fd_ofiles[fd]) == NULL) + return(EBADF); + + /* + * Note: FREAD failures returns EBADF to maintain backwards + * compatibility with what routines returned before. + * + * Only one flag, or 0, may be specified. + */ + if (flags == FREAD && (fp->f_flag & FREAD) == 0) + return(EBADF); + if (flags == FWRITE && (fp->f_flag & FWRITE) == 0) + return(EINVAL); + ++fp->f_count; + *fpp = fp; + return(0); +} + +int +fget(struct thread *td, int fd, struct file **fpp) +{ + return(_fget(td, fd, fpp, 0)); +} + +int +fget_read(struct thread *td, int fd, struct file **fpp) +{ + return(_fget(td, fd, fpp, FREAD)); +} + +int +fget_write(struct thread *td, int fd, struct file **fpp) +{ + return(_fget(td, fd, fpp, FWRITE)); +} + +/* + * Like fget() but loads the underlying vnode, or returns an error if + * the descriptor does not represent a vnode. Note that pipes use vnodes + * but never have VM objects (so VOP_GETVOBJECT() calls will return an + * error). The returned vnode will be vref()d. + */ + +static __inline +int +_fgetvp(struct thread *td, int fd, struct vnode **vpp, int flags) +{ + struct filedesc *fdp; + struct file *fp; + + GIANT_REQUIRED; + fdp = td->td_proc->p_fd; + *vpp = NULL; + if ((u_int)fd >= fdp->fd_nfiles) + return(EBADF); + if ((fp = fdp->fd_ofiles[fd]) == NULL) + return(EBADF); + if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) + return(EINVAL); + if (fp->f_data == NULL) + return(EINVAL); + + /* + * Note: FREAD failures returns EBADF to maintain backwards + * compatibility with what routines returned before. + * + * Only one flag, or 0, may be specified. + */ + if (flags == FREAD && (fp->f_flag & FREAD) == 0) + return(EBADF); + if (flags == FWRITE && (fp->f_flag & FWRITE) == 0) + return(EINVAL); + *vpp = (struct vnode *)fp->f_data; + vref(*vpp); + return(0); +} + +int +fgetvp(struct thread *td, int fd, struct vnode **vpp) +{ + return(_fgetvp(td, fd, vpp, 0)); +} + +int +fgetvp_read(struct thread *td, int fd, struct vnode **vpp) +{ + return(_fgetvp(td, fd, vpp, FREAD)); +} + +int +fgetvp_write(struct thread *td, int fd, struct vnode **vpp) +{ + return(_fgetvp(td, fd, vpp, FWRITE)); +} + int fdrop(fp, td) struct file *fp; diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 191010d..5b4445c 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -394,23 +394,19 @@ struct kevent_args { int kevent(struct thread *td, struct kevent_args *uap) { - struct filedesc *fdp; struct kevent *kevp; struct kqueue *kq; - struct file *fp = NULL; + struct file *fp; struct timespec ts; int i, n, nerrors, error; mtx_lock(&Giant); - fdp = td->td_proc->p_fd; - if (((u_int)uap->fd) >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[uap->fd]) == NULL || - (fp->f_type != DTYPE_KQUEUE)) { + if ((error = fget(td, uap->fd, &fp)) != 0) + goto done; + if (fp->f_type != DTYPE_KQUEUE) { error = EBADF; goto done; } - fhold(fp); - if (uap->timeout != NULL) { error = copyin(uap->timeout, &ts, sizeof(ts)); if (error) diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 17cee14..352e325 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -83,22 +83,6 @@ static int dofileread __P((struct thread *, struct file *, int, void *, static int dofilewrite __P((struct thread *, struct file *, int, const void *, size_t, off_t, int)); -struct file* -holdfp(fdp, fd, flag) - struct filedesc* fdp; - int fd, flag; -{ - struct file* fp; - - if (((u_int)fd) >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[fd]) == NULL || - (fp->f_flag & flag) == 0) { - return (NULL); - } - fhold(fp); - return (fp); -} - /* * Read system call. */ @@ -115,18 +99,16 @@ struct read_args { int read(td, uap) struct thread *td; - register struct read_args *uap; + struct read_args *uap; { - register struct file *fp; + struct file *fp; int error; mtx_lock(&Giant); - if ((fp = holdfp(td->td_proc->p_fd, uap->fd, FREAD)) != NULL) { + if ((error = fget_read(td, uap->fd, &fp)) == 0) { error = dofileread(td, fp, uap->fd, uap->buf, uap->nbyte, (off_t)-1, 0); fdrop(fp, td); - } else { - error = EBADF; } mtx_unlock(&Giant); return(error); @@ -150,20 +132,19 @@ struct pread_args { int pread(td, uap) struct thread *td; - register struct pread_args *uap; + struct pread_args *uap; { - register struct file *fp; + struct file *fp; int error; mtx_lock(&Giant); - if ((fp = holdfp(td->td_proc->p_fd, uap->fd, FREAD)) == NULL) { - error = EBADF; - } else if (fp->f_type != DTYPE_VNODE) { - error = ESPIPE; - fdrop(fp, td); - } else { - error = dofileread(td, fp, uap->fd, uap->buf, uap->nbyte, - uap->offset, FOF_OFFSET); + if ((error = fget_read(td, uap->fd, &fp)) == 0) { + if (fp->f_type == DTYPE_VNODE) { + error = dofileread(td, fp, uap->fd, uap->buf, + uap->nbyte, uap->offset, FOF_OFFSET); + } else { + error = ESPIPE; + } fdrop(fp, td); } mtx_unlock(&Giant); @@ -247,12 +228,11 @@ struct readv_args { int readv(td, uap) struct thread *td; - register struct readv_args *uap; + struct readv_args *uap; { - register struct file *fp; - register struct filedesc *fdp; + struct file *fp; struct uio auio; - register struct iovec *iov; + struct iovec *iov; struct iovec *needfree; struct iovec aiov[UIO_SMALLIOV]; long i, cnt, error = 0; @@ -262,12 +242,9 @@ readv(td, uap) struct uio ktruio; #endif mtx_lock(&Giant); - fdp = td->td_proc->p_fd; - if ((fp = holdfp(fdp, uap->fd, FREAD)) == NULL) { - error = EBADF; + if ((error = fget_read(td, uap->fd, &fp)) != 0) goto done2; - } /* note: can't use iovlen until iovcnt is validated */ iovlen = uap->iovcnt * sizeof (struct iovec); if (uap->iovcnt > UIO_SMALLIOV) { @@ -352,18 +329,18 @@ struct write_args { int write(td, uap) struct thread *td; - register struct write_args *uap; + struct write_args *uap; { - register struct file *fp; + struct file *fp; int error; mtx_lock(&Giant); - if ((fp = holdfp(td->td_proc->p_fd, uap->fd, FWRITE)) != NULL) { + if ((error = fget_write(td, uap->fd, &fp)) == 0) { error = dofilewrite(td, fp, uap->fd, uap->buf, uap->nbyte, (off_t)-1, 0); fdrop(fp, td); } else { - error = EBADF; + error = EBADF; /* XXX this can't be right */ } mtx_unlock(&Giant); return(error); @@ -387,21 +364,22 @@ struct pwrite_args { int pwrite(td, uap) struct thread *td; - register struct pwrite_args *uap; + struct pwrite_args *uap; { - register struct file *fp; + struct file *fp; int error; mtx_lock(&Giant); - if ((fp = holdfp(td->td_proc->p_fd, uap->fd, FWRITE)) == NULL) { - error = EBADF; - } else if (fp->f_type != DTYPE_VNODE) { - error = ESPIPE; + if ((error = fget_write(td, uap->fd, &fp)) == 0) { + if (fp->f_type == DTYPE_VNODE) { + error = dofilewrite(td, fp, uap->fd, uap->buf, + uap->nbyte, uap->offset, FOF_OFFSET); + } else { + error = ESPIPE; + } fdrop(fp, td); } else { - error = dofilewrite(td, fp, uap->fd, uap->buf, uap->nbyte, - uap->offset, FOF_OFFSET); - fdrop(fp, td); + error = EBADF; /* this can't be right */ } mtx_unlock(&Giant); return(error); @@ -489,8 +467,7 @@ writev(td, uap) struct thread *td; register struct writev_args *uap; { - register struct file *fp; - register struct filedesc *fdp; + struct file *fp; struct uio auio; register struct iovec *iov; struct iovec *needfree; @@ -503,8 +480,7 @@ writev(td, uap) #endif mtx_lock(&Giant); - fdp = td->td_proc->p_fd; - if ((fp = holdfp(fdp, uap->fd, FWRITE)) == NULL) { + if ((error = fget_write(td, uap->fd, &fp)) != 0) { error = EBADF; goto done2; } diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index e09951f..a0ca7cc 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1678,8 +1678,7 @@ sf_buf_free(caddr_t addr, void *args) int sendfile(struct thread *td, struct sendfile_args *uap) { - struct file *fp; - struct filedesc *fdp = td->td_proc->p_fd; + struct file *fp = NULL; struct vnode *vp; struct vm_object *obj; struct socket *so; @@ -1689,30 +1688,19 @@ sendfile(struct thread *td, struct sendfile_args *uap) struct writev_args nuap; struct sf_hdtr hdtr; off_t off, xfsize, sbytes = 0; - int error = 0, s; + int error, s; mtx_lock(&Giant); - vp = NULL; + /* - * Do argument checking. Must be a regular file in, stream - * type and connected socket out, positive offset. + * The descriptor must be a regular file and have a backing VM object. */ - fp = holdfp(fdp, uap->fd, FREAD); - if (fp == NULL) { - error = EBADF; + if ((error = fgetvp_read(td, uap->fd, &vp)) != 0) goto done; - } - if (fp->f_type != DTYPE_VNODE) { - error = EINVAL; - goto done; - } - vp = (struct vnode *)fp->f_data; - vref(vp); if (vp->v_type != VREG || VOP_GETVOBJECT(vp, &obj) != 0) { error = EINVAL; goto done; } - fdrop(fp, td); error = holdsock(td->td_proc->p_fd, uap->s, &fp); if (error) goto done; diff --git a/sys/sys/file.h b/sys/sys/file.h index fc68b80..589bffd 100644 --- a/sys/sys/file.h +++ b/sys/sys/file.h @@ -49,6 +49,7 @@ struct stat; struct thread; struct uio; struct knote; +struct vnode; /* * Kernel descriptor table. @@ -109,8 +110,15 @@ extern int maxfilesperproc; /* per process limit on number of open files */ extern int nfiles; /* actual number of open files */ static __inline void fhold __P((struct file *fp)); +int fget __P((struct thread *td, int fd, struct file **fpp)); +int fget_read __P((struct thread *td, int fd, struct file **fpp)); +int fget_write __P((struct thread *td, int fd, struct file **fpp)); int fdrop __P((struct file *fp, struct thread *td)); +int fgetvp __P((struct thread *td, int fd, struct vnode **vpp)); +int fgetvp_read __P((struct thread *td, int fd, struct vnode **vpp)); +int fgetvp_write __P((struct thread *td, int fd, struct vnode **vpp)); + static __inline void fhold(fp) struct file *fp; |