Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 03 Jan 2007 19:04:24 +0200
From:      Diomidis Spinellis <dds@aueb.gr>
To:        freebsd-hackers@FreeBSD.ORG
Subject:   Filesystem layering
Message-ID:  <459BE218.7070605@aueb.gr>

next in thread | raw e-mail | index | archive | help
I've been puzzling for a couple of days to understand how the code moves 
from one layer to another in the FreeeBSD stacked filesystems, but I'm 
stuck.  I've scrutinized the code, and I've read carefully pp. 254-257 
of the "Design and Implementation of the FreeBSD Operating System", but 
one detail still escapes me.  When is control passed from one layer with 
a bypass function to a lower one?

Consider a case when umapfs is layered on top of another filesystem.  As 
far as I can tell, the following excerpted sequence of function calls 
will end up continuously calling VOP_READ_APV passing umap_vnodeop as 
its first argument.  Obviously somewhere somewhere the cycle breaks, but 
I can't see where.

static int
vn_read(fp, uio, active_cred, flags, td)
     struct file *fp;
     struct uio *uio;
     struct ucred *active_cred;
     struct thread *td;
     int flags;
{
     struct vnode *vp;
     vp = fp->f_vnode;	/* dds: vp->v_op == umap_vnodeops */
     error = VOP_READ(vp, uio, ioflag, fp->f_cred);
}

static __inline int VOP_READ(
     struct vnode *vp,
     struct uio *uio,
     int ioflag,
     struct ucred *cred)
{
     struct vop_read_args a;

     a.a_gen.a_desc = &vop_read_desc;
     a.a_vp = vp;	/* dds: a.a_vp->v_op == umap_vnodeops */
     a.a_uio = uio;
     a.a_ioflag = ioflag;
     a.a_cred = cred;
     /* dds: vp->v_op == umap_vnodeops */
     return (VOP_READ_APV(vp->v_op, &a));
}

int
VOP_READ_APV(struct vop_vector *vop, struct vop_read_args *a)
{
     int rc;

     /* dds: vop->vop_bypass == umap_bypass; while body skipped */
     while(vop != NULL &&
         vop->vop_read == NULL && vop->vop_bypass == NULL)
         vop = vop->vop_default;
     if (vop->vop_read != NULL)
         rc = vop->vop_read(a);
     else
         rc = vop->vop_bypass(&a->a_gen); /* dds: this is executed */
}

static int
umap_bypass(ap)
     struct vop_generic_args /* {
         struct vnodeop_desc *a_desc;
         <other random data follows, presumably>
     } */ *ap;
{
	/* ... */
     error = VCALL(ap);	/* dds: ap->a_desc == &vop_read_desc */
}

#define VCALL(c) ((c)->a_desc->vdesc_call(c))

/* dds: vdesc_call == VOP_READ_AP */

int
VOP_READ_AP(struct vop_read_args *a)
{
     /* dds: a->a_vp->v_op still == umap_vnodeops ???? */
     return(VOP_READ_APV(a->a_vp->v_op, a));
}

/* dds: again VOP_READ_APV with the same arguments? */
int
VOP_READ_APV(struct vop_vector *vop, struct vop_read_args *a)
{
     int rc;

     while(vop != NULL &&
         vop->vop_read == NULL && vop->vop_bypass == NULL)
         vop = vop->vop_default;
     if (vop->vop_read != NULL)
         rc = vop->vop_read(a);
     else
         rc = vop->vop_bypass(&a->a_gen);
}

Diomidis Spinellis - http://www.spinellis.gr



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?459BE218.7070605>