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>