diff options
Diffstat (limited to 'sys/fs/devfs/devfs_vnops.c')
| -rw-r--r-- | sys/fs/devfs/devfs_vnops.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index 323f1e0fa961..d594b1584757 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -367,6 +367,9 @@ devfs_populate_vp(struct vnode *vp) 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 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock) 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); |
