154753Sjohnh /* 254753Sjohnh * Copyright (c) 1992 The Regents of the University of California 354753Sjohnh * All rights reserved. 454753Sjohnh * 554766Sjohnh * This code is derived from the null layer of 6*54893Sheideman * John Heidemann from the UCLA Ficus project and 7*54893Sheideman * Jan-Simon Pendry's loopback file system. 854753Sjohnh * 954753Sjohnh * %sccs.include.redist.c% 1054753Sjohnh * 11*54893Sheideman * @(#)null_vnops.c 1.4 (Berkeley) 07/10/92 1254766Sjohnh * 1354766Sjohnh * Ancestors: 1454753Sjohnh * @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92 1554766Sjohnh * $Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 1654766Sjohnh * ...and... 1754766Sjohnh * @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project 1854753Sjohnh */ 1954753Sjohnh 2054753Sjohnh /* 2154766Sjohnh * Null Layer 2254766Sjohnh * 2354766Sjohnh * The null layer duplicates a portion of the file system 2454766Sjohnh * name space under a new name. In this respect, it is 2554766Sjohnh * similar to the loopback file system. It differs from 2654766Sjohnh * the loopback fs in two respects: it is implemented using 27*54893Sheideman * a bypass operation, and it's "null-node"s stack above 2854766Sjohnh * all lower-layer vnodes, not just over directory vnodes. 2954766Sjohnh * 3054766Sjohnh * The null layer is the minimum file system layer, 3154766Sjohnh * simply bypassing all possible operations to the lower layer 3254766Sjohnh * for processing there. All but vop_getattr, _inactive, _reclaim, 3354766Sjohnh * and _print are bypassed. 3454766Sjohnh * 3554766Sjohnh * Vop_getattr is not bypassed so that we can change the fsid being 3654766Sjohnh * returned. Vop_{inactive,reclaim} are bypassed so that 3754766Sjohnh * they can handle freeing null-layer specific data. 3854766Sjohnh * Vop_print is not bypassed for debugging. 3954766Sjohnh * 40*54893Sheideman * 41*54893Sheideman * INVOKING OPERATIONS ON LOWER LAYERS 42*54893Sheideman * 4354766Sjohnh * NEEDSWORK: Describe methods to invoke operations on the lower layer 4454766Sjohnh * (bypass vs. VOP). 45*54893Sheideman * 46*54893Sheideman * 47*54893Sheideman * CREATING NEW FILESYSTEM LAYERS 48*54893Sheideman * 49*54893Sheideman * One of the easiest ways to construct new file system layers is to make 50*54893Sheideman * a copy of the null layer, rename all files and variables, and 51*54893Sheideman * then begin modifing the copy. Sed can be used to easily rename 52*54893Sheideman * all variables. 53*54893Sheideman * 5454753Sjohnh */ 5554753Sjohnh 5654753Sjohnh #include <sys/param.h> 5754753Sjohnh #include <sys/systm.h> 5854753Sjohnh #include <sys/proc.h> 5954753Sjohnh #include <sys/time.h> 6054753Sjohnh #include <sys/types.h> 6154753Sjohnh #include <sys/vnode.h> 6254753Sjohnh #include <sys/mount.h> 6354753Sjohnh #include <sys/namei.h> 6454753Sjohnh #include <sys/malloc.h> 6554753Sjohnh #include <sys/buf.h> 66*54893Sheideman #include <nullfs/null.h> 6754753Sjohnh 6854753Sjohnh 6954766Sjohnh int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ 7054753Sjohnh 7154753Sjohnh /* 7254766Sjohnh * This is the 10-Apr-92 bypass routine. 7354766Sjohnh * This version has been optimized for speed, throwing away some 7454766Sjohnh * safety checks. It should still always work, but it's not as 7554766Sjohnh * robust to programmer errors. 7654766Sjohnh * Define SAFETY to include some error checking code. 7754766Sjohnh * 7854766Sjohnh * In general, we map all vnodes going down and unmap them on the way back. 7954766Sjohnh * As an exception to this, vnodes can be marked "unmapped" by setting 8054766Sjohnh * the Nth bit in operation's vdesc_flags. 8154766Sjohnh * 8254766Sjohnh * Also, some BSD vnode operations have the side effect of vrele'ing 8354766Sjohnh * their arguments. With stacking, the reference counts are held 8454766Sjohnh * by the upper node, not the lower one, so we must handle these 8554766Sjohnh * side-effects here. This is not of concern in Sun-derived systems 8654766Sjohnh * since there are no such side-effects. 8754766Sjohnh * 8854766Sjohnh * This makes the following assumptions: 8954766Sjohnh * - only one returned vpp 9054766Sjohnh * - no INOUT vpp's (Sun's vop_open has one of these) 9154766Sjohnh * - the vnode operation vector of the first vnode should be used 9254766Sjohnh * to determine what implementation of the op should be invoked 9354766Sjohnh * - all mapped vnodes are of our vnode-type (NEEDSWORK: 9454766Sjohnh * problems on rmdir'ing mount points and renaming?) 9554766Sjohnh */ 9654766Sjohnh int 9754766Sjohnh null_bypass(ap) 98*54893Sheideman struct vop_generic_args *ap; 9954753Sjohnh { 100*54893Sheideman extern int (**null_vnodeop_p)(); /* not extern, really "forward" */ 101*54893Sheideman register struct vnode **this_vp_p; 10254753Sjohnh int error; 10354766Sjohnh struct vnode *old_vps[VDESC_MAX_VPS]; 10454766Sjohnh struct vnode **vps_p[VDESC_MAX_VPS]; 10554766Sjohnh struct vnode ***vppp; 10654766Sjohnh struct vnodeop_desc *descp = ap->a_desc; 107*54893Sheideman int reles, i; 10854753Sjohnh 10954766Sjohnh if (null_bug_bypass) 11054766Sjohnh printf ("null_bypass: %s\n", descp->vdesc_name); 11154753Sjohnh 11254766Sjohnh #ifdef SAFETY 11354753Sjohnh /* 11454766Sjohnh * We require at least one vp. 11554753Sjohnh */ 11654766Sjohnh if (descp->vdesc_vp_offsets==NULL || 11754766Sjohnh descp->vdesc_vp_offsets[0]==VDESC_NO_OFFSET) 11854766Sjohnh panic ("null_bypass: no vp's in map.\n"); 11954753Sjohnh #endif 12054753Sjohnh 12154753Sjohnh /* 12254766Sjohnh * Map the vnodes going in. 12354766Sjohnh * Later, we'll invoke the operation based on 12454766Sjohnh * the first mapped vnode's operation vector. 12554753Sjohnh */ 126*54893Sheideman reles = descp->vdesc_flags; 127*54893Sheideman for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) { 12854766Sjohnh if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET) 12954766Sjohnh break; /* bail out at end of list */ 13054766Sjohnh vps_p[i] = this_vp_p = 13154766Sjohnh VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap); 132*54893Sheideman /* 133*54893Sheideman * We're not guaranteed that any but the first vnode 134*54893Sheideman * are of our type. Check for and don't map any 135*54893Sheideman * that aren't. 136*54893Sheideman */ 137*54893Sheideman if ((*this_vp_p)->v_op != null_vnodeop_p) { 138*54893Sheideman old_vps[i] = NULL; 139*54893Sheideman } else { 140*54893Sheideman old_vps[i] = *this_vp_p; 141*54893Sheideman *(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p); 142*54893Sheideman if (reles & 1) 143*54893Sheideman VREF(*this_vp_p); 144*54893Sheideman }; 14554766Sjohnh 14654766Sjohnh }; 14754753Sjohnh 14854753Sjohnh /* 14954766Sjohnh * Call the operation on the lower layer 15054766Sjohnh * with the modified argument structure. 15154753Sjohnh */ 15254766Sjohnh error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap); 15354753Sjohnh 15454753Sjohnh /* 15554766Sjohnh * Maintain the illusion of call-by-value 15654766Sjohnh * by restoring vnodes in the argument structure 15754766Sjohnh * to their original value. 15854753Sjohnh */ 159*54893Sheideman reles = descp->vdesc_flags; 160*54893Sheideman for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) { 16154766Sjohnh if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET) 16254766Sjohnh break; /* bail out at end of list */ 163*54893Sheideman if (old_vps[i]) { 164*54893Sheideman *(vps_p[i]) = old_vps[i]; 165*54893Sheideman if (reles & 1) 166*54893Sheideman vrele(*(vps_p[i])); 167*54893Sheideman }; 16854766Sjohnh }; 16954766Sjohnh 17054753Sjohnh /* 17154766Sjohnh * Map the possible out-going vpp. 17254753Sjohnh */ 17354766Sjohnh if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && 17454766Sjohnh !(descp->vdesc_flags & VDESC_NOMAP_VPP) && 17554766Sjohnh !error) { 17654766Sjohnh vppp=VOPARG_OFFSETTO(struct vnode***, 17754766Sjohnh descp->vdesc_vpp_offset,ap); 178*54893Sheideman error = null_node_create(old_vps[0]->v_mount, **vppp, *vppp); 17954766Sjohnh }; 18054753Sjohnh 18154766Sjohnh return (error); 18254753Sjohnh } 18354753Sjohnh 18454753Sjohnh 18554753Sjohnh /* 18654766Sjohnh * We handle getattr to change the fsid. 18754753Sjohnh */ 18854766Sjohnh int 18954766Sjohnh null_getattr(ap) 190*54893Sheideman struct vop_getattr_args *ap; 19154753Sjohnh { 19254753Sjohnh int error; 19354766Sjohnh if (error=null_bypass(ap)) 19454766Sjohnh return error; 19554766Sjohnh /* Requires that arguments be restored. */ 19654766Sjohnh ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 19754766Sjohnh return 0; 19854766Sjohnh } 19954753Sjohnh 20054753Sjohnh 20154766Sjohnh int 20254754Sjohnh null_inactive (ap) 20354753Sjohnh struct vop_inactive_args *ap; 20454753Sjohnh { 20554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 206*54893Sheideman printf("null_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp)); 20754753Sjohnh #endif 20854766Sjohnh /* 20954766Sjohnh * Do nothing (and _don't_ bypass). 21054766Sjohnh * Wait to vrele lowervp until reclaim, 21154766Sjohnh * so that until then our null_node is in the 21254766Sjohnh * cache and reusable. 21354766Sjohnh * 21454766Sjohnh * NEEDSWORK: Someday, consider inactive'ing 21554766Sjohnh * the lowervp and then trying to reactivate it 21654766Sjohnh * like they do in the name lookup cache code. 21754766Sjohnh * That's too much work for now. 21854766Sjohnh */ 21954766Sjohnh return 0; 22054753Sjohnh } 22154753Sjohnh 22254754Sjohnh null_reclaim (ap) 22354753Sjohnh struct vop_reclaim_args *ap; 22454753Sjohnh { 22554753Sjohnh struct vnode *targetvp; 22654754Sjohnh #ifdef NULLFS_DIAGNOSTIC 227*54893Sheideman printf("null_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp)); 22854753Sjohnh #endif 229*54893Sheideman remque(VTONULL(ap->a_vp)); /* NEEDSWORK: What? */ 230*54893Sheideman vrele (NULLVPTOLOWERVP(ap->a_vp)); /* release lower layer */ 23154753Sjohnh FREE(ap->a_vp->v_data, M_TEMP); 23254753Sjohnh ap->a_vp->v_data = 0; 23354753Sjohnh return (0); 23454753Sjohnh } 23554753Sjohnh 23654754Sjohnh null_bmap (ap) 23754753Sjohnh struct vop_bmap_args *ap; 23854753Sjohnh { 23954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 240*54893Sheideman printf("null_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp)); 24154753Sjohnh #endif 24254753Sjohnh 243*54893Sheideman return VOP_BMAP(NULLVPTOLOWERVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp); 24454753Sjohnh } 24554753Sjohnh 24654754Sjohnh null_strategy (ap) 24754753Sjohnh struct vop_strategy_args *ap; 24854753Sjohnh { 24954753Sjohnh int error; 25054766Sjohnh struct vnode *savedvp; 25154753Sjohnh 25254754Sjohnh #ifdef NULLFS_DIAGNOSTIC 253*54893Sheideman printf("null_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, NULLVPTOLOWERVP(ap->a_bp->b_vp)); 25454753Sjohnh #endif 25554753Sjohnh 25654766Sjohnh savedvp = ap->a_bp->b_vp; 25754753Sjohnh 25854753Sjohnh error = VOP_STRATEGY(ap->a_bp); 25954753Sjohnh 26054766Sjohnh ap->a_bp->b_vp = savedvp; 26154753Sjohnh 26254766Sjohnh return error; 26354753Sjohnh } 26454753Sjohnh 26554766Sjohnh 26654766Sjohnh int 26754754Sjohnh null_print (ap) 26854753Sjohnh struct vop_print_args *ap; 26954753Sjohnh { 27054766Sjohnh register struct vnode *vp = ap->a_vp; 271*54893Sheideman printf ("tag VT_NULLFS, vp=%x, lowervp=%x\n", vp, NULLVPTOLOWERVP(vp)); 27254766Sjohnh return 0; 27354753Sjohnh } 27454753Sjohnh 27554753Sjohnh 27654753Sjohnh /* 27754766Sjohnh * Global vfs data structures 27854753Sjohnh */ 27954753Sjohnh /* 28054766Sjohnh * NEEDSWORK: strategy,bmap are hand coded currently. They should 28154766Sjohnh * go away with a merged buffer/block cache. 28254766Sjohnh * 28354753Sjohnh */ 28454766Sjohnh int (**null_vnodeop_p)(); 285*54893Sheideman struct vnodeopv_entry_desc null_vnodeop_entries[] = { 28654766Sjohnh { &vop_default_desc, null_bypass }, 28754753Sjohnh 28854766Sjohnh { &vop_getattr_desc, null_getattr }, 28954766Sjohnh { &vop_inactive_desc, null_inactive }, 29054766Sjohnh { &vop_reclaim_desc, null_reclaim }, 29154766Sjohnh { &vop_print_desc, null_print }, 29254753Sjohnh 29354766Sjohnh { &vop_bmap_desc, null_bmap }, 29454766Sjohnh { &vop_strategy_desc, null_strategy }, 29554753Sjohnh 29654753Sjohnh { (struct vnodeop_desc*)NULL, (int(*)())NULL } 29754753Sjohnh }; 298*54893Sheideman struct vnodeopv_desc null_vnodeop_opv_desc = 299*54893Sheideman { &null_vnodeop_p, null_vnodeop_entries }; 300