From owner-freebsd-hackers@FreeBSD.ORG Wed Jan 3 17:26:50 2007 Return-Path: X-Original-To: freebsd-hackers@FreeBSD.ORG Delivered-To: freebsd-hackers@FreeBSD.ORG Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 52B6B16A415 for ; Wed, 3 Jan 2007 17:26:50 +0000 (UTC) (envelope-from dds@aueb.gr) Received: from mx-out-04.forthnet.gr (mx-out.forthnet.gr [193.92.150.105]) by mx1.freebsd.org (Postfix) with ESMTP id BAFE713C457 for ; Wed, 3 Jan 2007 17:26:49 +0000 (UTC) (envelope-from dds@aueb.gr) Received: from mx-av-02.forthnet.gr (mx-av.forthnet.gr [193.92.150.27]) by mx-out-04.forthnet.gr (8.13.7/8.13.7) with ESMTP id l03H4WQU020209 for ; Wed, 3 Jan 2007 19:04:32 +0200 Received: from mx-in-04.forthnet.gr (mx-in-04.forthnet.gr [193.92.150.163]) by mx-av-02.forthnet.gr (8.13.7/8.13.7) with ESMTP id l03H4WI8009840 for ; Wed, 3 Jan 2007 19:04:32 +0200 Received: from [192.168.136.22] (ppp197-7.adsl.forthnet.gr [62.1.146.7]) by mx-in-04.forthnet.gr (8.13.7/8.13.7) with ESMTP id l03H4Uld004412 for ; Wed, 3 Jan 2007 19:04:31 +0200 Authentication-Results: mx-in-04.forthnet.gr from=dds@aueb.gr; sender-id=neutral; spf=neutral Message-ID: <459BE218.7070605@aueb.gr> Date: Wed, 03 Jan 2007 19:04:24 +0200 From: Diomidis Spinellis User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.9) Gecko/20061211 SeaMonkey/1.0.7 MIME-Version: 1.0 To: freebsd-hackers@FreeBSD.ORG Content-Type: text/plain; charset=ISO-8859-7; format=flowed Content-Transfer-Encoding: 7bit Cc: Subject: Filesystem layering X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Jan 2007 17:26:50 -0000 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; } */ *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