mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
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:
1 parent
8f20299b47
commit
2d21dbaaaf
2 files changed
+15
-44
No files matched your search
+15
-41
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in new issue
Block a user