remove holdfp()

Replace uses of holdfp() with fget*() or fgetvp*() calls as appropriate

introduce fget(), fget_read(), fget_write() - these functions will take
a thread and file descriptor and return a file pointer with its ref
count bumped.

introduce fgetvp(), fgetvp_read(), fgetvp_write() - these functions will
take a thread and file descriptor and return a vref()'d vnode.

*_read() requires that the file pointer be FREAD, *_write that it be
FWRITE.

This continues the cleanup of struct filedesc and struct file access
routines which, when are all through with it, will allow us to then
make the API calls MP safe and be able to move Giant down into the fo_*
functions.
This commit is contained in:
dillon 2001-11-14 06:30:36 +00:00
parent d6cc98f055
commit 7fbc7a8dce
5 changed files with 176 additions and 118 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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;