git: 0a4eb4d65c11 - stable/13 - null_bypass(): prevent loosing the only reference to the lower vnode
Konstantin Belousov
kib at FreeBSD.org
Tue Aug 3 09:52:47 UTC 2021
The branch stable/13 has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=0a4eb4d65c11dc775733dd5a0a470419e1376515
commit 0a4eb4d65c11dc775733dd5a0a470419e1376515
Author: Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-07-20 00:53:08 +0000
Commit: Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-08-03 09:52:35 +0000
null_bypass(): prevent loosing the only reference to the lower vnode
(cherry picked from commit d5b078163e0d6bb2fe36f8e49a44853908d5e2db)
---
sys/fs/nullfs/null_vnops.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c
index 4dfc5efaf9ed..03f8b0dcbf7d 100644
--- a/sys/fs/nullfs/null_vnops.c
+++ b/sys/fs/nullfs/null_vnops.c
@@ -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];
More information about the dev-commits-src-all
mailing list