fix p9fs_vget_common() panics

This addresses a race when two vnodes attempt to call vfs_hash_insert(),
but only one succeeds. Also, in case of an error from
p9fs_reload_stats_dotl(), it marks the vnode for deletion.

Reviewed by:	kib
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D58632
This commit is contained in:
Nimish Jain authored and Konstantin Belousov committed 2026-08-04 19:00:48 +03:00
1 parent 8f20299b47
commit 2d21dbaaaf
2 files changed
+15 -44

No files matched your search

+15 -41
View File
@@ -263,7 +263,7 @@ p9fs_vget_common(struct mount *mp, struct p9fs_node *np, int flags,
struct p9fs_node *node;
struct thread *td;
uint32_t hash;
int error, error_reload = 0;
int error;
struct p9fs_inode *inode;
td = curthread;
@@ -352,57 +352,31 @@ p9fs_vget_common(struct mount *mp, struct p9fs_node *np, int flags,
if (vp->v_type != VFIFO)
VN_LOCK_ASHARE(vp);
error = insmntque(vp, mp);
if (error != 0) {
/*
* vput(vp) is already called from insmntque_stddtr().
* Just goto 'out' to dispose the node.
*/
goto out;
}
if (error != 0)
return (error);
/* Init the vnode with the disk info*/
error = p9fs_reload_stats_dotl(vp, curthread->td_ucred);
if (error != 0) {
error_reload = 1;
goto out;
P9FS_NODE_SETF(np, P9FS_NODE_DELETED);
vgone(vp);
vput(vp);
return (error);
}
error = vfs_hash_insert(vp, hash, flags, td, vpp,
p9fs_node_cmp, &fid->qid);
if (error != 0) {
goto out;
}
if (error != 0 || *vpp != NULL)
return (error);
if (*vpp == NULL) {
P9FS_LOCK(vses);
STAILQ_INSERT_TAIL(&vses->virt_node_list, np, p9fs_node_next);
P9FS_NODE_SETF(np, P9FS_NODE_IN_SESSION);
P9FS_UNLOCK(vses);
vn_set_state(vp, VSTATE_CONSTRUCTED);
*vpp = vp;
} else {
/*
* Returning matching vp found in hashlist.
* So cleanup the np allocated above in this context.
*/
if (!IS_ROOT(np)) {
p9fs_destroy_node(&np);
}
}
P9FS_LOCK(vses);
STAILQ_INSERT_TAIL(&vses->virt_node_list, np, p9fs_node_next);
P9FS_NODE_SETF(np, P9FS_NODE_IN_SESSION);
P9FS_UNLOCK(vses);
vn_set_state(vp, VSTATE_CONSTRUCTED);
*vpp = vp;
return (0);
out:
/* Something went wrong, dispose the node */
if (!IS_ROOT(np)) {
p9fs_destroy_node(&np);
}
if (error_reload) {
vput(vp);
}
*vpp = NULL;
return (error);
}
/* Main mount function for 9pfs */
-3
View File
@@ -115,9 +115,6 @@ p9fs_cleanup(struct p9fs_node *np)
if ((np->flags & P9FS_NODE_IN_SESSION) != 0) {
P9FS_NODE_CLRF(np, P9FS_NODE_IN_SESSION);
STAILQ_REMOVE(&vses->virt_node_list, np, p9fs_node, p9fs_node_next);
} else {
P9FS_UNLOCK(vses);
return;
}
P9FS_UNLOCK(vses);