diff options
author | Konstantin Belousov <kib@FreeBSD.org> | 2021-01-24 13:22:48 +0000 |
---|---|---|
committer | Konstantin Belousov <kib@FreeBSD.org> | 2021-02-12 01:02:20 +0000 |
commit | e4aaf35ab54958f74409790fa2b7df8c2d230cee (patch) | |
tree | d9f6ad64a274e27e58f56dd936f7bf533f9ba28b | |
parent | 49c117c193768b10f5fb1c5e4d6b88300cfbcdd6 (diff) |
nullfs: provide special bypass for VOP_VPUT_PAIR
Generic bypass cannot understand the rules of liveness for the VOP.
Reviewed by: chs, mckusick
Tested by: pho
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
-rw-r--r-- | sys/fs/nullfs/null_vnops.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/sys/fs/nullfs/null_vnops.c b/sys/fs/nullfs/null_vnops.c index 1de0cdfca9ac..45065e0be7b5 100644 --- a/sys/fs/nullfs/null_vnops.c +++ b/sys/fs/nullfs/null_vnops.c @@ -968,6 +968,54 @@ null_read_pgcache(struct vop_read_pgcache_args *ap) } /* + * Avoid standard bypass, since lower dvp and vp could be no longer + * valid after vput(). + */ +static int +null_vput_pair(struct vop_vput_pair_args *ap) +{ + struct mount *mp; + struct vnode *dvp, *ldvp, *lvp, *vp, *vp1, **vpp; + int error, res; + + dvp = ap->a_dvp; + ldvp = NULLVPTOLOWERVP(dvp); + vref(ldvp); + + vpp = ap->a_vpp; + vp = NULL; + lvp = NULL; + if (vpp != NULL) { + vp = *vpp; + if (vp != NULL) { + vhold(vp); + mp = vp->v_mount; + lvp = NULLVPTOLOWERVP(vp); + if (ap->a_unlock_vp) + vref(lvp); + } + } + + res = VOP_VPUT_PAIR(ldvp, &lvp, ap->a_unlock_vp); + + /* lvp might have been unlocked and vp reclaimed */ + if (vp != NULL) { + if (!ap->a_unlock_vp && vp->v_vnlock != lvp->v_vnlock) { + error = null_nodeget(mp, lvp, &vp1); + if (error == 0) { + vput(vp); + *vpp = vp1; + } + } + if (ap->a_unlock_vp) + vrele(vp); + vdrop(vp); + } + vrele(dvp); + return (res); +} + +/* * Global vfs data structures */ struct vop_vector null_vnodeops = { @@ -997,5 +1045,6 @@ struct vop_vector null_vnodeops = { .vop_vptocnp = null_vptocnp, .vop_vptofh = null_vptofh, .vop_add_writecount = null_add_writecount, + .vop_vput_pair = null_vput_pair, }; VFS_VOP_VECTOR_REGISTER(null_vnodeops); |