summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_descrip.c164
-rw-r--r--sys/kern/kern_event.c12
-rw-r--r--sys/kern/sys_generic.c88
-rw-r--r--sys/kern/uipc_syscalls.c22
-rw-r--r--sys/sys/file.h8
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;
OpenPOWER on IntegriCloud