diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -367,6 +367,9 @@ ASSERT_VOP_LOCKED(vp, "devfs_populate_vp"); + if (VN_IS_DOOMED(vp)) + return (ENOENT); + dmp = VFSTODEVFS(vp->v_mount); if (!devfs_populate_needed(dmp)) { sx_xlock(&dmp->dm_lock); @@ -1128,8 +1131,25 @@ cdev = NULL; DEVFS_DMP_HOLD(dmp); sx_xunlock(&dmp->dm_lock); + dvplocked = VOP_ISLOCKED(dvp); + + /* + * Invoke the dev_clone handler. Unlock dvp around it + * to simplify the cloner operations. + * + * If dvp is reclaimed while we unlocked it, we return + * with ENOENT by some of the paths below. If cloner + * returned cdev, then devfs_populate_vp() notes the + * reclamation. Otherwise, note that either our devfs + * mount is being unmounted, then DEVFS_DMP_DROP() + * returns true, and we return ENOENT this way. Or, + * because de == NULL, the check for it after the loop + * returns ENOENT. + */ + VOP_UNLOCK(dvp); EVENTHANDLER_INVOKE(dev_clone, td->td_ucred, pname, strlen(pname), &cdev); + vn_lock(dvp, dvplocked | LK_RETRY); if (cdev == NULL) sx_xlock(&dmp->dm_lock);