dodup3() is already calling FREF(), just before a sleeping point. Diff below moves it right after fd_getfile() to prepare for unlocking some syscalls.
Ok? Index: kern/kern_descrip.c =================================================================== RCS file: /cvs/src/sys/kern/kern_descrip.c,v retrieving revision 1.143 diff -u -p -r1.143 kern_descrip.c --- kern/kern_descrip.c 28 Mar 2018 09:49:28 -0000 1.143 +++ kern/kern_descrip.c 2 Apr 2018 10:51:51 -0000 @@ -289,9 +289,12 @@ dodup3(struct proc *p, int old, int new, restart: if ((fp = fd_getfile(fdp, old)) == NULL) return (EBADF); + FREF(fp); if ((u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || - (u_int)new >= maxfiles) + (u_int)new >= maxfiles) { + FRELE(fp, p); 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) {