nullfs: provide custom bypass for VOP_READ_PGCACHE().

Normal bypass expects locked vnode, which is not true for
VOP_READ_PGCACHE().  Ensure liveness of the lower vnode by taking the
upper vnode interlock, which is also taked by null_reclaim() when
setting v_data to NULL.

Reported and tested by:	pho
Reviewed by:	markj, mjg
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D27327
This commit is contained in:
kib 2020-11-26 18:16:32 +00:00
parent 1cede83674
commit 3d3de5ce17

View File

@ -947,6 +947,28 @@ null_vptocnp(struct vop_vptocnp_args *ap)
return (error); return (error);
} }
static int
null_read_pgcache(struct vop_read_pgcache_args *ap)
{
struct vnode *lvp, *vp;
struct null_node *xp;
int error;
vp = ap->a_vp;
VI_LOCK(vp);
xp = VTONULL(vp);
if (xp == NULL) {
VI_UNLOCK(vp);
return (EJUSTRETURN);
}
lvp = xp->null_lowervp;
vref(lvp);
VI_UNLOCK(vp);
error = VOP_READ_PGCACHE(lvp, ap->a_uio, ap->a_ioflag, ap->a_cred);
vrele(lvp);
return (error);
}
/* /*
* Global vfs data structures * Global vfs data structures
*/ */
@ -966,6 +988,7 @@ struct vop_vector null_vnodeops = {
.vop_lookup = null_lookup, .vop_lookup = null_lookup,
.vop_open = null_open, .vop_open = null_open,
.vop_print = null_print, .vop_print = null_print,
.vop_read_pgcache = null_read_pgcache,
.vop_reclaim = null_reclaim, .vop_reclaim = null_reclaim,
.vop_remove = null_remove, .vop_remove = null_remove,
.vop_rename = null_rename, .vop_rename = null_rename,