git: d5b078163e0d - main - null_bypass(): prevent loosing the only reference to the lower vnode
Konstantin Belousov
kib at FreeBSD.org
Tue Jul 27 16:58:58 UTC 2021
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=d5b078163e0d6bb2fe36f8e49a44853908d5e2db
commit d5b078163e0d6bb2fe36f8e49a44853908d5e2db
Author: Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-07-20 00:53:08 +0000
Commit: Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-07-27 16:58:47 +0000
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
---
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 0d5092f5e33d..47b0bda32b6b 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-main
mailing list