diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2021-01-24 13:22:48 +0000 |
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2021-02-24 07:43:22 +0000 |
| commit | e45f7c841983f6ccd65d6061a5542989a8201826 (patch) | |
| tree | f350efbf75b68a4bfb304e85b0a713f88d04e50a | |
| parent | 1f96e4cd1e3c500d3837a77811ce47b96353296b (diff) | |
nullfs: provide special bypass for VOP_VPUT_PAIR
(cherry picked from commit e4aaf35ab54958f74409790fa2b7df8c2d230cee)
| -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); |
