fd_getfile() and fp refcounting

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

fd_getfile() and fp refcounting

Martin Pieuchot
Here's diff a that moves FRELE() inside fd_getfile().  This is some
plumbing to help unlocking code paths manipulating fp.  The idea is
to guarantee to the callers of fd_getfile() that the returned fp has
the necessary reference counts and will not disappear while it is
being manipulated.

Some code paths are more tricky than others so comments are appreciated.

Index: arch/i386/i386/linux_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/linux_machdep.c,v
retrieving revision 1.46
diff -u -p -r1.46 linux_machdep.c
--- arch/i386/i386/linux_machdep.c 16 Dec 2014 18:30:03 -0000 1.46
+++ arch/i386/i386/linux_machdep.c 14 Jul 2015 21:19:26 -0000
@@ -428,7 +428,6 @@ linux_machdepioctl(struct proc *p, void
  struct vt_mode lvt;
  caddr_t bvtp, sg;
 #endif
- struct filedesc *fdp;
  struct file *fp;
  int fd;
  int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *);
@@ -439,9 +438,10 @@ linux_machdepioctl(struct proc *p, void
  SCARG(&bia, data) = SCARG(uap, data);
  com = SCARG(uap, com);
 
- fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
  return (EBADF);
+ FRELE(fp, p);
+ fp = NULL;
 
  switch (com) {
 #if (NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL))
@@ -568,7 +568,8 @@ linux_machdepioctl(struct proc *p, void
  * XXX hack: if the function returns EJUSTRETURN,
  * it has stuffed a sysctl return value in pt.data.
  */
- FREF(fp);
+ if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
+ return (EBADF);
  ioctlf = fp->f_ops->fo_ioctl;
  pt.com = SCARG(uap, com);
  pt.data = SCARG(uap, data);
Index: compat/linux/linux_blkio.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_blkio.c,v
retrieving revision 1.9
diff -u -p -r1.9 linux_blkio.c
--- compat/linux/linux_blkio.c 22 Apr 2012 05:43:14 -0000 1.9
+++ compat/linux/linux_blkio.c 14 Jul 2015 21:19:26 -0000
@@ -72,7 +72,6 @@ linux_ioctl_blkio(struct proc *p, struct
         fdp = p->p_fd;
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
- FREF(fp);
  error = 0;
  ioctlf = fp->f_ops->fo_ioctl;
  com = SCARG(uap, com);
Index: compat/linux/linux_cdrom.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_cdrom.c,v
retrieving revision 1.12
diff -u -p -r1.12 linux_cdrom.c
--- compat/linux/linux_cdrom.c 30 Apr 2015 09:20:51 -0000 1.12
+++ compat/linux/linux_cdrom.c 14 Jul 2015 21:19:26 -0000
@@ -77,7 +77,6 @@ linux_ioctl_cdrom(p, v, retval)
  syscallarg(caddr_t) data;
  } */ *uap = v;
  struct file *fp;
- struct filedesc *fdp;
  caddr_t sg;
  u_long com, arg;
  struct sys_ioctl_args ia;
@@ -107,10 +106,8 @@ linux_ioctl_cdrom(p, v, retval)
  } tmpl;
 
 
- fdp = p->p_fd;
- if ((fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
  return (EBADF);
- FREF(fp);
 
  com = SCARG(uap, com);
  retval[0] = 0;
Index: compat/linux/linux_fdio.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_fdio.c,v
retrieving revision 1.7
diff -u -p -r1.7 linux_fdio.c
--- compat/linux/linux_fdio.c 22 Apr 2012 05:43:14 -0000 1.7
+++ compat/linux/linux_fdio.c 14 Jul 2015 21:19:26 -0000
@@ -78,7 +78,6 @@ linux_ioctl_fdio(struct proc *p, struct
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
 
- FREF(fp);
  com = SCARG(uap, com);
  ioctlf = fp->f_ops->fo_ioctl;
 
Index: compat/linux/linux_file.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_file.c,v
retrieving revision 1.30
diff -u -p -r1.30 linux_file.c
--- compat/linux/linux_file.c 26 Mar 2014 05:23:42 -0000 1.30
+++ compat/linux/linux_file.c 14 Jul 2015 21:19:26 -0000
@@ -198,7 +198,6 @@ linux_sys_open(p, v, retval)
 
  if ((fp = fd_getfile(fdp, *retval)) == NULL)
  return (EBADF);
- FREF(fp);
                 if (fp->f_type == DTYPE_VNODE)
                         (fp->f_ops->fo_ioctl) (fp, TIOCSCTTY, (caddr_t) 0, p);
  FRELE(fp, p);
@@ -420,12 +419,14 @@ linux_sys_fcntl(p, v, retval)
  return (EBADF);
  if (fp->f_type == DTYPE_SOCKET) {
  cmd = cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
+ FRELE(fp, p);
  break;
  }
  vp = (struct vnode *)fp->f_data;
- if (vp->v_type != VCHR)
+ if (vp->v_type != VCHR) {
+ FRELE(fp, p);
  return EINVAL;
- FREF(fp);
+ }
  error = VOP_GETATTR(vp, &va, p->p_ucred, p);
  FRELE(fp, p);
  if (error)
Index: compat/linux/linux_hdio.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_hdio.c,v
retrieving revision 1.9
diff -u -p -r1.9 linux_hdio.c
--- compat/linux/linux_hdio.c 26 Mar 2014 05:23:42 -0000 1.9
+++ compat/linux/linux_hdio.c 14 Jul 2015 21:19:26 -0000
@@ -81,7 +81,6 @@ linux_ioctl_hdio(struct proc *p, struct
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
 
- FREF(fp);
  com = SCARG(uap, com);
  ioctlf = fp->f_ops->fo_ioctl;
  retval[0] = error = 0;
Index: compat/linux/linux_socket.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_socket.c,v
retrieving revision 1.61
diff -u -p -r1.61 linux_socket.c
--- compat/linux/linux_socket.c 6 May 2015 08:52:17 -0000 1.61
+++ compat/linux/linux_socket.c 14 Jul 2015 21:19:26 -0000
@@ -1372,7 +1372,6 @@ linux_ioctl_socket(p, v, retval)
  fdp = p->p_fd;
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
- FREF(fp);
 
  if (fp->f_type == DTYPE_VNODE) {
  vp = (struct vnode *)fp->f_data;
Index: compat/linux/linux_termios.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_termios.c,v
retrieving revision 1.18
diff -u -p -r1.18 linux_termios.c
--- compat/linux/linux_termios.c 30 Apr 2015 09:20:51 -0000 1.18
+++ compat/linux/linux_termios.c 14 Jul 2015 21:19:26 -0000
@@ -449,7 +449,6 @@ linux_ioctl_termios(p, v, retval)
  syscallarg(caddr_t) data;
  } */ *uap = v;
  struct file *fp;
- struct filedesc *fdp;
  u_long com;
  struct linux_termio tmplt;
  struct linux_termios tmplts;
@@ -460,10 +459,8 @@ linux_ioctl_termios(p, v, retval)
  char tioclinux;
  int error = 0;
 
- fdp = p->p_fd;
- if ((fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
  return (EBADF);
- FREF(fp);
 
  com = SCARG(uap, com);
  retval[0] = 0;
Index: dev/systrace.c
===================================================================
RCS file: /cvs/src/sys/dev/systrace.c,v
retrieving revision 1.75
diff -u -p -r1.75 systrace.c
--- dev/systrace.c 14 Mar 2015 03:38:46 -0000 1.75
+++ dev/systrace.c 14 Jul 2015 21:19:26 -0000
@@ -1058,9 +1058,10 @@ systrace_processready(struct str_process
 int
 systrace_getcwd(struct fsystrace *fst, struct str_process *strp, int atfd)
 {
+ struct file *fp = NULL;
  struct filedesc *myfdp, *fdp;
  struct vnode *dvp, *odvp;
- int error;
+ int error = 0;
 
  DPRINTF(("%s: %d\n", __func__, strp->pid));
 
@@ -1073,15 +1074,21 @@ systrace_getcwd(struct fsystrace *fst, s
  if (myfdp == NULL || fdp == NULL)
  return (EINVAL);
 
- if (atfd == AT_FDCWD)
- dvp = fdp->fd_cdir;
- else {
- struct file *fp = fd_getfile(fdp, atfd);
- if (fp == NULL || fp->f_type != DTYPE_VNODE)
+ if (atfd != AT_FDCWD) {
+ if ((fp = fd_getfile(fdp, atfd)) == NULL)
  return (EINVAL);
+
+ if (fp->f_type != DTYPE_VNODE) {
+ error = EINVAL;
+ goto out;
+ }
  dvp = (struct vnode *)fp->f_data;
- if (dvp->v_type != VDIR)
- return (EINVAL);
+ if (dvp->v_type != VDIR) {
+ error = EINVAL;
+ goto out;
+ }
+ } else {
+ dvp = fdp->fd_cdir;
  }
 
  /* Is there a STRIOCGETCWD currently in effect? */
@@ -1107,7 +1114,11 @@ systrace_getcwd(struct fsystrace *fst, s
  if ((myfdp->fd_rdir = fdp->fd_rdir) != NULL)
  vref(myfdp->fd_rdir);
 
- return (0);
+out:
+ if (fp != NULL)
+ FRELE(fp, strp->proc);
+
+ return (error);
 }
 
 int
Index: kern/kern_descrip.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.120
diff -u -p -r1.120 kern_descrip.c
--- kern/kern_descrip.c 17 May 2015 01:22:01 -0000 1.120
+++ kern/kern_descrip.c 14 Jul 2015 21:19:26 -0000
@@ -189,20 +189,24 @@ fd_getfile(struct filedesc *fdp, int fd)
  if (!FILE_IS_USABLE(fp))
  return (NULL);
 
+ FREF(fp);
  return (fp);
 }
 
 struct file *
-fd_getfile_mode(struct filedesc *fdp, int fd, int mode)
+fd_getfile_mode(struct proc *p, int fd, int mode)
 {
  struct file *fp;
 
  KASSERT(mode != 0);
 
- fp = fd_getfile(fdp, fd);
+ if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
+ return (NULL);
 
- if (fp == NULL || (fp->f_flag & mode) == 0)
+ if ((fp->f_flag & mode) == 0) {
+ FRELE(fp, p);
  return (NULL);
+ }
 
  return (fp);
 }
@@ -230,7 +234,6 @@ sys_dup(struct proc *p, void *v, registe
 restart:
  if ((fp = fd_getfile(fdp, old)) == NULL)
  return (EBADF);
- FREF(fp);
  fdplock(fdp);
  if ((error = fdalloc(p, 0, &new)) != 0) {
  FRELE(fp, p);
@@ -287,11 +290,11 @@ dodup3(struct proc *p, int old, int new,
  int i, error;
 
 restart:
- if ((fp = fd_getfile(fdp, old)) == NULL)
- return (EBADF);
  if ((u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
     (u_int)new >= maxfiles)
  return (EBADF);
+ if ((fp = fd_getfile(fdp, old)) == NULL)
+ return (EBADF);
  if (old == new) {
  /*
  * NOTE! This doesn't clear the close-on-exec flag. This might
@@ -299,9 +302,9 @@ restart:
  * this is what everyone else does.
  */
  *retval = new;
+ FRELE(fp, p);
  return (0);
  }
- FREF(fp);
  fdplock(fdp);
  if (new >= fdp->fd_nfiles) {
  if ((error = fdalloc(p, new, &i)) != 0) {
@@ -341,16 +344,16 @@ sys_fcntl(struct proc *p, void *v, regis
  } */ *uap = v;
  int fd = SCARG(uap, fd);
  struct filedesc *fdp = p->p_fd;
- struct file *fp;
+ struct file *fp, *fp0;
  struct vnode *vp;
  int i, tmp, newmin, flg = F_POSIX;
  struct flock fl;
- int error = 0;
+ int lost, error = 0;
 
 restart:
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- FREF(fp);
+
  switch (SCARG(uap, cmd)) {
 
  case F_DUPFD:
@@ -508,7 +511,11 @@ restart:
  goto out;
  }
 
- if (fp != fd_getfile(fdp, fd)) {
+ fp0 = fd_getfile(fdp, fd);
+ lost = (fp != fp0);
+ if (fp0 != NULL)
+ FRELE(fp0, p);
+ if (lost) {
  /*
  * We have lost the race with close() or dup2();
  * unlock, pretend that we've won the race and that
@@ -648,12 +655,15 @@ sys_close(struct proc *p, void *v, regis
  struct sys_close_args /* {
  syscallarg(int) fd;
  } */ *uap = v;
- int fd = SCARG(uap, fd), error;
+ int fd = SCARG(uap, fd);
  struct filedesc *fdp = p->p_fd;
+ struct file *fp;
+ int error;
 
- if (fd_getfile(fdp, fd) == NULL)
+ if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
  fdplock(fdp);
+ FRELE(fp, p);
  error = fdrelease(p, fd);
  fdpunlock(fdp);
 
@@ -678,7 +688,6 @@ sys_fstat(struct proc *p, void *v, regis
 
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- FREF(fp);
  error = (*fp->f_ops->fo_stat)(fp, &ub, p);
  FRELE(fp, p);
  if (error == 0) {
@@ -717,7 +726,6 @@ sys_fpathconf(struct proc *p, void *v, r
 
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- FREF(fp);
  switch (fp->f_type) {
  case DTYPE_PIPE:
  case DTYPE_SOCKET:
@@ -1175,9 +1183,10 @@ sys_flock(struct proc *p, void *v, regis
 
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- if (fp->f_type != DTYPE_VNODE)
- return (EOPNOTSUPP);
- FREF(fp);
+ if (fp->f_type != DTYPE_VNODE) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
  vp = (struct vnode *)fp->f_data;
  lf.l_whence = SEEK_SET;
  lf.l_start = 0;
@@ -1235,8 +1244,10 @@ filedescopen(dev_t dev, int mode, int ty
  * Duplicate the specified descriptor to a free descriptor.
  */
 int
-dupfdopen(struct filedesc *fdp, int indx, int dfd, int mode)
+dupfdopen(struct proc *p, int indx, int mode)
 {
+ struct filedesc *fdp = p->p_fd;
+ int dfd = p->p_dupfd;
  struct file *wfp;
 
  fdpassertlocked(fdp);
@@ -1245,10 +1256,10 @@ dupfdopen(struct filedesc *fdp, int indx
  * Assume that the filename was user-specified; applications do
  * not tend to open /dev/fd/# when they can just call dup()
  */
- if ((curproc->p_p->ps_flags & (PS_SUGIDEXEC | PS_SUGID))) {
- if (curproc->p_descfd == 255)
+ if ((p->p_p->ps_flags & (PS_SUGIDEXEC | PS_SUGID))) {
+ if (p->p_descfd == 255)
  return (EPERM);
- if (curproc->p_descfd != curproc->p_dupfd)
+ if (p->p_descfd != p->p_dupfd)
  return (EPERM);
  }
 
@@ -1266,16 +1277,19 @@ dupfdopen(struct filedesc *fdp, int indx
  * Check that the mode the file is being opened for is a
  * subset of the mode of the existing descriptor.
  */
- if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
+ if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) {
+ FRELE(wfp, p);
  return (EACCES);
- if (wfp->f_count == LONG_MAX-2)
+ }
+ if (wfp->f_count == LONG_MAX-2) {
+ FRELE(wfp, p);
  return (EDEADLK);
-
+ }
  fdp->fd_ofiles[indx] = wfp;
  fdp->fd_ofileflags[indx] = (fdp->fd_ofileflags[indx] & UF_EXCLOSE) |
-    (fdp->fd_ofileflags[dfd] & ~UF_EXCLOSE);
- wfp->f_count++;
+    (fdp->fd_ofileflags[p->p_dupfd] & ~UF_EXCLOSE);
  fd_used(fdp, indx);
+
  return (0);
 }
 
Index: kern/kern_event.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_event.c,v
retrieving revision 1.61
diff -u -p -r1.61 kern_event.c
--- kern/kern_event.c 19 Dec 2014 05:59:21 -0000 1.61
+++ kern/kern_event.c 14 Jul 2015 21:19:26 -0000
@@ -480,11 +480,13 @@ sys_kevent(struct proc *p, void *v, regi
  struct timespec ts;
  int i, n, nerrors, error;
 
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL ||
-    (fp->f_type != DTYPE_KQUEUE))
+ if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
 
- FREF(fp);
+ if (fp->f_type != DTYPE_KQUEUE) {
+ error = EBADF;
+ goto done;
+ }
 
  if (SCARG(uap, timeout) != NULL) {
  error = copyin(SCARG(uap, timeout), &ts, sizeof(ts));
@@ -575,7 +577,6 @@ kqueue_register(struct kqueue *kq, struc
  /* validate descriptor */
  if ((fp = fd_getfile(fdp, kev->ident)) == NULL)
  return (EBADF);
- FREF(fp);
 
  if (kev->ident < fdp->fd_knlistsize) {
  SLIST_FOREACH(kn, &fdp->fd_knlist[kev->ident], kn_link)
Index: kern/kern_exec.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.161
diff -u -p -r1.161 kern_exec.c
--- kern/kern_exec.c 14 Mar 2015 03:38:50 -0000 1.161
+++ kern/kern_exec.c 14 Jul 2015 21:19:26 -0000
@@ -606,7 +606,10 @@ sys_execve(struct proc *p, void *v, regi
  fp->f_ops = &vnops;
  fp->f_data = (caddr_t)vp;
  FILE_SET_MATURE(fp, p);
+ } else {
+ FRELE(fp, p);
  }
+
  }
  fdpunlock(p->p_fd);
  if (error)
Index: kern/sys_generic.c
===================================================================
RCS file: /cvs/src/sys/kern/sys_generic.c,v
retrieving revision 1.98
diff -u -p -r1.98 sys_generic.c
--- kern/sys_generic.c 10 May 2015 22:35:38 -0000 1.98
+++ kern/sys_generic.c 14 Jul 2015 21:19:26 -0000
@@ -85,16 +85,13 @@ sys_read(struct proc *p, void *v, regist
  struct iovec iov;
  int fd = SCARG(uap, fd);
  struct file *fp;
- struct filedesc *fdp = p->p_fd;
 
- if ((fp = fd_getfile_mode(fdp, fd, FREAD)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FREAD)) == NULL)
  return (EBADF);
 
  iov.iov_base = SCARG(uap, buf);
  iov.iov_len = SCARG(uap, nbyte);
 
- FREF(fp);
-
  /* dofilereadv() will FRELE the descriptor for us */
  return (dofilereadv(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval));
 }
@@ -112,11 +109,9 @@ sys_readv(struct proc *p, void *v, regis
  } */ *uap = v;
  int fd = SCARG(uap, fd);
  struct file *fp;
- struct filedesc *fdp = p->p_fd;
 
- if ((fp = fd_getfile_mode(fdp, fd, FREAD)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FREAD)) == NULL)
  return (EBADF);
- FREF(fp);
 
  /* dofilereadv() will FRELE the descriptor for us */
  return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
@@ -233,16 +228,13 @@ sys_write(struct proc *p, void *v, regis
  struct iovec iov;
  int fd = SCARG(uap, fd);
  struct file *fp;
- struct filedesc *fdp = p->p_fd;
 
- if ((fp = fd_getfile_mode(fdp, fd, FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FWRITE)) == NULL)
  return (EBADF);
 
  iov.iov_base = (void *)SCARG(uap, buf);
  iov.iov_len = SCARG(uap, nbyte);
 
- FREF(fp);
-
  /* dofilewritev() will FRELE the descriptor for us */
  return (dofilewritev(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval));
 }
@@ -260,11 +252,9 @@ sys_writev(struct proc *p, void *v, regi
  } */ *uap = v;
  int fd = SCARG(uap, fd);
  struct file *fp;
- struct filedesc *fdp = p->p_fd;
 
- if ((fp = fd_getfile_mode(fdp, fd, FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FWRITE)) == NULL)
  return (EBADF);
- FREF(fp);
 
  /* dofilewritev() will FRELE the descriptor for us */
  return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
@@ -383,17 +373,16 @@ sys_ioctl(struct proc *p, void *v, regis
  syscallarg(void *) data;
  } */ *uap = v;
  struct file *fp;
- struct filedesc *fdp;
+ struct filedesc *fdp = p->p_fd;
  u_long com;
  int error;
  u_int size;
- caddr_t data, memp;
+ caddr_t data, memp = NULL;
  int tmp;
 #define STK_PARAMS 128
  long long stkbuf[STK_PARAMS / sizeof(long long)];
 
- fdp = p->p_fd;
- if ((fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
  return (EBADF);
 
  switch (com = SCARG(uap, com)) {
@@ -405,6 +394,7 @@ sys_ioctl(struct proc *p, void *v, regis
  else
  fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
  fdpunlock(fdp);
+ FRELE(fp, p);
  return (0);
  }
 
@@ -413,10 +403,11 @@ sys_ioctl(struct proc *p, void *v, regis
  * copied to/from the user's address space.
  */
  size = IOCPARM_LEN(com);
- if (size > IOCPARM_MAX)
- return (ENOTTY);
- FREF(fp);
- memp = NULL;
+ if (size > IOCPARM_MAX) {
+ error = ENOTTY;
+ goto out;
+ }
+
  if (size > sizeof (stkbuf)) {
  memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
  data = memp;
@@ -724,7 +715,6 @@ selscan(struct proc *p, fd_set *ibits, f
  bits &= ~(1 << j);
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- FREF(fp);
  if ((*fp->f_ops->fo_poll)(fp, flag[msk], p)) {
  FD_SET(fd, pobits);
  n++;
@@ -822,7 +812,6 @@ pollscan(struct proc *p, struct pollfd *
  n++;
  continue;
  }
- FREF(fp);
  pl->revents = (*fp->f_ops->fo_poll)(fp, pl->events, p);
  FRELE(fp, p);
  if (pl->revents != 0)
Index: kern/uipc_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.102
diff -u -p -r1.102 uipc_syscalls.c
--- kern/uipc_syscalls.c 21 May 2015 13:35:15 -0000 1.102
+++ kern/uipc_syscalls.c 14 Jul 2015 21:19:26 -0000
@@ -1022,10 +1022,11 @@ getsock(struct proc *p, int fdes, struct
 
  if ((fp = fd_getfile(p->p_fd, fdes)) == NULL)
  return (EBADF);
- if (fp->f_type != DTYPE_SOCKET)
+ if (fp->f_type != DTYPE_SOCKET) {
+ FRELE(fp, p);
  return (ENOTSOCK);
+ }
  *fpp = fp;
- FREF(fp);
 
  return (0);
 }
Index: kern/uipc_usrreq.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.81
diff -u -p -r1.81 uipc_usrreq.c
--- kern/uipc_usrreq.c 30 Jun 2015 15:30:17 -0000 1.81
+++ kern/uipc_usrreq.c 14 Jul 2015 21:19:26 -0000
@@ -826,18 +826,19 @@ morespace:
  }
  if (fp->f_count == LONG_MAX-2 ||
     fp->f_msgcount == LONG_MAX-2) {
+ FRELE(fp, p);
  error = EDEADLK;
  goto fail;
  }
  /* kq and systrace descriptors cannot be copied */
  if (fp->f_type == DTYPE_KQUEUE ||
     fp->f_type == DTYPE_SYSTRACE) {
+ FRELE(fp, p);
  error = EINVAL;
  goto fail;
  }
  memcpy(rp, &fp, sizeof fp);
  rp--;
- fp->f_count++;
  fp->f_msgcount++;
  unp_rights++;
  }
@@ -847,9 +848,9 @@ fail:
  for ( ; i > 0; i--) {
  rp++;
  memcpy(&fp, rp, sizeof(fp));
- fp->f_count--;
  fp->f_msgcount--;
  unp_rights--;
+ FRELE(fp, p);
  }
 
  return (error);
Index: kern/vfs_lookup.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_lookup.c,v
retrieving revision 1.53
diff -u -p -r1.53 vfs_lookup.c
--- kern/vfs_lookup.c 23 Apr 2015 02:55:15 -0000 1.53
+++ kern/vfs_lookup.c 14 Jul 2015 21:19:26 -0000
@@ -86,6 +86,7 @@
 int
 namei(struct nameidata *ndp)
 {
+ struct file *fp = NULL;
  struct filedesc *fdp; /* pointer to file descriptor state */
  char *cp; /* pointer into pathname argument */
  struct vnode *dp; /* the directory we are searching */
@@ -104,7 +105,7 @@ namei(struct nameidata *ndp)
  if (cnp->cn_flags & OPMASK)
  panic ("namei: flags contaminated with nameiops");
 #endif
- fdp = cnp->cn_proc->p_fd;
+ fdp = p->p_fd;
 
  /*
  * Get a buffer for the name to be translated, and copy the
@@ -174,7 +175,7 @@ namei(struct nameidata *ndp)
  dp = fdp->fd_cdir;
  vref(dp);
  } else {
- struct file *fp = fd_getfile(fdp, ndp->ni_dirfd);
+ fp = fd_getfile(fdp, ndp->ni_dirfd);
  if (fp == NULL) {
  pool_put(&namei_pool, cnp->cn_pnbuf);
  return (EBADF);
@@ -182,7 +183,8 @@ namei(struct nameidata *ndp)
  dp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || dp->v_type != VDIR) {
  pool_put(&namei_pool, cnp->cn_pnbuf);
- return (ENOTDIR);
+ error = ENOTDIR;
+ goto out;
  }
  vref(dp);
  }
@@ -190,13 +192,14 @@ namei(struct nameidata *ndp)
  if (!dp->v_mount) {
  /* Give up if the directory is no longer mounted */
  pool_put(&namei_pool, cnp->cn_pnbuf);
- return (ENOENT);
+ error = ENOENT;
+ goto out;
  }
  cnp->cn_nameptr = cnp->cn_pnbuf;
  ndp->ni_startdir = dp;
  if ((error = vfs_lookup(ndp)) != 0) {
  pool_put(&namei_pool, cnp->cn_pnbuf);
- return (error);
+ goto out;
  }
  /*
  * If not a symbolic link, return search result.
@@ -206,7 +209,8 @@ namei(struct nameidata *ndp)
  pool_put(&namei_pool, cnp->cn_pnbuf);
  else
  cnp->cn_flags |= HASBUF;
- return (0);
+ error = 0;
+ goto out;
  }
  if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
  VOP_UNLOCK(ndp->ni_dvp, 0, p);
@@ -265,6 +269,10 @@ badlink:
  vrele(ndp->ni_dvp);
  vput(ndp->ni_vp);
  ndp->ni_vp = NULL;
+
+out:
+ if (fp)
+ FRELE(fp, p);
  return (error);
 }
 
Index: kern/vfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.220
diff -u -p -r1.220 vfs_syscalls.c
--- kern/vfs_syscalls.c 7 May 2015 08:53:33 -0000 1.220
+++ kern/vfs_syscalls.c 14 Jul 2015 21:19:26 -0000
@@ -683,13 +683,15 @@ sys_fchdir(struct proc *p, void *v, regi
  struct vnode *vp, *tdp, *old_cdir;
  struct mount *mp;
  struct file *fp;
- int error;
+ int error = 0;
 
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
  vp = (struct vnode *)fp->f_data;
- if (fp->f_type != DTYPE_VNODE || vp->v_type != VDIR)
- return (ENOTDIR);
+ if (fp->f_type != DTYPE_VNODE || vp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
+ }
  vref(vp);
  vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
@@ -706,13 +708,15 @@ sys_fchdir(struct proc *p, void *v, regi
  }
  if (error) {
  vput(vp);
- return (error);
+ goto out;
  }
  VOP_UNLOCK(vp, 0, p);
  old_cdir = fdp->fd_cdir;
  fdp->fd_cdir = vp;
  vrele(old_cdir);
- return (0);
+out:
+ FRELE(fp, p);
+ return (error);
 }
 
 /*
@@ -863,7 +867,7 @@ doopenat(struct proc *p, int fd, const c
  if (error == ENODEV &&
     p->p_dupfd >= 0 && /* XXX from fdopen */
     (error =
- dupfdopen(fdp, indx, p->p_dupfd, flags)) == 0) {
+ dupfdopen(p, indx, flags)) == 0) {
  closef(fp, p);
  *retval = indx;
  goto out;
@@ -1534,12 +1538,11 @@ sys_lseek(struct proc *p, void *v, regis
 
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
- if (fp->f_type != DTYPE_VNODE)
- return (ESPIPE);
  vp = (struct vnode *)fp->f_data;
- if (vp->v_type == VFIFO)
- return (ESPIPE);
- FREF(fp);
+ if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
+ error = ESPIPE;
+ goto bad;
+ }
  if (vp->v_type == VCHR)
  special = 1;
  else
@@ -2791,14 +2794,17 @@ getvnode(struct proc *p, int fd, struct
  if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
  return (EBADF);
 
- if (fp->f_type != DTYPE_VNODE)
+ if (fp->f_type != DTYPE_VNODE) {
+ FRELE(fp, p);
  return (EINVAL);
+ }
 
  vp = (struct vnode *)fp->f_data;
- if (vp->v_type == VBAD)
+ if (vp->v_type == VBAD) {
+ FRELE(fp, p);
  return (EBADF);
+ }
 
- FREF(fp);
  *fpp = fp;
 
  return (0);
@@ -2818,18 +2824,18 @@ sys_pread(struct proc *p, void *v, regis
  syscallarg(off_t) offset;
  } */ *uap = v;
  struct iovec iov;
- struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  off_t offset;
  int fd = SCARG(uap, fd);
 
- if ((fp = fd_getfile_mode(fdp, fd, FREAD)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FREAD)) == NULL)
  return (EBADF);
 
  vp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
     (vp->v_flag & VISTTY)) {
+ FRELE(fp, p);
  return (ESPIPE);
  }
 
@@ -2837,10 +2843,10 @@ sys_pread(struct proc *p, void *v, regis
  iov.iov_len = SCARG(uap, nbyte);
 
  offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
+ if (offset < 0 && vp->v_type != VCHR) {
+ FRELE(fp, p);
  return (EINVAL);
-
- FREF(fp);
+ }
 
  /* dofilereadv() will FRELE the descriptor for us */
  return (dofilereadv(p, fd, fp, &iov, 1, 0, &offset, retval));
@@ -2859,26 +2865,26 @@ sys_preadv(struct proc *p, void *v, regi
  syscallarg(int) pad;
  syscallarg(off_t) offset;
  } */ *uap = v;
- struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  off_t offset;
  int fd = SCARG(uap, fd);
 
- if ((fp = fd_getfile_mode(fdp, fd, FREAD)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FREAD)) == NULL)
  return (EBADF);
 
  vp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
     (vp->v_flag & VISTTY)) {
+ FRELE(fp, p);
  return (ESPIPE);
  }
 
  offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
+ if (offset < 0 && vp->v_type != VCHR) {
+ FRELE(fp, p);
  return (EINVAL);
-
- FREF(fp);
+ }
 
  /* dofilereadv() will FRELE the descriptor for us */
  return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
@@ -2899,18 +2905,18 @@ sys_pwrite(struct proc *p, void *v, regi
  syscallarg(off_t) offset;
  } */ *uap = v;
  struct iovec iov;
- struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  off_t offset;
  int fd = SCARG(uap, fd);
 
- if ((fp = fd_getfile_mode(fdp, fd, FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FWRITE)) == NULL)
  return (EBADF);
 
  vp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
     (vp->v_flag & VISTTY)) {
+ FRELE(fp, p);
  return (ESPIPE);
  }
 
@@ -2918,10 +2924,10 @@ sys_pwrite(struct proc *p, void *v, regi
  iov.iov_len = SCARG(uap, nbyte);
 
  offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
+ if (offset < 0 && vp->v_type != VCHR) {
+ FRELE(fp, p);
  return (EINVAL);
-
- FREF(fp);
+ }
 
  /* dofilewritev() will FRELE the descriptor for us */
  return (dofilewritev(p, fd, fp, &iov, 1, 0, &offset, retval));
@@ -2940,26 +2946,26 @@ sys_pwritev(struct proc *p, void *v, reg
  syscallarg(int) pad;
  syscallarg(off_t) offset;
  } */ *uap = v;
- struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  off_t offset;
  int fd = SCARG(uap, fd);
 
- if ((fp = fd_getfile_mode(fdp, fd, FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FWRITE)) == NULL)
  return (EBADF);
 
  vp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
     (vp->v_flag & VISTTY)) {
+ FRELE(fp, p);
  return (ESPIPE);
  }
 
  offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
+ if (offset < 0 && vp->v_type != VCHR) {
+ FRELE(fp, p);
  return (EINVAL);
-
- FREF(fp);
+ }
 
  /* dofilewritev() will FRELE the descriptor for us */
  return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
Index: miscfs/fuse/fuse_vfsops.c
===================================================================
RCS file: /cvs/src/sys/miscfs/fuse/fuse_vfsops.c,v
retrieving revision 1.15
diff -u -p -r1.15 fuse_vfsops.c
--- miscfs/fuse/fuse_vfsops.c 23 Dec 2014 04:54:45 -0000 1.15
+++ miscfs/fuse/fuse_vfsops.c 14 Jul 2015 21:19:26 -0000
@@ -76,7 +76,7 @@ fusefs_mount(struct mount *mp, const cha
  struct fusefs_args args;
  struct vnode *vp;
  struct file *fp;
- int error;
+ int error = 0;
 
  if (mp->mnt_flag & MNT_UPDATE)
  return (EOPNOTSUPP);
@@ -88,12 +88,16 @@ fusefs_mount(struct mount *mp, const cha
  if ((fp = fd_getfile(p->p_fd, args.fd)) == NULL)
  return (EBADF);
 
- if (fp->f_type != DTYPE_VNODE)
- return (EINVAL);
+ if (fp->f_type != DTYPE_VNODE) {
+ error = EINVAL;
+ goto out;
+ }
 
  vp = fp->f_data;
- if (vp->v_type != VCHR)
- return (EBADF);
+ if (vp->v_type != VCHR) {
+ error = EBADF;
+ goto out;
+ }
 
  fmp = malloc(sizeof(*fmp), M_FUSEFS, M_WAITOK | M_ZERO);
  fmp->mp = mp;
@@ -119,7 +123,9 @@ fusefs_mount(struct mount *mp, const cha
  /* cannot tsleep on mount */
  fuse_device_queue_fbuf(fmp->dev, fbuf);
 
- return (0);
+out:
+ FRELE(fp, p);
+ return (error);
 }
 
 int
Index: sys/filedesc.h
===================================================================
RCS file: /cvs/src/sys/sys/filedesc.h,v
retrieving revision 1.30
diff -u -p -r1.30 filedesc.h
--- sys/filedesc.h 6 May 2015 08:52:17 -0000 1.30
+++ sys/filedesc.h 14 Jul 2015 21:19:26 -0000
@@ -121,7 +121,7 @@ struct filedesc0 {
  * Kernel global variables and routines.
  */
 void filedesc_init(void);
-int dupfdopen(struct filedesc *, int, int, int);
+int dupfdopen(struct proc *, int, int);
 int fdalloc(struct proc *p, int want, int *result);
 void fdexpand(struct proc *);
 int falloc(struct proc *p, struct file **resultfp, int *resultfd);
@@ -133,7 +133,7 @@ int fdrelease(struct proc *p, int);
 void fdremove(struct filedesc *, int);
 void fdcloseexec(struct proc *);
 struct file *fd_getfile(struct filedesc *, int);
-struct file *fd_getfile_mode(struct filedesc *, int, int);
+struct file *fd_getfile_mode(struct proc *, int, int);
 
 int closef(struct file *, struct proc *);
 int getsock(struct proc *, int, struct file **);
Index: uvm/uvm_mmap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.109
diff -u -p -r1.109 uvm_mmap.c
--- uvm/uvm_mmap.c 7 May 2015 08:53:33 -0000 1.109
+++ uvm/uvm_mmap.c 14 Jul 2015 21:19:26 -0000
@@ -389,8 +389,6 @@ sys_mmap(struct proc *p, void *v, regist
  return (EBADF);
  }
 
- FREF(fp);
-
  if (fp->f_type != DTYPE_VNODE) {
  error = ENODEV; /* only mmap vnodes! */
  goto out;

Reply | Threaded
Open this post in threaded view
|

Re: fd_getfile() and fp refcounting

Martin Pieuchot
On 15/07/15(Wed) 17:01, Martin Pieuchot wrote:
> Here's diff a that moves FRELE() inside fd_getfile().  This is some
> plumbing to help unlocking code paths manipulating fp.  The idea is
> to guarantee to the callers of fd_getfile() that the returned fp has
> the necessary reference counts and will not disappear while it is
> being manipulated.
>
> Some code paths are more tricky than others so comments are appreciated.

Seems that some people have interest in this, so here's an updated
version including tame(2) bits.

Now would be a good time to put this in, so oks are welcome.

Index: arch/i386/i386/linux_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/linux_machdep.c,v
retrieving revision 1.46
diff -u -p -U20 -r1.46 linux_machdep.c
--- arch/i386/i386/linux_machdep.c 16 Dec 2014 18:30:03 -0000 1.46
+++ arch/i386/i386/linux_machdep.c 13 Aug 2015 13:27:25 -0000
@@ -411,54 +411,54 @@ linux_fakedev(dev_t dev)
 }
 
 /*
  * We come here in a last attempt to satisfy a Linux ioctl() call
  */
 int
 linux_machdepioctl(struct proc *p, void *v, register_t *retval)
 {
  struct linux_sys_ioctl_args /* {
  syscallarg(int) fd;
  syscallarg(u_long) com;
  syscallarg(caddr_t) data;
  } */ *uap = v;
  struct sys_ioctl_args bia;
  u_long com;
  int error;
 #if (NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL))
  struct vt_mode lvt;
  caddr_t bvtp, sg;
 #endif
- struct filedesc *fdp;
  struct file *fp;
  int fd;
  int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *);
  struct ioctl_pt pt;
 
  fd = SCARG(uap, fd);
  SCARG(&bia, fd) = SCARG(uap, fd);
  SCARG(&bia, data) = SCARG(uap, data);
  com = SCARG(uap, com);
 
- fdp = p->p_fd;
- if ((fp = fd_getfile(fdp, fd)) == NULL)
+ if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
  return (EBADF);
+ FRELE(fp, p);
+ fp = NULL;
 
  switch (com) {
 #if (NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL))
  case LINUX_KDGKBMODE:
  com = KDGKBMODE;
  break;
  case LINUX_KDSKBMODE:
  com = KDSKBMODE;
  if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW)
  SCARG(&bia, data) = (caddr_t)K_RAW;
  break;
  case LINUX_KIOCSOUND:
  SCARG(&bia, data) =
  (caddr_t)(((unsigned long)SCARG(&bia, data)) & 0xffff);
  /* FALLTHROUGH */
  case LINUX_KDMKTONE:
  com = KDMKTONE;
  break;
  case LINUX_KDSETMODE:
  com = KDSETMODE;
@@ -551,41 +551,42 @@ linux_machdepioctl(struct proc *p, void
  break;
  case LINUX_VT_GETSTATE:
  com = VT_GETSTATE;
  break;
  case LINUX_KDGKBTYPE:
  {
  char tmp = KB_101;
 
  /* This is what Linux does */
  return copyout(&tmp, SCARG(uap, data), sizeof(char));
  }
 #endif
  default:
  /*
  * Unknown to us. If it's on a device, just pass it through
  * using PTIOCLINUX, the device itself might be able to
  * make some sense of it.
  * XXX hack: if the function returns EJUSTRETURN,
  * it has stuffed a sysctl return value in pt.data.
  */
- FREF(fp);
+ if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
+ return (EBADF);
  ioctlf = fp->f_ops->fo_ioctl;
  pt.com = SCARG(uap, com);
  pt.data = SCARG(uap, data);
  error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p);
  FRELE(fp, p);
  if (error == EJUSTRETURN) {
  retval[0] = (register_t)pt.data;
  error = 0;
  }
 
  if (error == ENOTTY)
  printf("linux_machdepioctl: invalid ioctl %08lx\n",
     com);
  return (error);
  }
  SCARG(&bia, com) = com;
  return sys_ioctl(p, &bia, retval);
 }
 
 /*
Index: compat/linux/linux_blkio.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_blkio.c,v
retrieving revision 1.9
diff -u -p -U20 -r1.9 linux_blkio.c
--- compat/linux/linux_blkio.c 22 Apr 2012 05:43:14 -0000 1.9
+++ compat/linux/linux_blkio.c 13 Aug 2015 13:27:25 -0000
@@ -55,41 +55,40 @@
 #include <compat/linux/linux_blkio.h>
 
 #include <compat/linux/linux_syscallargs.h>
 
 int
 linux_ioctl_blkio(struct proc *p, struct linux_sys_ioctl_args *uap,
   register_t *retval)
 {
  u_long com;
  long size;
  int error;
  struct filedesc *fdp;
  struct file *fp;
  int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *);
  struct partinfo partp;
  struct disklabel label;
 
         fdp = p->p_fd;
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
- FREF(fp);
  error = 0;
  ioctlf = fp->f_ops->fo_ioctl;
  com = SCARG(uap, com);
 
  switch (com) {
  case LINUX_BLKGETSIZE:
  /*
  * Try to get the partition size of this device. If that
  * fails, it may be a disk without label; try to get
  * the default label and compute the size from it.
  */
  error = ioctlf(fp, DIOCGPART, (caddr_t)&partp, p);
  if (error != 0) {
  error = ioctlf(fp, DIOCGDINFO, (caddr_t)&label, p);
  if (error != 0)
  break;
  size = label.d_nsectors * label.d_ntracks *
     label.d_ncylinders;
  } else
  /* XXX ignores > 32bit blocks */
Index: compat/linux/linux_cdrom.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_cdrom.c,v
retrieving revision 1.12
diff -u -p -U20 -r1.12 linux_cdrom.c
--- compat/linux/linux_cdrom.c 30 Apr 2015 09:20:51 -0000 1.12
+++ compat/linux/linux_cdrom.c 13 Aug 2015 13:27:25 -0000
@@ -60,74 +60,71 @@ bsd_addr_to_linux_addr(bsd, linux, forma
         if (format == CD_MSF_FORMAT) {
         linux->msf.minute = bsd->msf.minute;
  linux->msf.second = bsd->msf.second;
  linux->msf.frame = bsd->msf.frame;
  } else
         linux->lba = bsd->lba;
 }
 
 int
 linux_ioctl_cdrom(p, v, retval)
  struct proc *p;
  void *v;
  register_t *retval;
 {
  struct linux_sys_ioctl_args /* {
  syscallarg(int) fd;
  syscallarg(u_long) com;
  syscallarg(caddr_t) data;
  } */ *uap = v;
  struct file *fp;
- struct filedesc *fdp;
  caddr_t sg;
  u_long com, arg;
  struct sys_ioctl_args ia;
  int error;
 
  union {
         struct cd_toc_entry te;
         struct cd_sub_channel_info scinfo;
  } data;
  union {
         struct ioc_toc_header th;
         struct ioc_read_toc_entry tes;
         struct ioc_play_track ti;
  struct ioc_play_msf msf;
  struct ioc_play_blocks blk;
         struct ioc_read_subchannel sc;
  struct ioc_vol vol;
  } tmpb;
  union {
         struct linux_cdrom_tochdr th;
         struct linux_cdrom_tocentry te;
         struct linux_cdrom_ti ti;
  struct linux_cdrom_msf msf;
  struct linux_cdrom_blk blk;
         struct linux_cdrom_subchnl sc;
  struct linux_cdrom_volctrl vol;
  } tmpl;
 
 
- fdp = p->p_fd;
- if ((fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
  return (EBADF);
- FREF(fp);
 
  com = SCARG(uap, com);
  retval[0] = 0;
                 
  switch (com) {
  case LINUX_CDROMREADTOCHDR:
         error = (*fp->f_ops->fo_ioctl)(fp, CDIOREADTOCHEADER,
     (caddr_t)&tmpb.th, p);
         if (error)
  goto out;
  tmpl.th.cdth_trk0 = tmpb.th.starting_track;
  tmpl.th.cdth_trk1 = tmpb.th.ending_track;
  error = copyout(&tmpl, SCARG(uap, data), sizeof tmpl.th);
  goto out;
  case LINUX_CDROMREADTOCENTRY:
  error = copyin(SCARG(uap, data), &tmpl.te, sizeof tmpl.te);
  if (error)
         goto out;
 
  sg = stackgap_init(p);
Index: compat/linux/linux_fdio.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_fdio.c,v
retrieving revision 1.7
diff -u -p -U20 -r1.7 linux_fdio.c
--- compat/linux/linux_fdio.c 22 Apr 2012 05:43:14 -0000 1.7
+++ compat/linux/linux_fdio.c 13 Aug 2015 13:27:25 -0000
@@ -61,41 +61,40 @@
 
 int
 linux_ioctl_fdio(struct proc *p, struct linux_sys_ioctl_args *uap,
  register_t *retval)
 {
  struct filedesc *fdp;
  struct file *fp;
  int error;
  int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *);
  u_long com;
  struct fd_type fparams;
  struct linux_floppy_struct lflop;
  struct linux_floppy_drive_struct ldrive;
 
  com = (u_long)SCARG(uap, data);
 
  fdp = p->p_fd;
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
 
- FREF(fp);
  com = SCARG(uap, com);
  ioctlf = fp->f_ops->fo_ioctl;
 
  retval[0] = error = 0;
 
  switch (com) {
  case LINUX_FDMSGON:
  case LINUX_FDMSGOFF:
  case LINUX_FDTWADDLE:
  case LINUX_FDCLRPRM:
  /* whatever you say */
  break;
  case LINUX_FDPOLLDRVSTAT:
  /*
  * Just fill in some innocent defaults.
  */
  memset(&ldrive, 0, sizeof ldrive);
  ldrive.fd_ref = 1;
  ldrive.maxblock = 2;
  ldrive.maxtrack = ldrive.track = 1;
Index: compat/linux/linux_file.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_file.c,v
retrieving revision 1.30
diff -u -p -U20 -r1.30 linux_file.c
--- compat/linux/linux_file.c 26 Mar 2014 05:23:42 -0000 1.30
+++ compat/linux/linux_file.c 13 Aug 2015 13:27:25 -0000
@@ -181,41 +181,40 @@ linux_sys_open(p, v, retval)
  SCARG(&boa, path) = SCARG(uap, path);
  SCARG(&boa, flags) = fl;
  SCARG(&boa, mode) = SCARG(uap, mode);
 
  if ((error = sys_open(p, &boa, retval)))
  return error;
 
  /*
  * this bit from sunos_misc.c (and svr4_fcntl.c).
  * If we are a session leader, and we don't have a controlling
  * terminal yet, and the O_NOCTTY flag is not set, try to make
  * this the controlling terminal.
  */
         if (!(fl & O_NOCTTY) && SESS_LEADER(p->p_p) &&
     !(p->p_p->ps_flags & PS_CONTROLT)) {
                 struct filedesc *fdp = p->p_fd;
                 struct file     *fp;
 
  if ((fp = fd_getfile(fdp, *retval)) == NULL)
  return (EBADF);
- FREF(fp);
                 if (fp->f_type == DTYPE_VNODE)
                         (fp->f_ops->fo_ioctl) (fp, TIOCSCTTY, (caddr_t) 0, p);
  FRELE(fp, p);
         }
  return 0;
 }
 
 int
 linux_sys_lseek(p, v, retval)
  struct proc *p;
  void *v;
  register_t *retval;
 {
  struct linux_sys_lseek_args /* {
  syscallarg(int) fd;
  syscallarg(long) offset;
  syscallarg(int) whence;
  } */ *uap = v;
  struct sys_lseek_args bla;
 
@@ -403,46 +402,48 @@ linux_sys_fcntl(p, v, retval)
  if ((error = copyout(&bfl, bfp, sizeof bfl)))
  return error;
  SCARG(&fca, fd) = fd;
  SCARG(&fca, cmd) = cmd;
  SCARG(&fca, arg) = bfp;
  return sys_fcntl(p, &fca, retval);
  break;
  case LINUX_F_SETOWN:
  case LINUX_F_GETOWN:
  /*
  * We need to route around the normal fcntl() for these calls,
  * since it uses TIOC{G,S}PGRP, which is too restrictive for
  * Linux F_{G,S}ETOWN semantics. For sockets, this problem
  * does not exist.
  */
  fdp = p->p_fd;
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
  if (fp->f_type == DTYPE_SOCKET) {
  cmd = cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN;
+ FRELE(fp, p);
  break;
  }
  vp = (struct vnode *)fp->f_data;
- if (vp->v_type != VCHR)
+ if (vp->v_type != VCHR) {
+ FRELE(fp, p);
  return EINVAL;
- FREF(fp);
+ }
  error = VOP_GETATTR(vp, &va, p->p_ucred, p);
  FRELE(fp, p);
  if (error)
  return error;
  d_tty = cdevsw[major(va.va_rdev)].d_tty;
  if (!d_tty || (!(tp = (*d_tty)(va.va_rdev))))
  return EINVAL;
  if (cmd == LINUX_F_GETOWN) {
  retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
  return 0;
  }
  if ((long)arg <= 0) {
  pgid = -(long)arg;
  } else {
  struct process *pr = prfind((long)arg);
  if (pr == 0)
  return (ESRCH);
  pgid = (long)pr->ps_pgrp->pg_id;
  }
  pgrp = pgfind(pgid);
Index: compat/linux/linux_hdio.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_hdio.c,v
retrieving revision 1.9
diff -u -p -U20 -r1.9 linux_hdio.c
--- compat/linux/linux_hdio.c 26 Mar 2014 05:23:42 -0000 1.9
+++ compat/linux/linux_hdio.c 13 Aug 2015 13:27:25 -0000
@@ -64,41 +64,40 @@ int
 linux_ioctl_hdio(struct proc *p, struct linux_sys_ioctl_args *uap,
  register_t *retval)
 {
  u_long com;
  int error, error1;
  caddr_t sg;
  struct filedesc *fdp;
  struct file *fp;
  int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *);
  struct ataparams *atap, ata;
  struct atareq req;
  struct disklabel label, *labp;
  struct partinfo partp;
  struct linux_hd_geometry hdg;
  struct linux_hd_big_geometry hdg_big;
 
  fdp = p->p_fd;
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
 
- FREF(fp);
  com = SCARG(uap, com);
  ioctlf = fp->f_ops->fo_ioctl;
  retval[0] = error = 0;
 
  com = SCARG(uap, com);
 
  switch (com) {
  case LINUX_HDIO_OBSOLETE_IDENTITY:
  case LINUX_HDIO_GET_IDENTITY:
  sg = stackgap_init(p);
  atap = stackgap_alloc(&sg, DEV_BSIZE);
  if (atap == NULL) {
  error = ENOMEM;
  break;
  }
 
  req.flags = ATACMD_READ;
  req.command = WDCC_IDENTIFY;
  req.databuf = (caddr_t)atap;
  req.datalen = DEV_BSIZE;
Index: compat/linux/linux_socket.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_socket.c,v
retrieving revision 1.61
diff -u -p -U20 -r1.61 linux_socket.c
--- compat/linux/linux_socket.c 6 May 2015 08:52:17 -0000 1.61
+++ compat/linux/linux_socket.c 13 Aug 2015 13:27:25 -0000
@@ -1355,41 +1355,40 @@ linux_ioctl_socket(p, v, retval)
  register_t *retval;
 {
  struct linux_sys_ioctl_args /* {
  syscallarg(int) fd;
  syscallarg(u_long) com;
  syscallarg(caddr_t) data;
  } */ *uap = v;
  u_long com;
  struct sys_ioctl_args ia;
  struct file *fp;
  struct filedesc *fdp;
  struct vnode *vp;
  int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *);
  struct ioctl_pt pt;
  void *data = SCARG(uap, data);
  int error = 0, isdev = 0, dosys = 1;
 
  fdp = p->p_fd;
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
- FREF(fp);
 
  if (fp->f_type == DTYPE_VNODE) {
  vp = (struct vnode *)fp->f_data;
  isdev = vp->v_type == VCHR;
  }
 
  /*
  * Don't try to interpret socket ioctl calls that are done
  * on a device file descriptor, just pass them through, to
  * emulate Linux behaviour. Use PTIOCLINUX so that the
  * device will only handle these if it's prepared to do
  * so, to avoid unexpected things from happening.
  */
  if (isdev) {
  dosys = 0;
  ioctlf = fp->f_ops->fo_ioctl;
  pt.com = SCARG(uap, com);
  pt.data = data;
  error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p);
  /*
Index: compat/linux/linux_termios.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_termios.c,v
retrieving revision 1.18
diff -u -p -U20 -r1.18 linux_termios.c
--- compat/linux/linux_termios.c 30 Apr 2015 09:20:51 -0000 1.18
+++ compat/linux/linux_termios.c 13 Aug 2015 13:27:25 -0000
@@ -432,55 +432,52 @@ bsd_termios_to_linux_termios(bts, lts)
  lts->c_cc[LINUX_VDISCARD] = bts->c_cc[VDISCARD];
  lts->c_cc[LINUX_VREPRINT] = bts->c_cc[VREPRINT];
  lts->c_cc[LINUX_VSWTC] = 0;
 
  /* XXX should be fixed someday */
  lts->c_line = 0;
 }
 
 int
 linux_ioctl_termios(p, v, retval)
  struct proc *p;
  void *v;
  register_t *retval;
 {
  struct linux_sys_ioctl_args /* {
  syscallarg(int) fd;
  syscallarg(u_long) com;
  syscallarg(caddr_t) data;
  } */ *uap = v;
  struct file *fp;
- struct filedesc *fdp;
  u_long com;
  struct linux_termio tmplt;
  struct linux_termios tmplts;
  struct termios tmpbts;
  caddr_t sg;
  int idat;
  struct sys_ioctl_args ia;
  char tioclinux;
  int error = 0;
 
- fdp = p->p_fd;
- if ((fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, SCARG(uap, fd), FREAD|FWRITE)) == NULL)
  return (EBADF);
- FREF(fp);
 
  com = SCARG(uap, com);
  retval[0] = 0;
                 
  switch (com) {
  case LINUX_TCGETS:
  error = (*fp->f_ops->fo_ioctl)(fp, TIOCGETA, (caddr_t)&tmpbts,
     p);
  if (error)
  goto out;
  bsd_termios_to_linux_termios(&tmpbts, &tmplts);
  error = copyout(&tmplts, SCARG(uap, data), sizeof tmplts);
  goto out;
  case LINUX_TCSETS:
  case LINUX_TCSETSW:
  case LINUX_TCSETSF:
  /*
  * First fill in all fields, so that we keep the current
  * values for fields that Linux doesn't know about.
  */
Index: dev/systrace.c
===================================================================
RCS file: /cvs/src/sys/dev/systrace.c,v
retrieving revision 1.75
diff -u -p -U20 -r1.75 systrace.c
--- dev/systrace.c 14 Mar 2015 03:38:46 -0000 1.75
+++ dev/systrace.c 13 Aug 2015 13:27:25 -0000
@@ -1041,90 +1041,101 @@ systrace_policy(struct fsystrace *fst, s
 }
 
 int
 systrace_processready(struct str_process *strp)
 {
  if (ISSET(strp->flags, STR_PROC_ONQUEUE))
  return (EBUSY);
 
  if (!ISSET(strp->flags, STR_PROC_WAITANSWER))
  return (EBUSY);
 
  if (strp->proc->p_stat != SSLEEP)
  return (EBUSY);
 
  return (0);
 }
 
 int
 systrace_getcwd(struct fsystrace *fst, struct str_process *strp, int atfd)
 {
+ struct file *fp = NULL;
  struct filedesc *myfdp, *fdp;
  struct vnode *dvp, *odvp;
- int error;
+ int error = 0;
 
  DPRINTF(("%s: %d\n", __func__, strp->pid));
 
  error = systrace_processready(strp);
  if (error)
  return (error);
 
  myfdp = curproc->p_fd;
  fdp = strp->proc->p_fd;
  if (myfdp == NULL || fdp == NULL)
  return (EINVAL);
 
- if (atfd == AT_FDCWD)
- dvp = fdp->fd_cdir;
- else {
- struct file *fp = fd_getfile(fdp, atfd);
- if (fp == NULL || fp->f_type != DTYPE_VNODE)
+ if (atfd != AT_FDCWD) {
+ if ((fp = fd_getfile(fdp, atfd)) == NULL)
  return (EINVAL);
+
+ if (fp->f_type != DTYPE_VNODE) {
+ error = EINVAL;
+ goto out;
+ }
  dvp = (struct vnode *)fp->f_data;
- if (dvp->v_type != VDIR)
- return (EINVAL);
+ if (dvp->v_type != VDIR) {
+ error = EINVAL;
+ goto out;
+ }
+ } else {
+ dvp = fdp->fd_cdir;
  }
 
  /* Is there a STRIOCGETCWD currently in effect? */
  if (fst->fd_pid == 0) {
  /* nope: just save the current values */
  fst->fd_cdir = myfdp->fd_cdir;
  fst->fd_rdir = myfdp->fd_rdir;
  } else {
  /* yep: carefully release the current values */
  odvp = myfdp->fd_rdir;
  myfdp->fd_rdir = fst->fd_rdir;
  if (odvp != NULL)
  vrele(odvp);
  odvp = myfdp->fd_cdir;
  myfdp->fd_cdir = fst->fd_cdir;
  if (odvp != NULL)
  vrele(odvp);
  }
  fst->fd_pid = strp->pid;
 
  if ((myfdp->fd_cdir = dvp) != NULL)
  vref(myfdp->fd_cdir);
  if ((myfdp->fd_rdir = fdp->fd_rdir) != NULL)
  vref(myfdp->fd_rdir);
 
- return (0);
+out:
+ if (fp != NULL)
+ FRELE(fp, strp->proc);
+
+ return (error);
 }
 
 int
 systrace_restorecwd(struct fsystrace *fst, struct proc *p)
 {
  struct filedesc *fdp;
  struct vnode *rvp, *cvp;
 
  if (!fst->fd_pid)
  return (EINVAL);
 
  fdp = p->p_fd;
 
  /*
  * Restore original root and current directories and release the
  * ones from the other process.
  */
  rvp = fdp->fd_rdir;
  cvp = fdp->fd_cdir;
  fdp->fd_rdir = fst->fd_rdir;
Index: kern/kern_descrip.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_descrip.c,v
retrieving revision 1.120
diff -u -p -U20 -r1.120 kern_descrip.c
--- kern/kern_descrip.c 17 May 2015 01:22:01 -0000 1.120
+++ kern/kern_descrip.c 13 Aug 2015 13:27:25 -0000
@@ -172,82 +172,85 @@ fd_unused(struct filedesc *fdp, int fd)
 #ifdef DIAGNOSTIC
  if (fd > fdp->fd_lastfile)
  panic("fd_unused: fd_lastfile inconsistent");
 #endif
  if (fd == fdp->fd_lastfile)
  fdp->fd_lastfile = find_last_set(fdp, fd);
  fdp->fd_openfd--;
 }
 
 struct file *
 fd_getfile(struct filedesc *fdp, int fd)
 {
  struct file *fp;
 
  if ((u_int)fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)
  return (NULL);
 
  if (!FILE_IS_USABLE(fp))
  return (NULL);
 
+ FREF(fp);
  return (fp);
 }
 
 struct file *
-fd_getfile_mode(struct filedesc *fdp, int fd, int mode)
+fd_getfile_mode(struct proc *p, int fd, int mode)
 {
  struct file *fp;
 
  KASSERT(mode != 0);
 
- fp = fd_getfile(fdp, fd);
+ if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
+ return (NULL);
 
- if (fp == NULL || (fp->f_flag & mode) == 0)
+ if ((fp->f_flag & mode) == 0) {
+ FRELE(fp, p);
  return (NULL);
+ }
 
  return (fp);
 }
 
 /*
  * System calls on descriptors.
  */
 
 /*
  * Duplicate a file descriptor.
  */
 /* ARGSUSED */
 int
 sys_dup(struct proc *p, void *v, register_t *retval)
 {
  struct sys_dup_args /* {
  syscallarg(int) fd;
  } */ *uap = v;
  struct filedesc *fdp = p->p_fd;
  int old = SCARG(uap, fd);
  struct file *fp;
  int new;
  int error;
 
 restart:
  if ((fp = fd_getfile(fdp, old)) == NULL)
  return (EBADF);
- FREF(fp);
  fdplock(fdp);
  if ((error = fdalloc(p, 0, &new)) != 0) {
  FRELE(fp, p);
  if (error == ENOSPC) {
  fdexpand(p);
  fdpunlock(fdp);
  goto restart;
  }
  goto out;
  }
  error = finishdup(p, fp, old, new, retval, 0);
 
 out:
  fdpunlock(fdp);
  return (error);
 }
 
 /*
  * Duplicate a file descriptor to a particular value.
  */
@@ -270,104 +273,104 @@ sys_dup3(struct proc *p, void *v, regist
  syscallarg(int) to;
  syscallarg(int) flags;
  } */ *uap = v;
 
  if (SCARG(uap, from) == SCARG(uap, to))
  return (EINVAL);
  if (SCARG(uap, flags) & ~O_CLOEXEC)
  return (EINVAL);
  return (dodup3(p, SCARG(uap, from), SCARG(uap, to),
     SCARG(uap, flags), retval));
 }
 
 int
 dodup3(struct proc *p, int old, int new, int flags, register_t *retval)
 {
  struct filedesc *fdp = p->p_fd;
  struct file *fp;
  int i, error;
 
 restart:
- if ((fp = fd_getfile(fdp, old)) == NULL)
- return (EBADF);
  if ((u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
     (u_int)new >= maxfiles)
  return (EBADF);
+ if ((fp = fd_getfile(fdp, old)) == NULL)
+ return (EBADF);
  if (old == new) {
  /*
  * NOTE! This doesn't clear the close-on-exec flag. This might
  * or might not be the intended behavior from the start, but
  * this is what everyone else does.
  */
  *retval = new;
+ FRELE(fp, p);
  return (0);
  }
- FREF(fp);
  fdplock(fdp);
  if (new >= fdp->fd_nfiles) {
  if ((error = fdalloc(p, new, &i)) != 0) {
  FRELE(fp, p);
  if (error == ENOSPC) {
  fdexpand(p);
  fdpunlock(fdp);
  goto restart;
  }
  goto out;
  }
  if (new != i)
  panic("dup2: fdalloc");
  fd_unused(fdp, new);
  }
  /* finishdup() does FRELE */
  error = finishdup(p, fp, old, new, retval, 1);
  if (!error && flags & O_CLOEXEC)
  fdp->fd_ofileflags[new] |= UF_EXCLOSE;
 
 out:
  fdpunlock(fdp);
  return (error);
 }
 
 /*
  * The file control system call.
  */
 /* ARGSUSED */
 int
 sys_fcntl(struct proc *p, void *v, register_t *retval)
 {
  struct sys_fcntl_args /* {
  syscallarg(int) fd;
  syscallarg(int) cmd;
  syscallarg(void *) arg;
  } */ *uap = v;
  int fd = SCARG(uap, fd);
  struct filedesc *fdp = p->p_fd;
- struct file *fp;
+ struct file *fp, *fp0;
  struct vnode *vp;
  int i, tmp, newmin, flg = F_POSIX;
  struct flock fl;
- int error = 0;
+ int lost, error = 0;
 
 restart:
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- FREF(fp);
+
  switch (SCARG(uap, cmd)) {
 
  case F_DUPFD:
  case F_DUPFD_CLOEXEC:
  newmin = (long)SCARG(uap, arg);
  if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
     (u_int)newmin >= maxfiles) {
  error = EINVAL;
  break;
  }
  fdplock(fdp);
  if ((error = fdalloc(p, newmin, &i)) != 0) {
  FRELE(fp, p);
  if (error == ENOSPC) {
  fdexpand(p);
  fdpunlock(fdp);
  goto restart;
  }
  } else {
  /* finishdup will FRELE for us. */
@@ -491,41 +494,45 @@ restart:
  break;
 
  case F_WRLCK:
  if ((fp->f_flag & FWRITE) == 0) {
  error = EBADF;
  goto out;
  }
  atomic_setbits_int(&fdp->fd_flags, FD_ADVLOCK);
  error = VOP_ADVLOCK(vp, fdp, F_SETLK, &fl, flg);
  break;
 
  case F_UNLCK:
  error = VOP_ADVLOCK(vp, fdp, F_UNLCK, &fl, F_POSIX);
  goto out;
 
  default:
  error = EINVAL;
  goto out;
  }
 
- if (fp != fd_getfile(fdp, fd)) {
+ fp0 = fd_getfile(fdp, fd);
+ lost = (fp != fp0);
+ if (fp0 != NULL)
+ FRELE(fp0, p);
+ if (lost) {
  /*
  * We have lost the race with close() or dup2();
  * unlock, pretend that we've won the race and that
  * lock had been removed by close()
  */
  fl.l_whence = SEEK_SET;
  fl.l_start = 0;
  fl.l_len = 0;
  VOP_ADVLOCK(vp, fdp, F_UNLCK, &fl, F_POSIX);
  fl.l_type = F_UNLCK;
  }
  goto out;
 
 
  case F_GETLK:
  if (fp->f_type != DTYPE_VNODE) {
  error = EBADF;
  break;
  }
  vp = (struct vnode *)fp->f_data;
@@ -631,110 +638,111 @@ fdrelease(struct proc *p, int fd)
  if (fp == NULL)
  return (EBADF);
  FREF(fp);
  *fpp = NULL;
  fd_unused(fdp, fd);
  if (fd < fdp->fd_knlistsize)
  knote_fdclose(p, fd);
  return (closef(fp, p));
 }
 
 /*
  * Close a file descriptor.
  */
 /* ARGSUSED */
 int
 sys_close(struct proc *p, void *v, register_t *retval)
 {
  struct sys_close_args /* {
  syscallarg(int) fd;
  } */ *uap = v;
- int fd = SCARG(uap, fd), error;
+ int fd = SCARG(uap, fd);
  struct filedesc *fdp = p->p_fd;
+ struct file *fp;
+ int error;
 
- if (fd_getfile(fdp, fd) == NULL)
+ if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
  fdplock(fdp);
+ FRELE(fp, p);
  error = fdrelease(p, fd);
  fdpunlock(fdp);
 
  return (error);
 }
 
 /*
  * Return status information about a file descriptor.
  */
 int
 sys_fstat(struct proc *p, void *v, register_t *retval)
 {
  struct sys_fstat_args /* {
  syscallarg(int) fd;
  syscallarg(struct stat *) sb;
  } */ *uap = v;
  int fd = SCARG(uap, fd);
  struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct stat ub;
  int error;
 
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- FREF(fp);
  error = (*fp->f_ops->fo_stat)(fp, &ub, p);
  FRELE(fp, p);
  if (error == 0) {
  /*
  * Don't let non-root see generation numbers
  * (for NFS security)
  */
  if (suser(p, 0))
  ub.st_gen = 0;
  error = copyout((caddr_t)&ub, (caddr_t)SCARG(uap, sb),
     sizeof (ub));
  }
 #ifdef KTRACE
  if (error == 0 && KTRPOINT(p, KTR_STRUCT))
  ktrstat(p, &ub);
 #endif
  return (error);
 }
 
 /*
  * Return pathconf information about a file descriptor.
  */
 /* ARGSUSED */
 int
 sys_fpathconf(struct proc *p, void *v, register_t *retval)
 {
  struct sys_fpathconf_args /* {
  syscallarg(int) fd;
  syscallarg(int) name;
  } */ *uap = v;
  int fd = SCARG(uap, fd);
  struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  int error;
 
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- FREF(fp);
  switch (fp->f_type) {
  case DTYPE_PIPE:
  case DTYPE_SOCKET:
  if (SCARG(uap, name) != _PC_PIPE_BUF) {
  error = EINVAL;
  break;
  }
  *retval = PIPE_BUF;
  error = 0;
  break;
 
  case DTYPE_VNODE:
  vp = (struct vnode *)fp->f_data;
  vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  error = VOP_PATHCONF(vp, SCARG(uap, name), retval);
  VOP_UNLOCK(vp, 0, p);
  break;
 
  default:
  error = EOPNOTSUPP;
@@ -1158,43 +1166,44 @@ fdrop(struct file *fp, struct proc *p)
  * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
  */
 /* ARGSUSED */
 int
 sys_flock(struct proc *p, void *v, register_t *retval)
 {
  struct sys_flock_args /* {
  syscallarg(int) fd;
  syscallarg(int) how;
  } */ *uap = v;
  int fd = SCARG(uap, fd);
  int how = SCARG(uap, how);
  struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  struct flock lf;
  int error;
 
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- if (fp->f_type != DTYPE_VNODE)
- return (EOPNOTSUPP);
- FREF(fp);
+ if (fp->f_type != DTYPE_VNODE) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
  vp = (struct vnode *)fp->f_data;
  lf.l_whence = SEEK_SET;
  lf.l_start = 0;
  lf.l_len = 0;
  if (how & LOCK_UN) {
  lf.l_type = F_UNLCK;
  fp->f_iflags &= ~FIF_HASLOCK;
  error = VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
  goto out;
  }
  if (how & LOCK_EX)
  lf.l_type = F_WRLCK;
  else if (how & LOCK_SH)
  lf.l_type = F_RDLCK;
  else {
  error = EINVAL;
  goto out;
  }
  fp->f_iflags |= FIF_HASLOCK;
  if (how & LOCK_NB)
@@ -1218,81 +1227,86 @@ out:
 int
 filedescopen(dev_t dev, int mode, int type, struct proc *p)
 {
 
  /*
  * XXX Kludge: set curproc->p_dupfd to contain the value of the
  * the file descriptor being sought for duplication. The error
  * return ensures that the vnode for this device will be released
  * by vn_open. Open will detect this special error and take the
  * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
  * will simply report the error.
  */
  p->p_dupfd = minor(dev);
  return (ENODEV);
 }
 
 /*
  * Duplicate the specified descriptor to a free descriptor.
  */
 int
-dupfdopen(struct filedesc *fdp, int indx, int dfd, int mode)
+dupfdopen(struct proc *p, int indx, int mode)
 {
+ struct filedesc *fdp = p->p_fd;
+ int dfd = p->p_dupfd;
  struct file *wfp;
 
  fdpassertlocked(fdp);
 
  /*
  * Assume that the filename was user-specified; applications do
  * not tend to open /dev/fd/# when they can just call dup()
  */
- if ((curproc->p_p->ps_flags & (PS_SUGIDEXEC | PS_SUGID))) {
- if (curproc->p_descfd == 255)
+ if ((p->p_p->ps_flags & (PS_SUGIDEXEC | PS_SUGID))) {
+ if (p->p_descfd == 255)
  return (EPERM);
- if (curproc->p_descfd != curproc->p_dupfd)
+ if (p->p_descfd != p->p_dupfd)
  return (EPERM);
  }
 
  /*
  * If the to-be-dup'd fd number is greater than the allowed number
  * of file descriptors, or the fd to be dup'd has already been
  * closed, reject. Note, there is no need to check for new == old
  * because fd_getfile will return NULL if the file at indx is
  * newly created by falloc (FIF_LARVAL).
  */
  if ((wfp = fd_getfile(fdp, dfd)) == NULL)
  return (EBADF);
 
  /*
  * Check that the mode the file is being opened for is a
  * subset of the mode of the existing descriptor.
  */
- if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
+ if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) {
+ FRELE(wfp, p);
  return (EACCES);
- if (wfp->f_count == LONG_MAX-2)
+ }
+ if (wfp->f_count == LONG_MAX-2) {
+ FRELE(wfp, p);
  return (EDEADLK);
-
+ }
  fdp->fd_ofiles[indx] = wfp;
  fdp->fd_ofileflags[indx] = (fdp->fd_ofileflags[indx] & UF_EXCLOSE) |
-    (fdp->fd_ofileflags[dfd] & ~UF_EXCLOSE);
- wfp->f_count++;
+    (fdp->fd_ofileflags[p->p_dupfd] & ~UF_EXCLOSE);
  fd_used(fdp, indx);
+
  return (0);
 }
 
 /*
  * Close any files on exec?
  */
 void
 fdcloseexec(struct proc *p)
 {
  struct filedesc *fdp = p->p_fd;
  int fd;
 
  fdplock(fdp);
  for (fd = 0; fd <= fdp->fd_lastfile; fd++)
  if (fdp->fd_ofileflags[fd] & UF_EXCLOSE)
  (void) fdrelease(p, fd);
  fdpunlock(fdp);
 }
 
 int
Index: kern/kern_event.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_event.c,v
retrieving revision 1.61
diff -u -p -U20 -r1.61 kern_event.c
--- kern/kern_event.c 19 Dec 2014 05:59:21 -0000 1.61
+++ kern/kern_event.c 13 Aug 2015 13:27:25 -0000
@@ -463,45 +463,47 @@ sys_kqueue(struct proc *p, void *v, regi
 }
 
 int
 sys_kevent(struct proc *p, void *v, register_t *retval)
 {
  struct filedesc* fdp = p->p_fd;
  struct sys_kevent_args /* {
  syscallarg(int) fd;
  syscallarg(const struct kevent *) changelist;
  syscallarg(int) nchanges;
  syscallarg(struct kevent *) eventlist;
  syscallarg(int) nevents;
  syscallarg(const struct timespec *) timeout;
  } */ *uap = v;
  struct kevent *kevp;
  struct kqueue *kq;
  struct file *fp;
  struct timespec ts;
  int i, n, nerrors, error;
 
- if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL ||
-    (fp->f_type != DTYPE_KQUEUE))
+ if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
 
- FREF(fp);
+ if (fp->f_type != DTYPE_KQUEUE) {
+ error = EBADF;
+ goto done;
+ }
 
  if (SCARG(uap, timeout) != NULL) {
  error = copyin(SCARG(uap, timeout), &ts, sizeof(ts));
  if (error)
  goto done;
 #ifdef KTRACE
  if (KTRPOINT(p, KTR_STRUCT))
  ktrreltimespec(p, &ts);
 #endif
  SCARG(uap, timeout) = &ts;
  }
 
  kq = (struct kqueue *)fp->f_data;
  nerrors = 0;
 
  while (SCARG(uap, nchanges) > 0) {
  n = SCARG(uap, nchanges) > KQ_NEVENTS
  ? KQ_NEVENTS : SCARG(uap, nchanges);
  error = copyin(SCARG(uap, changelist), kq->kq_kev,
     n * sizeof(struct kevent));
@@ -558,41 +560,40 @@ kqueue_register(struct kqueue *kq, struc
 
  if (kev->filter < 0) {
  if (kev->filter + EVFILT_SYSCOUNT < 0)
  return (EINVAL);
  fops = sysfilt_ops[~kev->filter]; /* to 0-base index */
  }
 
  if (fops == NULL) {
  /*
  * XXX
  * filter attach routine is responsible for ensuring that
  * the identifier can be attached to it.
  */
  return (EINVAL);
  }
 
  if (fops->f_isfd) {
  /* validate descriptor */
  if ((fp = fd_getfile(fdp, kev->ident)) == NULL)
  return (EBADF);
- FREF(fp);
 
  if (kev->ident < fdp->fd_knlistsize) {
  SLIST_FOREACH(kn, &fdp->fd_knlist[kev->ident], kn_link)
  if (kq == kn->kn_kq &&
     kev->filter == kn->kn_filter)
  break;
  }
  } else {
  if (fdp->fd_knhashmask != 0) {
  struct klist *list;
 
  list = &fdp->fd_knhash[
     KN_HASH((u_long)kev->ident, fdp->fd_knhashmask)];
  SLIST_FOREACH(kn, list, kn_link)
  if (kev->ident == kn->kn_id &&
     kq == kn->kn_kq &&
     kev->filter == kn->kn_filter)
  break;
  }
  }
Index: kern/kern_exec.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.163
diff -u -p -U20 -r1.163 kern_exec.c
--- kern/kern_exec.c 22 Jul 2015 05:31:33 -0000 1.163
+++ kern/kern_exec.c 13 Aug 2015 13:27:25 -0000
@@ -591,41 +591,44 @@ sys_execve(struct proc *p, void *v, regi
  panic("sys_execve: falloc indx != i");
 #endif
  if ((error = cdevvp(getnulldev(), &vp)) != 0) {
  fdremove(p->p_fd, indx);
  closef(fp, p);
  break;
  }
  if ((error = VOP_OPEN(vp, flags, cred, p)) != 0) {
  fdremove(p->p_fd, indx);
  closef(fp, p);
  vrele(vp);
  break;
  }
  if (flags & FWRITE)
  vp->v_writecount++;
  fp->f_flag = flags;
  fp->f_type = DTYPE_VNODE;
  fp->f_ops = &vnops;
  fp->f_data = (caddr_t)vp;
  FILE_SET_MATURE(fp, p);
+ } else {
+ FRELE(fp, p);
  }
+
  }
  fdpunlock(p->p_fd);
  if (error)
  goto exec_abort;
  } else
  atomic_clearbits_int(&pr->ps_flags, PS_SUGID);
 
  /*
  * Reset the saved ugids and update the process's copy of the
  * creds if the creds have been changed
  */
  if (cred->cr_uid != cred->cr_svuid ||
     cred->cr_gid != cred->cr_svgid) {
  /* make sure we have unshared ucreds */
  p->p_ucred = cred = crcopy(cred);
  cred->cr_svuid = cred->cr_uid;
  cred->cr_svgid = cred->cr_gid;
  }
 
  if (pr->ps_ucred != cred) {
Index: kern/kern_tame.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_tame.c,v
retrieving revision 1.18
diff -u -p -U20 -r1.18 kern_tame.c
--- kern/kern_tame.c 29 Jul 2015 17:55:27 -0000 1.18
+++ kern/kern_tame.c 13 Aug 2015 13:39:04 -0000
@@ -446,50 +446,54 @@ tame_cmsg_recv(struct proc *p, void *v,
  if ((p->p_p->ps_tame & _TM_CMSG) == 0)
  return tame_fail(p, EPERM, TAME_CMSG);
 
  /* In OpenBSD, a CMSG only contains one SCM_RIGHTS.  Check it. */
  fdp = (int *)CMSG_DATA(cmsg);
  nfds = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg))) /
     sizeof(struct file *);
  for (i = 0; i < nfds; i++) {
  struct vnode *vp;
 
  fd = *fdp++;
  fp = fd_getfile(p->p_fd, fd);
  if (fp == NULL)
  return tame_fail(p, EBADF, TAME_CMSG);
 
  /* Only allow passing of sockets, pipes, and pure files */
  printf("f_type %d\n", fp->f_type);
  switch (fp->f_type) {
  case DTYPE_SOCKET:
  case DTYPE_PIPE:
+ FRELE(fp, p);
  continue;
  case DTYPE_VNODE:
  vp = (struct vnode *)fp->f_data;
  printf("v_type %d\n", vp->v_type);
- if (vp->v_type == VREG)
+ if (vp->v_type == VREG) {
+ FRELE(fp, p);
  continue;
+ }
  break;
  default:
  break;
  }
+ FRELE(fp, p);
  printf("bad fd type\n");
  return tame_fail(p, EPERM, TAME_CMSG);
  }
  return (0);
 }
 
 /*
  * When tamed, default prevents sending of a cmsg.
  * If CMSG flag is set,
  */
 int
 tame_cmsg_send(struct proc *p, void *v, int controllen)
 {
  struct mbuf *control = v;
  struct msghdr tmp;
  struct cmsghdr *cmsg;
  int *fdp, fd;
  struct file *fp;
  int nfds, i;
 
@@ -516,50 +520,54 @@ tame_cmsg_send(struct proc *p, void *v,
  if (cmsg == NULL)
  return (0);
 
  /* In OpenBSD, a CMSG only contains one SCM_RIGHTS.  Check it. */
  fdp = (int *)CMSG_DATA(cmsg);
  nfds = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg))) /
     sizeof(struct file *);
  for (i = 0; i < nfds; i++) {
  struct vnode *vp;
 
  fd = *fdp++;
  fp = fd_getfile(p->p_fd, fd);
  if (fp == NULL)
  return tame_fail(p, EBADF, TAME_CMSG);
 
  /* Only allow passing of sockets, pipes, and pure files */
  printf("f_type %d\n", fp->f_type);
  switch (fp->f_type) {
  case DTYPE_SOCKET:
  case DTYPE_PIPE:
+ FRELE(fp, p);
  continue;
  case DTYPE_VNODE:
  vp = (struct vnode *)fp->f_data;
  printf("v_type %d\n", vp->v_type);
- if (vp->v_type == VREG)
+ if (vp->v_type == VREG) {
+ FRELE(fp, p);
  continue;
+ }
  break;
  default:
  break;
  }
+ FRELE(fp, p);
  /* Not allowed to send a bad fd type */
  return tame_fail(p, EPERM, TAME_CMSG);
  }
  return (0);
 }
 
 int
 tame_sysctl_check(struct proc *p, int namelen, int *name, void *new)
 {
  if ((p->p_p->ps_flags & PS_TAMED) == 0)
  return (0);
 
  if (new)
  return (EFAULT);
 
  /* getifaddrs() */
  if ((p->p_p->ps_tame & _TM_INET) &&
         namelen == 6 &&
     name[0] == CTL_NET && name[1] == PF_ROUTE &&
     name[2] == 0 && name[3] == 0 &&
@@ -712,92 +720,96 @@ tame_ioctl_check(struct proc *p, long co
  return (0);
 
  if (fp == NULL)
  return (EBADF);
  vp = (struct vnode *)fp->f_data;
 
  switch (com) {
 
  /*
  * This is a set of "get" info ioctls at the top layer.  Hopefully
  * a safe list, since they are used a lot.
  */
  case FIOCLEX:
  case FIONCLEX:
  case FIONREAD:
  case FIONBIO:
  case FIOGETOWN:
  return (0);
  case FIOASYNC:
  case FIOSETOWN:
+ FRELE(fp, p);
  return (EPERM);
 
  /* tty subsystem */
  case TIOCGWINSZ: /* various programs */
  case TIOCSTI: /* ksh? csh? */
  if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
  return (0);
  break;
 
  default:
  break;
  }
 
- if ((p->p_p->ps_tame & _TM_IOCTL) == 0)
+ if ((p->p_p->ps_tame & _TM_IOCTL) == 0) {
+ FRELE(fp, p);
  return (EPERM);
+ }
 
  /*
  * Further sets of ioctl become available, but are checked a
  * bit more carefully against the vnode.
  */
 
  switch (com) {
  case BIOCGSTATS:        /* bpf: tcpdump privsep on ^C */
  if (fp->f_type == DTYPE_VNODE &&
     fp->f_ops->fo_ioctl == vn_ioctl)
  return (0);
  break;
 
  case TIOCSETAF: /* tcsetattr TCSAFLUSH, script */
  if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
  return (0);
  break;
 
 
  case MTIOCGET:
  case MTIOCTOP:
  /* for pax(1) and such, checking tapes... */
  if (fp->f_type == DTYPE_VNODE &&
     (vp->v_type == VCHR || vp->v_type == VBLK))
  return (0);
  break;
 
  case SIOCGIFGROUP:
  if ((p->p_p->ps_tame & _TM_INET) &&
     fp->f_type == DTYPE_SOCKET)
  return (0);
  break;
 
  default:
  printf("ioctl %lx\n", com);
  break;
  }
+ FRELE(fp, p);
  return (EPERM);
 }
 
 int
 tame_setsockopt_check(struct proc *p, int level, int optname)
 {
  if ((p->p_p->ps_flags & PS_TAMED) == 0)
  return (0);
 
  switch (level) {
  case SOL_SOCKET:
  switch (optname) {
  case SO_RTABLE:
  return (EPERM);
  }
  return (0);
  case IPPROTO_TCP:
  switch (optname) {
  case TCP_NODELAY:
  case TCP_MD5SIG:
Index: kern/sys_generic.c
===================================================================
RCS file: /cvs/src/sys/kern/sys_generic.c,v
retrieving revision 1.100
diff -u -p -U20 -r1.100 sys_generic.c
--- kern/sys_generic.c 28 Jul 2015 05:50:41 -0000 1.100
+++ kern/sys_generic.c 13 Aug 2015 13:29:01 -0000
@@ -69,72 +69,67 @@ int pollout(struct pollfd *, struct poll
 int dopselect(struct proc *, int, fd_set *, fd_set *, fd_set *,
     const struct timespec *, const sigset_t *, register_t *);
 int doppoll(struct proc *, struct pollfd *, u_int, const struct timespec *,
     const sigset_t *, register_t *);
 
 /*
  * Read system call.
  */
 /* ARGSUSED */
 int
 sys_read(struct proc *p, void *v, register_t *retval)
 {
  struct sys_read_args /* {
  syscallarg(int) fd;
  syscallarg(void *) buf;
  syscallarg(size_t) nbyte;
  } */ *uap = v;
  struct iovec iov;
  int fd = SCARG(uap, fd);
  struct file *fp;
- struct filedesc *fdp = p->p_fd;
 
- if ((fp = fd_getfile_mode(fdp, fd, FREAD)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FREAD)) == NULL)
  return (EBADF);
 
  iov.iov_base = SCARG(uap, buf);
  iov.iov_len = SCARG(uap, nbyte);
 
- FREF(fp);
-
  /* dofilereadv() will FRELE the descriptor for us */
  return (dofilereadv(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval));
 }
 
 /*
  * Scatter read system call.
  */
 int
 sys_readv(struct proc *p, void *v, register_t *retval)
 {
  struct sys_readv_args /* {
  syscallarg(int) fd;
  syscallarg(const struct iovec *) iovp;
  syscallarg(int) iovcnt;
  } */ *uap = v;
  int fd = SCARG(uap, fd);
  struct file *fp;
- struct filedesc *fdp = p->p_fd;
 
- if ((fp = fd_getfile_mode(fdp, fd, FREAD)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FREAD)) == NULL)
  return (EBADF);
- FREF(fp);
 
  /* dofilereadv() will FRELE the descriptor for us */
  return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
     &fp->f_offset, retval));
 }
 
 int
 dofilereadv(struct proc *p, int fd, struct file *fp, const struct iovec *iovp,
     int iovcnt, int userspace, off_t *offset, register_t *retval)
 {
  struct iovec aiov[UIO_SMALLIOV];
  struct uio auio;
  struct iovec *iov;
  struct iovec *needfree = NULL;
  long i, cnt, error = 0;
  u_int iovlen;
 #ifdef KTRACE
  struct iovec *ktriov = NULL;
 #endif
 
@@ -221,72 +216,67 @@ dofilereadv(struct proc *p, int fd, stru
  free(needfree, M_IOV, iovlen);
  out:
  FRELE(fp, p);
  return (error);
 }
 
 /*
  * Write system call
  */
 int
 sys_write(struct proc *p, void *v, register_t *retval)
 {
  struct sys_write_args /* {
  syscallarg(int) fd;
  syscallarg(const void *) buf;
  syscallarg(size_t) nbyte;
  } */ *uap = v;
  struct iovec iov;
  int fd = SCARG(uap, fd);
  struct file *fp;
- struct filedesc *fdp = p->p_fd;
 
- if ((fp = fd_getfile_mode(fdp, fd, FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FWRITE)) == NULL)
  return (EBADF);
 
  iov.iov_base = (void *)SCARG(uap, buf);
  iov.iov_len = SCARG(uap, nbyte);
 
- FREF(fp);
-
  /* dofilewritev() will FRELE the descriptor for us */
  return (dofilewritev(p, fd, fp, &iov, 1, 0, &fp->f_offset, retval));
 }
 
 /*
  * Gather write system call
  */
 int
 sys_writev(struct proc *p, void *v, register_t *retval)
 {
  struct sys_writev_args /* {
  syscallarg(int) fd;
  syscallarg(const struct iovec *) iovp;
  syscallarg(int) iovcnt;
  } */ *uap = v;
  int fd = SCARG(uap, fd);
  struct file *fp;
- struct filedesc *fdp = p->p_fd;
 
- if ((fp = fd_getfile_mode(fdp, fd, FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FWRITE)) == NULL)
  return (EBADF);
- FREF(fp);
 
  /* dofilewritev() will FRELE the descriptor for us */
  return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
     &fp->f_offset, retval));
 }
 
 int
 dofilewritev(struct proc *p, int fd, struct file *fp, const struct iovec *iovp,
     int iovcnt, int userspace, off_t *offset, register_t *retval)
 {
  struct iovec aiov[UIO_SMALLIOV];
  struct uio auio;
  struct iovec *iov;
  struct iovec *needfree = NULL;
  long i, cnt, error = 0;
  u_int iovlen;
 #ifdef KTRACE
  struct iovec *ktriov = NULL;
 #endif
 
@@ -375,79 +365,80 @@ dofilewritev(struct proc *p, int fd, str
  if (needfree)
  free(needfree, M_IOV, iovlen);
  out:
  FRELE(fp, p);
  return (error);
 }
 
 /*
  * Ioctl system call
  */
 /* ARGSUSED */
 int
 sys_ioctl(struct proc *p, void *v, register_t *retval)
 {
  struct sys_ioctl_args /* {
  syscallarg(int) fd;
  syscallarg(u_long) com;
  syscallarg(void *) data;
  } */ *uap = v;
  struct file *fp;
- struct filedesc *fdp;
+ struct filedesc *fdp = p->p_fd;
  u_long com = SCARG(uap, com);
  int error;
  u_int size;
- caddr_t data, memp;
+ caddr_t data, memp = NULL;
  int tmp;
 #define STK_PARAMS 128
  long long stkbuf[STK_PARAMS / sizeof(long long)];
 
- fdp = p->p_fd;
- fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE);
+ fp = fd_getfile_mode(p, SCARG(uap, fd), FREAD|FWRITE);
 
  if (tame_ioctl_check(p, com, fp))
  return (tame_fail(p, EPERM, _TM_IOCTL));
 
  if (fp == NULL)
  return (EBADF);
 
  switch (com) {
  case FIONCLEX:
  case FIOCLEX:
  fdplock(fdp);
  if (com == FIONCLEX)
  fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE;
  else
  fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
  fdpunlock(fdp);
+ FRELE(fp, p);
  return (0);
  }
 
  /*
  * Interpret high order word to find amount of data to be
  * copied to/from the user's address space.
  */
  size = IOCPARM_LEN(com);
- if (size > IOCPARM_MAX)
- return (ENOTTY);
- FREF(fp);
- memp = NULL;
+ if (size > IOCPARM_MAX) {
+ error = ENOTTY;
+ goto out;
+ }
+
  if (size > sizeof (stkbuf)) {
  memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
  data = memp;
  } else
  data = (caddr_t)stkbuf;
  if (com&IOC_IN) {
  if (size) {
  error = copyin(SCARG(uap, data), data, (u_int)size);
  if (error) {
  goto out;
  }
  } else
  *(caddr_t *)data = SCARG(uap, data);
  } else if ((com&IOC_OUT) && size)
  /*
  * Zero the buffer so the user always
  * gets back something deterministic.
  */
  memset(data, 0, size);
  else if (com&IOC_VOID)
@@ -721,41 +712,40 @@ selscan(struct proc *p, fd_set *ibits, f
     register_t *retval)
 {
  caddr_t cibits = (caddr_t)ibits, cobits = (caddr_t)obits;
  struct filedesc *fdp = p->p_fd;
  int msk, i, j, fd;
  fd_mask bits;
  struct file *fp;
  int n = 0;
  static const int flag[3] = { POLLIN, POLLOUT|POLLNOHUP, POLLPRI };
 
  for (msk = 0; msk < 3; msk++) {
  fd_set *pibits = (fd_set *)&cibits[msk*ni];
  fd_set *pobits = (fd_set *)&cobits[msk*ni];
 
  for (i = 0; i < nfd; i += NFDBITS) {
  bits = pibits->fds_bits[i/NFDBITS];
  while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
  bits &= ~(1 << j);
  if ((fp = fd_getfile(fdp, fd)) == NULL)
  return (EBADF);
- FREF(fp);
  if ((*fp->f_ops->fo_poll)(fp, flag[msk], p)) {
  FD_SET(fd, pobits);
  n++;
  }
  FRELE(fp, p);
  }
  }
  }
  *retval = n;
  return (0);
 }
 
 /*ARGSUSED*/
 int
 seltrue(dev_t dev, int events, struct proc *p)
 {
 
  return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
 }
 
@@ -819,41 +809,40 @@ selwakeup(struct selinfo *sip)
 
 void
 pollscan(struct proc *p, struct pollfd *pl, u_int nfd, register_t *retval)
 {
  struct filedesc *fdp = p->p_fd;
  struct file *fp;
  u_int i;
  int n = 0;
 
  for (i = 0; i < nfd; i++, pl++) {
  /* Check the file descriptor. */
  if (pl->fd < 0) {
  pl->revents = 0;
  continue;
  }
  if ((fp = fd_getfile(fdp, pl->fd)) == NULL) {
  pl->revents = POLLNVAL;
  n++;
  continue;
  }
- FREF(fp);
  pl->revents = (*fp->f_ops->fo_poll)(fp, pl->events, p);
  FRELE(fp, p);
  if (pl->revents != 0)
  n++;
  }
  *retval = n;
 }
 
 /*
  * Only copyout the revents field.
  */
 int
 pollout(struct pollfd *pl, struct pollfd *upl, u_int nfds)
 {
  int error = 0;
  u_int i = 0;
 
  while (!error && i++ < nfds) {
  error = copyout(&pl->revents, &upl->revents,
     sizeof(upl->revents));
Index: kern/uipc_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.106
diff -u -p -U20 -r1.106 uipc_syscalls.c
--- kern/uipc_syscalls.c 28 Jul 2015 05:50:41 -0000 1.106
+++ kern/uipc_syscalls.c 13 Aug 2015 13:27:25 -0000
@@ -1063,44 +1063,45 @@ sockargs(struct mbuf **mp, const void *b
  error = copyin(buf, mtod(m, caddr_t), buflen);
  if (error) {
  (void) m_free(m);
  return (error);
  }
  *mp = m;
  if (type == MT_SONAME) {
  sa = mtod(m, struct sockaddr *);
  sa->sa_len = buflen;
  }
  return (0);
 }
 
 int
 getsock(struct proc *p, int fdes, struct file **fpp)
 {
  struct file *fp;
 
  if ((fp = fd_getfile(p->p_fd, fdes)) == NULL)
  return (EBADF);
- if (fp->f_type != DTYPE_SOCKET)
+ if (fp->f_type != DTYPE_SOCKET) {
+ FRELE(fp, p);
  return (ENOTSOCK);
+ }
  *fpp = fp;
- FREF(fp);
 
  return (0);
 }
 
 /* ARGSUSED */
 int
 sys_setrtable(struct proc *p, void *v, register_t *retval)
 {
  struct sys_setrtable_args /* {
  syscallarg(int) rtableid;
  } */ *uap = v;
  int rtableid, error;
 
  rtableid = SCARG(uap, rtableid);
 
  if (p->p_p->ps_rtableid == (u_int)rtableid)
  return (0);
  if (p->p_p->ps_rtableid != 0 && (error = suser(p, 0)) != 0)
  return (error);
  if (rtableid < 0 || !rtable_exists((u_int)rtableid))
Index: kern/uipc_usrreq.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_usrreq.c,v
retrieving revision 1.83
diff -u -p -U20 -r1.83 uipc_usrreq.c
--- kern/uipc_usrreq.c 28 Jul 2015 14:20:10 -0000 1.83
+++ kern/uipc_usrreq.c 13 Aug 2015 13:27:25 -0000
@@ -789,64 +789,65 @@ morespace:
  memcpy(cm, tmp, control->m_len);
  free(tmp, M_TEMP, control->m_len);
  goto morespace;
  }
 
  /* adjust message & mbuf to note amount of space actually used. */
  cm->cmsg_len = CMSG_LEN(nfds * sizeof(struct file *));
  control->m_len = CMSG_SPACE(nfds * sizeof(struct file *));
 
  ip = ((int *)CMSG_DATA(cm)) + nfds - 1;
  rp = ((struct file **)CMSG_DATA(cm)) + nfds - 1;
  for (i = 0; i < nfds; i++) {
  memcpy(&fd, ip, sizeof fd);
  ip--;
  if ((fp = fd_getfile(fdp, fd)) == NULL) {
  error = EBADF;
  goto fail;
  }
  if (fp->f_count == LONG_MAX-2 ||
     fp->f_msgcount == LONG_MAX-2) {
+ FRELE(fp, p);
  error = EDEADLK;
  goto fail;
  }
  /* kq and systrace descriptors cannot be copied */
  if (fp->f_type == DTYPE_KQUEUE ||
     fp->f_type == DTYPE_SYSTRACE) {
+ FRELE(fp, p);
  error = EINVAL;
  goto fail;
  }
  memcpy(rp, &fp, sizeof fp);
  rp--;
- fp->f_count++;
  fp->f_msgcount++;
  unp_rights++;
  }
  return (0);
 fail:
  /* Back out what we just did. */
  for ( ; i > 0; i--) {
  rp++;
  memcpy(&fp, rp, sizeof(fp));
- fp->f_count--;
  fp->f_msgcount--;
  unp_rights--;
+ FRELE(fp, p);
  }
 
  return (error);
 }
 
 int unp_defer, unp_gcing;
 extern struct domain unixdomain;
 
 void
 unp_gc(void)
 {
  struct file *fp, *nextfp;
  struct socket *so;
  struct file **extra_ref, **fpp;
  int nunref, i;
 
  if (unp_gcing)
  return;
  unp_gcing = 1;
  unp_defer = 0;
Index: kern/vfs_lookup.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_lookup.c,v
retrieving revision 1.54
diff -u -p -U20 -r1.54 vfs_lookup.c
--- kern/vfs_lookup.c 19 Jul 2015 02:35:35 -0000 1.54
+++ kern/vfs_lookup.c 13 Aug 2015 13:27:25 -0000
@@ -70,59 +70,60 @@
  * Symbolic links are always followed for all other pathname
  * components other than the last.
  *
  * If the LOCKLEAF flag is set, a locked vnode is returned.
  *
  * The segflg defines whether the name is to be copied from user
  * space or kernel space.
  *
  * Overall outline of namei:
  *
  * copy in name
  * get starting directory
  * while (!done && !error) {
  * call lookup to search path.
  * if symbolic link, massage name in buffer and continue
  * }
  */
 int
 namei(struct nameidata *ndp)
 {
+ struct file *fp = NULL;
  struct filedesc *fdp; /* pointer to file descriptor state */
  char *cp; /* pointer into pathname argument */
  struct vnode *dp; /* the directory we are searching */
  struct iovec aiov; /* uio for reading symbolic links */
  struct uio auio;
  int error, linklen;
  struct componentname *cnp = &ndp->ni_cnd;
  struct proc *p = cnp->cn_proc;
 
  ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
 #ifdef DIAGNOSTIC
  if (!cnp->cn_cred || !cnp->cn_proc)
  panic ("namei: bad cred/proc");
  if (cnp->cn_nameiop & (~OPMASK))
  panic ("namei: nameiop contaminated with flags");
  if (cnp->cn_flags & OPMASK)
  panic ("namei: flags contaminated with nameiops");
 #endif
- fdp = cnp->cn_proc->p_fd;
+ fdp = p->p_fd;
 
  /*
  * Get a buffer for the name to be translated, and copy the
  * name into the buffer.
  */
  if ((cnp->cn_flags & HASBUF) == 0)
  cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
  if (ndp->ni_segflg == UIO_SYSSPACE)
  error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
     MAXPATHLEN, &ndp->ni_pathlen);
  else
  error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
     MAXPATHLEN, &ndp->ni_pathlen);
 
  /*
  * Fail on null pathnames
  */
  if (error == 0 && ndp->ni_pathlen == 1)
  error = ENOENT;
 
@@ -165,73 +166,76 @@ fail:
  * Get starting point for the translation.
  */
  if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
  ndp->ni_rootdir = rootvnode;
  if ((p->p_p->ps_flags & PS_TAMED)) {
  error = tame_namei(p, cnp->cn_pnbuf);
  if (error)
  goto fail;
  }
 
  /*
  * Check if starting from root directory or current directory.
  */
  if (cnp->cn_pnbuf[0] == '/') {
  dp = ndp->ni_rootdir;
  vref(dp);
  } else if (ndp->ni_dirfd == AT_FDCWD) {
  dp = fdp->fd_cdir;
  vref(dp);
  } else {
- struct file *fp = fd_getfile(fdp, ndp->ni_dirfd);
+ fp = fd_getfile(fdp, ndp->ni_dirfd);
  if (fp == NULL) {
  pool_put(&namei_pool, cnp->cn_pnbuf);
  return (EBADF);
  }
  dp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || dp->v_type != VDIR) {
  pool_put(&namei_pool, cnp->cn_pnbuf);
- return (ENOTDIR);
+ error = ENOTDIR;
+ goto out;
  }
  vref(dp);
  }
  for (;;) {
  if (!dp->v_mount) {
  /* Give up if the directory is no longer mounted */
  pool_put(&namei_pool, cnp->cn_pnbuf);
- return (ENOENT);
+ error = ENOENT;
+ goto out;
  }
  cnp->cn_nameptr = cnp->cn_pnbuf;
  ndp->ni_startdir = dp;
  if ((error = vfs_lookup(ndp)) != 0) {
  pool_put(&namei_pool, cnp->cn_pnbuf);
- return (error);
+ goto out;
  }
  /*
  * If not a symbolic link, return search result.
  */
  if ((cnp->cn_flags & ISSYMLINK) == 0) {
  if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
  pool_put(&namei_pool, cnp->cn_pnbuf);
  else
  cnp->cn_flags |= HASBUF;
- return (0);
+ error = 0;
+ goto out;
  }
  if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
  VOP_UNLOCK(ndp->ni_dvp, 0, p);
  if (ndp->ni_loopcnt++ >= SYMLOOP_MAX) {
  error = ELOOP;
  break;
  }
  if (ndp->ni_pathlen > 1)
  cp = pool_get(&namei_pool, PR_WAITOK);
  else
  cp = cnp->cn_pnbuf;
  aiov.iov_base = cp;
  aiov.iov_len = MAXPATHLEN;
  auio.uio_iov = &aiov;
  auio.uio_iovcnt = 1;
  auio.uio_offset = 0;
  auio.uio_rw = UIO_READ;
  auio.uio_segflg = UIO_SYSSPACE;
  auio.uio_procp = cnp->cn_proc;
  auio.uio_resid = MAXPATHLEN;
@@ -256,40 +260,44 @@ badlink:
  pool_put(&namei_pool, cnp->cn_pnbuf);
  cnp->cn_pnbuf = cp;
  } else
  cnp->cn_pnbuf[linklen] = '\0';
  ndp->ni_pathlen += linklen;
  vput(ndp->ni_vp);
  dp = ndp->ni_dvp;
  /*
  * Check if root directory should replace current directory.
  */
  if (cnp->cn_pnbuf[0] == '/') {
  vrele(dp);
  dp = ndp->ni_rootdir;
  vref(dp);
  }
  }
  pool_put(&namei_pool, cnp->cn_pnbuf);
  vrele(ndp->ni_dvp);
  vput(ndp->ni_vp);
  ndp->ni_vp = NULL;
+
+out:
+ if (fp)
+ FRELE(fp, p);
  return (error);
 }
 
 /*
  * Search a pathname.
  * This is a very central and rather complicated routine.
  *
  * The pathname is pointed to by ni_cnd.cn_nameptr and is of length
  * ni_pathlen.  The starting directory is taken from ni_startdir. The
  * pathname is descended until done, or a symbolic link is encountered.
  * If the path is completed the flag ISLASTCN is set in ni_cnd.cn_flags.
  * If a symbolic link need interpretation is encountered, the flag ISSYMLINK
  * is set in ni_cnd.cn_flags.
  *
  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
  * whether the name is to be looked up, created, renamed, or deleted.
  * When CREATE, RENAME, or DELETE is specified, information usable in
  * creating, renaming, or deleting a directory entry may be calculated.
  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
Index: kern/vfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.222
diff -u -p -U20 -r1.222 vfs_syscalls.c
--- kern/vfs_syscalls.c 20 Jul 2015 21:31:57 -0000 1.222
+++ kern/vfs_syscalls.c 13 Aug 2015 13:27:25 -0000
@@ -666,70 +666,74 @@ sys_getfsstat(struct proc *p, void *v, r
  else
  *retval = count;
 
  return (0);
 }
 
 /*
  * Change current working directory to a given file descriptor.
  */
 /* ARGSUSED */
 int
 sys_fchdir(struct proc *p, void *v, register_t *retval)
 {
  struct sys_fchdir_args /* {
  syscallarg(int) fd;
  } */ *uap = v;
  struct filedesc *fdp = p->p_fd;
  struct vnode *vp, *tdp, *old_cdir;
  struct mount *mp;
  struct file *fp;
- int error;
+ int error = 0;
 
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
  vp = (struct vnode *)fp->f_data;
- if (fp->f_type != DTYPE_VNODE || vp->v_type != VDIR)
- return (ENOTDIR);
+ if (fp->f_type != DTYPE_VNODE || vp->v_type != VDIR) {
+ error = ENOTDIR;
+ goto out;
+ }
  vref(vp);
  vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
 
  while (!error && (mp = vp->v_mountedhere) != NULL) {
  if (vfs_busy(mp, VB_READ|VB_WAIT))
  continue;
  error = VFS_ROOT(mp, &tdp);
  vfs_unbusy(mp);
  if (error)
  break;
  vput(vp);
  vp = tdp;
  }
  if (error) {
  vput(vp);
- return (error);
+ goto out;
  }
  VOP_UNLOCK(vp, 0, p);
  old_cdir = fdp->fd_cdir;
  fdp->fd_cdir = vp;
  vrele(old_cdir);
- return (0);
+out:
+ FRELE(fp, p);
+ return (error);
 }
 
 /*
  * Change current working directory (``.'').
  */
 /* ARGSUSED */
 int
 sys_chdir(struct proc *p, void *v, register_t *retval)
 {
  struct sys_chdir_args /* {
  syscallarg(const char *) path;
  } */ *uap = v;
  struct filedesc *fdp = p->p_fd;
  struct vnode *old_cdir;
  int error;
  struct nameidata nd;
 
  NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
     SCARG(uap, path), p);
  if ((error = change_dir(&nd, p)) != 0)
@@ -855,41 +859,41 @@ doopenat(struct proc *p, int fd, const c
 
  fdplock(fdp);
 
  if ((error = falloc(p, &fp, &indx)) != 0)
  goto out;
  flags = FFLAGS(oflags);
  if (flags & O_CLOEXEC)
  fdp->fd_ofileflags[indx] |= UF_EXCLOSE;
 
  cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
  NDINITAT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fd, path, p);
  p->p_dupfd = -1; /* XXX check for fdopen */
  if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) {
  localtrunc = 1;
  flags &= ~O_TRUNC; /* Must do truncate ourselves */
  }
  if ((error = vn_open(&nd, flags, cmode)) != 0) {
  if (error == ENODEV &&
     p->p_dupfd >= 0 && /* XXX from fdopen */
     (error =
- dupfdopen(fdp, indx, p->p_dupfd, flags)) == 0) {
+ dupfdopen(p, indx, flags)) == 0) {
  closef(fp, p);
  *retval = indx;
  goto out;
  }
  if (error == ERESTART)
  error = EINTR;
  fdremove(fdp, indx);
  closef(fp, p);
  goto out;
  }
  p->p_dupfd = 0;
  vp = nd.ni_vp;
  fp->f_flag = flags & FMASK;
  fp->f_type = DTYPE_VNODE;
  fp->f_ops = &vnops;
  fp->f_data = vp;
  if (flags & (O_EXLOCK | O_SHLOCK)) {
  lf.l_whence = SEEK_SET;
  lf.l_start = 0;
  lf.l_len = 0;
@@ -1531,46 +1535,45 @@ out:
  */
 int
 sys_lseek(struct proc *p, void *v, register_t *retval)
 {
  struct sys_lseek_args /* {
  syscallarg(int) fd;
  syscallarg(int) pad;
  syscallarg(off_t) offset;
  syscallarg(int) whence;
  } */ *uap = v;
  struct ucred *cred = p->p_ucred;
  struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vattr vattr;
  struct vnode *vp;
  off_t offarg, newoff;
  int error, special;
 
  if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
  return (EBADF);
- if (fp->f_type != DTYPE_VNODE)
- return (ESPIPE);
  vp = (struct vnode *)fp->f_data;
- if (vp->v_type == VFIFO)
- return (ESPIPE);
- FREF(fp);
+ if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
+ error = ESPIPE;
+ goto bad;
+ }
  if (vp->v_type == VCHR)
  special = 1;
  else
  special = 0;
  offarg = SCARG(uap, offset);
 
  switch (SCARG(uap, whence)) {
  case SEEK_CUR:
  newoff = fp->f_offset + offarg;
  break;
  case SEEK_END:
  error = VOP_GETATTR(vp, &vattr, cred, p);
  if (error)
  goto bad;
  newoff = offarg + (off_t)vattr.va_size;
  break;
  case SEEK_SET:
  newoff = offarg;
  break;
  default:
@@ -2798,195 +2801,198 @@ sys_revoke(struct proc *p, void *v, regi
  VOP_REVOKE(vp, REVOKEALL);
 out:
  vrele(vp);
  return (error);
 }
 
 /*
  * Convert a user file descriptor to a kernel file entry.
  *
  * On return *fpp is FREF:ed.
  */
 int
 getvnode(struct proc *p, int fd, struct file **fpp)
 {
  struct file *fp;
  struct vnode *vp;
 
  if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
  return (EBADF);
 
- if (fp->f_type != DTYPE_VNODE)
+ if (fp->f_type != DTYPE_VNODE) {
+ FRELE(fp, p);
  return (EINVAL);
+ }
 
  vp = (struct vnode *)fp->f_data;
- if (vp->v_type == VBAD)
+ if (vp->v_type == VBAD) {
+ FRELE(fp, p);
  return (EBADF);
+ }
 
- FREF(fp);
  *fpp = fp;
 
  return (0);
 }
 
 /*
  * Positional read system call.
  */
 int
 sys_pread(struct proc *p, void *v, register_t *retval)
 {
  struct sys_pread_args /* {
  syscallarg(int) fd;
  syscallarg(void *) buf;
  syscallarg(size_t) nbyte;
  syscallarg(int) pad;
  syscallarg(off_t) offset;
  } */ *uap = v;
  struct iovec iov;
- struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  off_t offset;
  int fd = SCARG(uap, fd);
 
- if ((fp = fd_getfile_mode(fdp, fd, FREAD)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FREAD)) == NULL)
  return (EBADF);
 
  vp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
     (vp->v_flag & VISTTY)) {
+ FRELE(fp, p);
  return (ESPIPE);
  }
 
  iov.iov_base = SCARG(uap, buf);
  iov.iov_len = SCARG(uap, nbyte);
 
  offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
+ if (offset < 0 && vp->v_type != VCHR) {
+ FRELE(fp, p);
  return (EINVAL);
-
- FREF(fp);
+ }
 
  /* dofilereadv() will FRELE the descriptor for us */
  return (dofilereadv(p, fd, fp, &iov, 1, 0, &offset, retval));
 }
 
 /*
  * Positional scatter read system call.
  */
 int
 sys_preadv(struct proc *p, void *v, register_t *retval)
 {
  struct sys_preadv_args /* {
  syscallarg(int) fd;
  syscallarg(const struct iovec *) iovp;
  syscallarg(int) iovcnt;
  syscallarg(int) pad;
  syscallarg(off_t) offset;
  } */ *uap = v;
- struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  off_t offset;
  int fd = SCARG(uap, fd);
 
- if ((fp = fd_getfile_mode(fdp, fd, FREAD)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FREAD)) == NULL)
  return (EBADF);
 
  vp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
     (vp->v_flag & VISTTY)) {
+ FRELE(fp, p);
  return (ESPIPE);
  }
 
  offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
+ if (offset < 0 && vp->v_type != VCHR) {
+ FRELE(fp, p);
  return (EINVAL);
-
- FREF(fp);
+ }
 
  /* dofilereadv() will FRELE the descriptor for us */
  return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt), 1,
     &offset, retval));
 }
 
 /*
  * Positional write system call.
  */
 int
 sys_pwrite(struct proc *p, void *v, register_t *retval)
 {
  struct sys_pwrite_args /* {
  syscallarg(int) fd;
  syscallarg(const void *) buf;
  syscallarg(size_t) nbyte;
  syscallarg(int) pad;
  syscallarg(off_t) offset;
  } */ *uap = v;
  struct iovec iov;
- struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  off_t offset;
  int fd = SCARG(uap, fd);
 
- if ((fp = fd_getfile_mode(fdp, fd, FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FWRITE)) == NULL)
  return (EBADF);
 
  vp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
     (vp->v_flag & VISTTY)) {
+ FRELE(fp, p);
  return (ESPIPE);
  }
 
  iov.iov_base = (void *)SCARG(uap, buf);
  iov.iov_len = SCARG(uap, nbyte);
 
  offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
+ if (offset < 0 && vp->v_type != VCHR) {
+ FRELE(fp, p);
  return (EINVAL);
-
- FREF(fp);
+ }
 
  /* dofilewritev() will FRELE the descriptor for us */
  return (dofilewritev(p, fd, fp, &iov, 1, 0, &offset, retval));
 }
 
 /*
  * Positional gather write system call.
  */
 int
 sys_pwritev(struct proc *p, void *v, register_t *retval)
 {
  struct sys_pwritev_args /* {
  syscallarg(int) fd;
  syscallarg(const struct iovec *) iovp;
  syscallarg(int) iovcnt;
  syscallarg(int) pad;
  syscallarg(off_t) offset;
  } */ *uap = v;
- struct filedesc *fdp = p->p_fd;
  struct file *fp;
  struct vnode *vp;
  off_t offset;
  int fd = SCARG(uap, fd);
 
- if ((fp = fd_getfile_mode(fdp, fd, FWRITE)) == NULL)
+ if ((fp = fd_getfile_mode(p, fd, FWRITE)) == NULL)
  return (EBADF);
 
  vp = (struct vnode *)fp->f_data;
  if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO ||
     (vp->v_flag & VISTTY)) {
+ FRELE(fp, p);
  return (ESPIPE);
  }
 
  offset = SCARG(uap, offset);
- if (offset < 0 && vp->v_type != VCHR)
+ if (offset < 0 && vp->v_type != VCHR) {
+ FRELE(fp, p);
  return (EINVAL);
-
- FREF(fp);
+ }
 
  /* dofilewritev() will FRELE the descriptor for us */
  return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
     1, &offset, retval));
 }
 
Index: miscfs/fuse/fuse_vfsops.c
===================================================================
RCS file: /cvs/src/sys/miscfs/fuse/fuse_vfsops.c,v
retrieving revision 1.16
diff -u -p -U20 -r1.16 fuse_vfsops.c
--- miscfs/fuse/fuse_vfsops.c 19 Jul 2015 14:21:14 -0000 1.16
+++ miscfs/fuse/fuse_vfsops.c 13 Aug 2015 13:27:25 -0000
@@ -59,84 +59,90 @@ const struct vfsops fusefs_vfsops = {
  fusefs_sync,
  fusefs_vget,
  fusefs_fhtovp,
  fusefs_vptofh,
  fusefs_init,
  fusefs_sysctl,
  fusefs_checkexp
 };
 
 struct pool fusefs_fbuf_pool;
 
 int
 fusefs_mount(struct mount *mp, const char *path, void *data,
     struct nameidata *ndp, struct proc *p)
 {
  struct fusefs_mnt *fmp;
  struct fusebuf *fbuf;
  struct fusefs_args args;
  struct vnode *vp;
  struct file *fp;
- int error;
+ int error = 0;
 
  if (mp->mnt_flag & MNT_UPDATE)
  return (EOPNOTSUPP);
 
  error = copyin(data, &args, sizeof(struct fusefs_args));
  if (error)
  return (error);
 
  if ((fp = fd_getfile(p->p_fd, args.fd)) == NULL)
  return (EBADF);
 
- if (fp->f_type != DTYPE_VNODE)
- return (EINVAL);
+ if (fp->f_type != DTYPE_VNODE) {
+ error = EINVAL;
+ goto out;
+ }
 
  vp = fp->f_data;
- if (vp->v_type != VCHR)
- return (EBADF);
+ if (vp->v_type != VCHR) {
+ error = EBADF;
+ goto out;
+ }
 
  fmp = malloc(sizeof(*fmp), M_FUSEFS, M_WAITOK | M_ZERO);
  fmp->mp = mp;
  fmp->sess_init = 0;
  fmp->dev = vp->v_rdev;
  if (args.max_read > 0)
  fmp->max_read = MIN(args.max_read, FUSEBUFMAXSIZE);
  else
  fmp->max_read = FUSEBUFMAXSIZE;
 
  mp->mnt_data = fmp;
  mp->mnt_flag |= MNT_LOCAL;
  vfs_getnewfsid(mp);
 
  bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
  strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
  bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
  bcopy("fusefs", mp->mnt_stat.f_mntfromname, sizeof("fusefs"));
 
  fuse_device_set_fmp(fmp, 1);
  fbuf = fb_setup(0, 0, FBT_INIT, p);
 
  /* cannot tsleep on mount */
  fuse_device_queue_fbuf(fmp->dev, fbuf);
 
- return (0);
+out:
+ FRELE(fp, p);
+ return (error);
 }
 
 int
 fusefs_start(struct mount *mp, int flags, struct proc *p)
 {
  return (0);
 }
 
 int
 fusefs_unmount(struct mount *mp, int mntflags, struct proc *p)
 {
  struct fusefs_mnt *fmp;
  struct fusebuf *fbuf;
  extern int doforce;
  int flags = 0;
  int error;
 
  fmp = VFSTOFUSEFS(mp);
 
  if (mntflags & MNT_FORCE) {
Index: sys/filedesc.h
===================================================================
RCS file: /cvs/src/sys/sys/filedesc.h,v
retrieving revision 1.30
diff -u -p -U20 -r1.30 filedesc.h
--- sys/filedesc.h 6 May 2015 08:52:17 -0000 1.30
+++ sys/filedesc.h 13 Aug 2015 13:27:25 -0000
@@ -104,41 +104,41 @@ struct filedesc0 {
 /*
  * Per-process open flags.
  */
 #define UF_EXCLOSE 0x01 /* auto-close on exec */
 
 /*
  * Flags on the file descriptor table.
  */
 #define FD_ADVLOCK 0x01 /* May hold a POSIX adv. lock. */
 
 /*
  * Storage required per open file descriptor.
  */
 #define OFILESIZE (sizeof(struct file *) + sizeof(char))
 
 #ifdef _KERNEL
 /*
  * Kernel global variables and routines.
  */
 void filedesc_init(void);
-int dupfdopen(struct filedesc *, int, int, int);
+int dupfdopen(struct proc *, int, int);
 int fdalloc(struct proc *p, int want, int *result);
 void fdexpand(struct proc *);
 int falloc(struct proc *p, struct file **resultfp, int *resultfd);
 struct filedesc *fdinit(void);
 struct filedesc *fdshare(struct process *);
 struct filedesc *fdcopy(struct process *);
 void fdfree(struct proc *p);
 int fdrelease(struct proc *p, int);
 void fdremove(struct filedesc *, int);
 void fdcloseexec(struct proc *);
 struct file *fd_getfile(struct filedesc *, int);
-struct file *fd_getfile_mode(struct filedesc *, int, int);
+struct file *fd_getfile_mode(struct proc *, int, int);
 
 int closef(struct file *, struct proc *);
 int getsock(struct proc *, int, struct file **);
 
 #define fdplock(fdp) rw_enter_write(&(fdp)->fd_lock)
 #define fdpunlock(fdp) rw_exit_write(&(fdp)->fd_lock)
 #define fdpassertlocked(fdp) rw_assert_wrlock(&(fdp)->fd_lock)
 #endif
Index: uvm/uvm_mmap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.112
diff -u -p -U20 -r1.112 uvm_mmap.c
--- uvm/uvm_mmap.c 20 Jul 2015 22:41:41 -0000 1.112
+++ uvm/uvm_mmap.c 13 Aug 2015 13:27:25 -0000
@@ -375,42 +375,40 @@ sys_mmap(struct proc *p, void *v, regist
  return (EINVAL); /* not page aligned */
 
  if (addr > SIZE_MAX - size)
  return (EINVAL); /* no wrapping! */
  if (VM_MAXUSER_ADDRESS > 0 &&
     (addr + size) > VM_MAXUSER_ADDRESS)
  return (EINVAL);
  if (vm_min_address > 0 && addr < vm_min_address)
  return (EINVAL);
 
  }
 
  /* check for file mappings (i.e. not anonymous) and verify file. */
  if ((flags & MAP_ANON) == 0) {
  KERNEL_LOCK();
  if ((fp = fd_getfile(fdp, fd)) == NULL) {
  KERNEL_UNLOCK();
  return (EBADF);
  }
 
- FREF(fp);
-
  if (fp->f_type != DTYPE_VNODE) {
  error = ENODEV; /* only mmap vnodes! */
  goto out;
  }
  vp = (struct vnode *)fp->f_data; /* convert to vnode */
 
  if (vp->v_type != VREG && vp->v_type != VCHR &&
     vp->v_type != VBLK) {
  error = ENODEV; /* only REG/CHR/BLK support mmap */
  goto out;
  }
 
  if (vp->v_type == VREG && (pos + size) < pos) {
  error = EINVAL; /* no offset wrapping */
  goto out;
  }
 
  /* special case: catch SunOS style /dev/zero */
  if (vp->v_type == VCHR && iszerodev(vp->v_rdev)) {
  flags |= MAP_ANON;