try_again:
while ((vp = node->v_node) != NULL) {
error = vget(vp, LK_EXCLUSIVE);
- if (error != ENOENT) {
+ if (error == 0) {
*vpp = vp;
goto out;
}
+ if (error != ENOENT) {
+ *vpp = NULL;
+ goto out;
+ }
}
if ((error = getnewvnode(VT_DEVFS, node->mp, vpp, 0, 0)) != 0)
node->flags |= DEVFS_INVISIBLE;
/*
- * Unlock around dev_dclose()
+ * Unlock around dev_dclose(), unless the vnode is
+ * undergoing a vgone/reclaim (during umount).
*/
needrelock = 0;
- if (vn_islocked(vp)) {
+ if ((vp->v_flag & VRECLAIMED) == 0 && vn_islocked(vp)) {
needrelock = 1;
vn_unlock(vp);
}
/*
* WARNING! If the device destroys itself the devfs node
* can disappear here.
+ *
+ * WARNING! vn_lock() will fail if the vp is in a VRECLAIM,
+ * which can occur during umount.
*/
error = dev_dclose(dev, ap->a_fflag, S_IFCHR);
/* node is now stale */
- if (needrelock)
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ if (needrelock) {
+ if (vn_lock(vp, LK_EXCLUSIVE | LK_RETRY) != 0) {
+ panic("devfs_spec_close: vnode %p "
+ "unexpectedly could not be relocked",
+ vp);
+ }
+ }
} else {
error = 0;
}