Index: kern/vfs_syscalls.c =================================================================== --- kern/vfs_syscalls.c (revision 188457) +++ kern/vfs_syscalls.c (working copy) @@ -1097,7 +1097,7 @@ * wonderous happened deep below and we just pass it up * pretending we know what we do. */ - if (error == ENXIO && fp->f_ops != &badfileops) { + if (error == ENXIO && fp->f_ops != &newfileops) { fdrop(fp, td); td->td_retval[0] = indx; return (0); @@ -1137,7 +1137,7 @@ * If the file wasn't claimed by devfs bind it to the normal * vnode operations here. */ - if (fp->f_ops == &badfileops) { + if (fp->f_ops == &newfileops) { KASSERT(vp->v_type != VFIFO, ("Unexpected fifo.")); fp->f_seqcount = 1; finit(fp, flags & FMASK, DTYPE_VNODE, vp, &vnops); Index: kern/tty.c =================================================================== --- kern/tty.c (revision 188457) +++ kern/tty.c (working copy) @@ -1700,7 +1700,8 @@ if ((fdp = p->p_fd) == NULL) return (EBADF); FILEDESC_SLOCK(fdp); - if ((fp = fget_locked(fdp, fd)) == NULL || fp->f_ops == &badfileops) { + if ((fp = fget_locked(fdp, fd)) == NULL || fp->f_ops == &badfileops + || fp->f_ops == &newfileops) { FILEDESC_SUNLOCK(fdp); return (EBADF); } Index: kern/kern_descrip.c =================================================================== --- kern/kern_descrip.c (revision 188457) +++ kern/kern_descrip.c (working copy) @@ -1439,7 +1439,7 @@ if (resultfp) fhold(fp); fp->f_cred = crhold(td->td_ucred); - fp->f_ops = &badfileops; + fp->f_ops = &newfileops; fp->f_data = NULL; fp->f_vnode = NULL; FILEDESC_XLOCK(p->p_fd); @@ -1583,7 +1583,8 @@ newfdp->fd_freefile = -1; for (i = 0; i <= fdp->fd_lastfile; ++i) { if (fdisused(fdp, i) && - fdp->fd_ofiles[i]->f_type != DTYPE_KQUEUE) { + fdp->fd_ofiles[i]->f_type != DTYPE_KQUEUE && + fdp->fd_ofiles[i]->f_ops != &newfileops) { newfdp->fd_ofiles[i] = fdp->fd_ofiles[i]; newfdp->fd_ofileflags[i] = fdp->fd_ofileflags[i]; fhold(newfdp->fd_ofiles[i]); @@ -2049,7 +2050,8 @@ if (td == NULL || (fdp = td->td_proc->p_fd) == NULL) return (EBADF); FILEDESC_SLOCK(fdp); - if ((fp = fget_locked(fdp, fd)) == NULL || fp->f_ops == &badfileops) { + if ((fp = fget_locked(fdp, fd)) == NULL || fp->f_ops == &badfileops + || fp->f_ops == &newfileops) { FILEDESC_SUNLOCK(fdp); return (EBADF); } @@ -2207,7 +2209,7 @@ error = 0; if (fp->f_count != 0) panic("fdrop: count %d", fp->f_count); - if (fp->f_ops != &badfileops) + if (fp->f_ops != &badfileops && fp->f_ops != &newfileops) error = fo_close(fp, td); /* * The f_cdevpriv cannot be assigned non-NULL value while we @@ -3199,6 +3201,14 @@ return (EBADF); } +/* + * We have two different file descriptor "bad" operation vectors, both + * implemented by the badfo_ functions. newfileops is used for new file + * descriptors that aren't yet ready for use; badfileops is used for revoked + * or otherwise invalidated file descripors. There are a number of places + * where comparisons are done, such as in fork(2) where bad file descriptors + * are inherited but new ones aren't. + */ struct fileops badfileops = { .fo_read = badfo_readwrite, .fo_write = badfo_readwrite, @@ -3210,6 +3220,16 @@ .fo_close = badfo_close, }; +struct fileops newfileops = { + .fo_read = badfo_readwrite, + .fo_write = badfo_readwrite, + .fo_truncate = badfo_truncate, + .fo_ioctl = badfo_ioctl, + .fo_poll = badfo_poll, + .fo_kqfilter = badfo_kqfilter, + .fo_stat = badfo_stat, + .fo_close = badfo_close, +}; /*-------------------------------------------------------------------*/ Index: fs/devfs/devfs_vnops.c =================================================================== --- fs/devfs/devfs_vnops.c (revision 188457) +++ fs/devfs/devfs_vnops.c (working copy) @@ -975,7 +975,7 @@ if(fp == NULL) return (error); #endif - if (fp->f_ops == &badfileops) + if (fp->f_ops == &newfileops) finit(fp, fp->f_flag, DTYPE_VNODE, dev, &devfs_ops_f); return (error); } Index: fs/fifofs/fifo_vnops.c =================================================================== --- fs/fifofs/fifo_vnops.c (revision 188457) +++ fs/fifofs/fifo_vnops.c (working copy) @@ -296,7 +296,7 @@ } mtx_unlock(&fifo_mtx); KASSERT(fp != NULL, ("can't fifo/vnode bypass")); - KASSERT(fp->f_ops == &badfileops, ("not badfileops in fifo_open")); + KASSERT(fp->f_ops == &newfileops, ("not badfileops in fifo_open")); finit(fp, fp->f_flag, DTYPE_FIFO, fip, &fifo_ops_f); return (0); } Index: sys/file.h =================================================================== --- sys/file.h (revision 188457) +++ sys/file.h (working copy) @@ -169,6 +169,7 @@ extern struct fileops vnops; extern struct fileops badfileops; +extern struct fileops newfileops; extern struct fileops socketops; extern int maxfiles; /* kernel limit on number of open files */ extern int maxfilesperproc; /* per process limit on number of open files */