The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=a8e92198f854c2766eedec5a2ea3cc23c64d7b12
commit a8e92198f854c2766eedec5a2ea3cc23c64d7b12 Author: Konstantin Belousov <[email protected]> AuthorDate: 2026-01-26 01:49:32 +0000 Commit: Konstantin Belousov <[email protected]> CommitDate: 2026-02-02 19:48:25 +0000 devfs: unlock the directory vnode around the call to dev_clone handler The lock around dev_clone is unfortunate because cloner might need to take its own locks that establish the order with devfs vnodes, and then transiently participates in further VFS locks order. For instance, this way the proctree_lock or allproc_lock become involved. Unlock dvp, we can unwind if the vnode become doomed while cloner was called. Reported and tested by: pho Reviewed by: kevans, markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D55028 --- sys/fs/devfs/devfs_vnops.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) 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);
