mirror of
https://github.com/opnsense/src.git
synced 2026-06-03 22:02:58 -04:00
null_bypass(): prevent loosing the only reference to the lower vnode
The upper vnode reference to the lower vnode is the only reference that keeps our pointer to the lower vnode alive. If lower vnode is relocked during the VOP call, upper vnode might become unlocked and reclaimed, which invalidates our reference. Add a transient vhold around VOP call. Reported and tested by: pho Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D31310
This commit is contained in:
parent
161e9a9736
commit
d5b078163e
1 changed files with 20 additions and 5 deletions
|
|
@ -266,6 +266,17 @@ null_bypass(struct vop_generic_args *ap)
|
|||
old_vps[i] = *this_vp_p;
|
||||
*(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
|
||||
|
||||
/*
|
||||
* The upper vnode reference to the lower
|
||||
* vnode is the only reference that keeps our
|
||||
* pointer to the lower vnode alive. If lower
|
||||
* vnode is relocked during the VOP call,
|
||||
* upper vnode might become unlocked and
|
||||
* reclaimed, which invalidates our reference.
|
||||
* Add a transient hold around VOP call.
|
||||
*/
|
||||
vhold(*this_vp_p);
|
||||
|
||||
/*
|
||||
* XXX - Several operations have the side effect
|
||||
* of vrele'ing their vp's. We must account for
|
||||
|
|
@ -300,6 +311,7 @@ null_bypass(struct vop_generic_args *ap)
|
|||
lvp = *(vps_p[i]);
|
||||
|
||||
/*
|
||||
* Get rid of the transient hold on lvp.
|
||||
* If lowervp was unlocked during VOP
|
||||
* operation, nullfs upper vnode could have
|
||||
* been reclaimed, which changes its v_vnlock
|
||||
|
|
@ -307,11 +319,14 @@ null_bypass(struct vop_generic_args *ap)
|
|||
* must move lock ownership from lower to
|
||||
* upper (reclaimed) vnode.
|
||||
*/
|
||||
if (lvp != NULLVP &&
|
||||
VOP_ISLOCKED(lvp) == LK_EXCLUSIVE &&
|
||||
old_vps[i]->v_vnlock != lvp->v_vnlock) {
|
||||
VOP_UNLOCK(lvp);
|
||||
VOP_LOCK(old_vps[i], LK_EXCLUSIVE | LK_RETRY);
|
||||
if (lvp != NULLVP) {
|
||||
if (VOP_ISLOCKED(lvp) == LK_EXCLUSIVE &&
|
||||
old_vps[i]->v_vnlock != lvp->v_vnlock) {
|
||||
VOP_UNLOCK(lvp);
|
||||
VOP_LOCK(old_vps[i], LK_EXCLUSIVE |
|
||||
LK_RETRY);
|
||||
}
|
||||
vdrop(lvp);
|
||||
}
|
||||
|
||||
*(vps_p[i]) = old_vps[i];
|
||||
|
|
|
|||
Loading…
Reference in a new issue