Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/devfs/devfs_vnops.c
| Show First 20 Lines • Show All 361 Lines • ▼ Show 20 Lines | |||||
| devfs_populate_vp(struct vnode *vp) | devfs_populate_vp(struct vnode *vp) | ||||
| { | { | ||||
| struct devfs_dirent *de; | struct devfs_dirent *de; | ||||
| struct devfs_mount *dmp; | struct devfs_mount *dmp; | ||||
| int locked; | int locked; | ||||
| ASSERT_VOP_LOCKED(vp, "devfs_populate_vp"); | ASSERT_VOP_LOCKED(vp, "devfs_populate_vp"); | ||||
| if (VN_IS_DOOMED(vp)) | |||||
| return (ENOENT); | |||||
| dmp = VFSTODEVFS(vp->v_mount); | dmp = VFSTODEVFS(vp->v_mount); | ||||
| if (!devfs_populate_needed(dmp)) { | if (!devfs_populate_needed(dmp)) { | ||||
| sx_xlock(&dmp->dm_lock); | sx_xlock(&dmp->dm_lock); | ||||
| goto out_nopopulate; | goto out_nopopulate; | ||||
| } | } | ||||
| locked = VOP_ISLOCKED(vp); | locked = VOP_ISLOCKED(vp); | ||||
| ▲ Show 20 Lines • Show All 745 Lines • ▼ Show 20 Lines | while (de == NULL) { /* While(...) so we can use break */ | ||||
| */ | */ | ||||
| pname = devfs_fqpn(specname, dmp, dd, cnp); | pname = devfs_fqpn(specname, dmp, dd, cnp); | ||||
| if (pname == NULL) | if (pname == NULL) | ||||
| break; | break; | ||||
| cdev = NULL; | cdev = NULL; | ||||
| DEVFS_DMP_HOLD(dmp); | DEVFS_DMP_HOLD(dmp); | ||||
| sx_xunlock(&dmp->dm_lock); | 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, | EVENTHANDLER_INVOKE(dev_clone, | ||||
| td->td_ucred, pname, strlen(pname), &cdev); | td->td_ucred, pname, strlen(pname), &cdev); | ||||
| vn_lock(dvp, dvplocked | LK_RETRY); | |||||
| if (cdev == NULL) | if (cdev == NULL) | ||||
| sx_xlock(&dmp->dm_lock); | sx_xlock(&dmp->dm_lock); | ||||
| else if (devfs_populate_vp(dvp) != 0) { | else if (devfs_populate_vp(dvp) != 0) { | ||||
markj: Why is it correct to handle the DOOMED case after checking `cdev == NULL`? It's not immediately… | |||||
Done Inline ActionsWhy is it not? If cdev == NULL, we fall to some of the paths that end up with return (ENOENT);. Either the devfs instance is being unmounted, and then DEVFS_DMP_DROP() is true and we use the exit path starting at line 1153 (patched). Or we break out of the loop, and since de == NULL, we return ENOENT in line 1179. kib: Why is it not? If cdev == NULL, we fall to some of the paths that end up with `return… | |||||
Not Done Inline ActionsI see now, thanks. Specifically, I missed that we must fall into the de == NULL case if the case on line 1162 is hit. markj: I see now, thanks. Specifically, I missed that we must fall into the de == NULL case if the… | |||||
| *dm_unlock = 0; | *dm_unlock = 0; | ||||
| sx_xlock(&dmp->dm_lock); | sx_xlock(&dmp->dm_lock); | ||||
| if (DEVFS_DMP_DROP(dmp)) { | if (DEVFS_DMP_DROP(dmp)) { | ||||
| sx_xunlock(&dmp->dm_lock); | sx_xunlock(&dmp->dm_lock); | ||||
| devfs_unmount_final(dmp); | devfs_unmount_final(dmp); | ||||
| } else | } else | ||||
| sx_xunlock(&dmp->dm_lock); | sx_xunlock(&dmp->dm_lock); | ||||
| dev_rel(cdev); | dev_rel(cdev); | ||||
| ▲ Show 20 Lines • Show All 1,017 Lines • Show Last 20 Lines | |||||
Why is it correct to handle the DOOMED case after checking cdev == NULL? It's not immediately clear to me.