154753Sjohnh /* 254753Sjohnh * Copyright (c) 1992 The Regents of the University of California 354753Sjohnh * All rights reserved. 454753Sjohnh * 5*54766Sjohnh * This code is derived from the null layer of 6*54766Sjohnh * John Heidemann of the UCLA Ficus project and 7*54766Sjohnh * the Jan-Simon Pendry's loopback file system. 854753Sjohnh * 954753Sjohnh * %sccs.include.redist.c% 1054753Sjohnh * 11*54766Sjohnh * @(#)null_vnops.c 1.3 (Berkeley) 07/07/92 12*54766Sjohnh * 13*54766Sjohnh * Ancestors: 1454753Sjohnh * @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92 15*54766Sjohnh * $Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 16*54766Sjohnh * ...and... 17*54766Sjohnh * @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project 1854753Sjohnh */ 1954753Sjohnh 2054753Sjohnh /* 21*54766Sjohnh * Null Layer 22*54766Sjohnh * 23*54766Sjohnh * The null layer duplicates a portion of the file system 24*54766Sjohnh * name space under a new name. In this respect, it is 25*54766Sjohnh * similar to the loopback file system. It differs from 26*54766Sjohnh * the loopback fs in two respects: it is implemented using 27*54766Sjohnh * a bypass operation, and it's "null-nodes" stack above 28*54766Sjohnh * all lower-layer vnodes, not just over directory vnodes. 29*54766Sjohnh * 30*54766Sjohnh * The null layer is the minimum file system layer, 31*54766Sjohnh * simply bypassing all possible operations to the lower layer 32*54766Sjohnh * for processing there. All but vop_getattr, _inactive, _reclaim, 33*54766Sjohnh * and _print are bypassed. 34*54766Sjohnh * 35*54766Sjohnh * Vop_getattr is not bypassed so that we can change the fsid being 36*54766Sjohnh * returned. Vop_{inactive,reclaim} are bypassed so that 37*54766Sjohnh * they can handle freeing null-layer specific data. 38*54766Sjohnh * Vop_print is not bypassed for debugging. 39*54766Sjohnh * 40*54766Sjohnh * NEEDSWORK: Describe methods to invoke operations on the lower layer 41*54766Sjohnh * (bypass vs. VOP). 4254753Sjohnh */ 4354753Sjohnh 4454753Sjohnh #include <sys/param.h> 4554753Sjohnh #include <sys/systm.h> 4654753Sjohnh #include <sys/proc.h> 4754753Sjohnh #include <sys/time.h> 4854753Sjohnh #include <sys/types.h> 4954753Sjohnh #include <sys/vnode.h> 5054753Sjohnh #include <sys/mount.h> 5154753Sjohnh #include <sys/namei.h> 5254753Sjohnh #include <sys/malloc.h> 5354753Sjohnh #include <sys/buf.h> 5454753Sjohnh #include <lofs/lofs.h> 5554753Sjohnh 5654753Sjohnh 57*54766Sjohnh int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ 5854753Sjohnh 5954753Sjohnh /* 60*54766Sjohnh * This is the 10-Apr-92 bypass routine. 61*54766Sjohnh * This version has been optimized for speed, throwing away some 62*54766Sjohnh * safety checks. It should still always work, but it's not as 63*54766Sjohnh * robust to programmer errors. 64*54766Sjohnh * Define SAFETY to include some error checking code. 65*54766Sjohnh * 66*54766Sjohnh * In general, we map all vnodes going down and unmap them on the way back. 67*54766Sjohnh * As an exception to this, vnodes can be marked "unmapped" by setting 68*54766Sjohnh * the Nth bit in operation's vdesc_flags. 69*54766Sjohnh * 70*54766Sjohnh * Also, some BSD vnode operations have the side effect of vrele'ing 71*54766Sjohnh * their arguments. With stacking, the reference counts are held 72*54766Sjohnh * by the upper node, not the lower one, so we must handle these 73*54766Sjohnh * side-effects here. This is not of concern in Sun-derived systems 74*54766Sjohnh * since there are no such side-effects. 75*54766Sjohnh * 76*54766Sjohnh * This makes the following assumptions: 77*54766Sjohnh * - only one returned vpp 78*54766Sjohnh * - no INOUT vpp's (Sun's vop_open has one of these) 79*54766Sjohnh * - the vnode operation vector of the first vnode should be used 80*54766Sjohnh * to determine what implementation of the op should be invoked 81*54766Sjohnh * - all mapped vnodes are of our vnode-type (NEEDSWORK: 82*54766Sjohnh * problems on rmdir'ing mount points and renaming?) 83*54766Sjohnh */ 84*54766Sjohnh int 85*54766Sjohnh null_bypass(ap) 86*54766Sjohnh struct nvop_generic_args *ap; 8754753Sjohnh { 88*54766Sjohnh register int this_vp_p; 8954753Sjohnh int error; 90*54766Sjohnh struct vnode *old_vps[VDESC_MAX_VPS]; 91*54766Sjohnh struct vnode **vps_p[VDESC_MAX_VPS]; 92*54766Sjohnh struct vnode ***vppp; 93*54766Sjohnh struct vnodeop_desc *descp = ap->a_desc; 94*54766Sjohnh int maps, reles, i; 9554753Sjohnh 96*54766Sjohnh if (null_bug_bypass) 97*54766Sjohnh printf ("null_bypass: %s\n", descp->vdesc_name); 9854753Sjohnh 99*54766Sjohnh #ifdef SAFETY 10054753Sjohnh /* 101*54766Sjohnh * We require at least one vp. 10254753Sjohnh */ 103*54766Sjohnh if (descp->vdesc_vp_offsets==NULL || 104*54766Sjohnh descp->vdesc_vp_offsets[0]==VDESC_NO_OFFSET) 105*54766Sjohnh panic ("null_bypass: no vp's in map.\n"); 10654753Sjohnh #endif 10754753Sjohnh 10854753Sjohnh /* 109*54766Sjohnh * Map the vnodes going in. 110*54766Sjohnh * Later, we'll invoke the operation based on 111*54766Sjohnh * the first mapped vnode's operation vector. 11254753Sjohnh */ 113*54766Sjohnh maps = descp->vdesc_flags; 114*54766Sjohnh reles = descp->vdesc_rele_flags; 115*54766Sjohnh for (i=0; i<VDESC_MAX_VPS; maps>>=1, reles>>=1, i++) { 116*54766Sjohnh if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET) 117*54766Sjohnh break; /* bail out at end of list */ 118*54766Sjohnh if (maps & 1) /* skip vps that aren't to be mapped */ 119*54766Sjohnh continue; 120*54766Sjohnh vps_p[i] = this_vp_p = 121*54766Sjohnh VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap); 122*54766Sjohnh old_vps[i] = *this_vp_p; 123*54766Sjohnh *(vps_p[i]) = NULLTOLOWERVP(VTONULLNODE(*this_vp_p)); 124*54766Sjohnh if (reles & 1) 125*54766Sjohnh VREF(*this_vp_p); 126*54766Sjohnh 127*54766Sjohnh }; 12854753Sjohnh 12954753Sjohnh /* 130*54766Sjohnh * Call the operation on the lower layer 131*54766Sjohnh * with the modified argument structure. 13254753Sjohnh */ 133*54766Sjohnh error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap); 13454753Sjohnh 13554753Sjohnh /* 136*54766Sjohnh * Maintain the illusion of call-by-value 137*54766Sjohnh * by restoring vnodes in the argument structure 138*54766Sjohnh * to their original value. 13954753Sjohnh */ 140*54766Sjohnh maps = descp->vdesc_flags; 141*54766Sjohnh reles = descp->vdesc_rele_flags; 142*54766Sjohnh for (i=0; i<VDESC_MAX_VPS; maps>>=1, i++) { 143*54766Sjohnh if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET) 144*54766Sjohnh break; /* bail out at end of list */ 145*54766Sjohnh if (maps & 1) /* skip vps that aren't to be mapped */ 146*54766Sjohnh continue; 147*54766Sjohnh *(vps_p[i]) = old_vps[i]; 148*54766Sjohnh if (reles & 1) 149*54766Sjohnh vrele(*(vps_p[i])); 150*54766Sjohnh }; 151*54766Sjohnh 15254753Sjohnh /* 153*54766Sjohnh * Map the possible out-going vpp. 15454753Sjohnh */ 155*54766Sjohnh if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && 156*54766Sjohnh !(descp->vdesc_flags & VDESC_NOMAP_VPP) && 157*54766Sjohnh !error) { 158*54766Sjohnh vppp=VOPARG_OFFSETTO(struct vnode***, 159*54766Sjohnh descp->vdesc_vpp_offset,ap); 160*54766Sjohnh error = make_null_node(old_vps[0]->v_mount, **vppp, *vppp); 161*54766Sjohnh }; 16254753Sjohnh 163*54766Sjohnh return (error); 16454753Sjohnh } 16554753Sjohnh 16654753Sjohnh 16754753Sjohnh /* 168*54766Sjohnh * We handle getattr to change the fsid. 16954753Sjohnh */ 170*54766Sjohnh int 171*54766Sjohnh null_getattr(ap) 172*54766Sjohnh struct nvop_getattr_args *ap; 17354753Sjohnh { 17454753Sjohnh int error; 175*54766Sjohnh if (error=null_bypass(ap)) 176*54766Sjohnh return error; 177*54766Sjohnh /* Requires that arguments be restored. */ 178*54766Sjohnh ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 179*54766Sjohnh return 0; 180*54766Sjohnh } 18154753Sjohnh 18254753Sjohnh 183*54766Sjohnh #if 0 18454754Sjohnh null_rename (ap) 18554753Sjohnh struct vop_rename_args *ap; 18654753Sjohnh { 18754753Sjohnh USES_VOP_RENAME; 18854753Sjohnh struct vnode *fvp, *tvp; 18954753Sjohnh struct vnode *tdvp; 19054753Sjohnh #if 0 19154753Sjohnh struct vnode *fsvp, *tsvp; 19254753Sjohnh #endif 19354753Sjohnh int error; 19454753Sjohnh 19554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 19654754Sjohnh printf("null_rename(fdvp = %x->%x)\n", ap->a_fdvp, NULLTOLOWERVP(ap->a_fdvp)); 19754754Sjohnh /*printf("null_rename(tdvp = %x->%x)\n", tndp->ni_dvp, NULLTOLOWERVP(tndp->ni_dvp));*/ 19854753Sjohnh #endif 19954753Sjohnh 20054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 20154754Sjohnh printf("null_rename - switch source dvp\n"); 20254753Sjohnh #endif 20354753Sjohnh /* 20454753Sjohnh * Switch source directory to point to lofsed vnode 20554753Sjohnh */ 20654753Sjohnh PUSHREF(fdvp, ap->a_fdvp); 20754753Sjohnh VREF(ap->a_fdvp); 20854753Sjohnh 20954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 21054754Sjohnh printf("null_rename - switch source vp\n"); 21154753Sjohnh #endif 21254753Sjohnh /* 21354753Sjohnh * And source object if it is lofsed... 21454753Sjohnh */ 21554753Sjohnh fvp = ap->a_fvp; 21654754Sjohnh if (fvp && fvp->v_op == null_vnodeop_p) { 21754754Sjohnh ap->a_fvp = NULLTOLOWERVP(fvp); 21854753Sjohnh VREF(ap->a_fvp); 21954753Sjohnh } else { 22054753Sjohnh fvp = 0; 22154753Sjohnh } 22254753Sjohnh 22354753Sjohnh #if 0 22454754Sjohnh #ifdef NULLFS_DIAGNOSTIC 22554754Sjohnh printf("null_rename - switch source start vp\n"); 22654753Sjohnh #endif 22754753Sjohnh /* 22854753Sjohnh * And source startdir object if it is lofsed... 22954753Sjohnh */ 23054753Sjohnh fsvp = fndp->ni_startdir; 23154754Sjohnh if (fsvp && fsvp->v_op == null_vnodeop_p) { 23254754Sjohnh fndp->ni_startdir = NULLTOLOWERVP(fsvp); 23354753Sjohnh VREF(fndp->ni_startdir); 23454753Sjohnh } else { 23554753Sjohnh fsvp = 0; 23654753Sjohnh } 23754753Sjohnh #endif 23854753Sjohnh 23954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 24054754Sjohnh printf("null_rename - switch target dvp\n"); 24154753Sjohnh #endif 24254753Sjohnh /* 24354753Sjohnh * Switch target directory to point to lofsed vnode 24454753Sjohnh */ 24554753Sjohnh tdvp = ap->a_tdvp; 24654754Sjohnh if (tdvp && tdvp->v_op == null_vnodeop_p) { 24754754Sjohnh ap->a_tdvp = NULLTOLOWERVP(tdvp); 24854753Sjohnh VREF(ap->a_tdvp); 24954753Sjohnh } else { 25054753Sjohnh tdvp = 0; 25154753Sjohnh } 25254753Sjohnh 25354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 25454754Sjohnh printf("null_rename - switch target vp\n"); 25554753Sjohnh #endif 25654753Sjohnh /* 25754753Sjohnh * And target object if it is lofsed... 25854753Sjohnh */ 25954753Sjohnh tvp = ap->a_tvp; 26054754Sjohnh if (tvp && tvp->v_op == null_vnodeop_p) { 26154754Sjohnh ap->a_tvp = NULLTOLOWERVP(tvp); 26254753Sjohnh VREF(ap->a_tvp); 26354753Sjohnh } else { 26454753Sjohnh tvp = 0; 26554753Sjohnh } 26654753Sjohnh 26754753Sjohnh #if 0 26854754Sjohnh #ifdef NULLFS_DIAGNOSTIC 26954754Sjohnh printf("null_rename - switch target start vp\n"); 27054753Sjohnh #endif 27154753Sjohnh /* 27254753Sjohnh * And target startdir object if it is lofsed... 27354753Sjohnh */ 27454753Sjohnh tsvp = tndp->ni_startdir; 27554754Sjohnh if (tsvp && tsvp->v_op == null_vnodeop_p) { 27654754Sjohnh tndp->ni_startdir = NULLTOLOWERVP(fsvp); 27754753Sjohnh VREF(tndp->ni_startdir); 27854753Sjohnh } else { 27954753Sjohnh tsvp = 0; 28054753Sjohnh } 28154753Sjohnh #endif 28254753Sjohnh 28354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 28454754Sjohnh printf("null_rename - VOP_RENAME(%x, %x, %x, %x)\n", 28554753Sjohnh ap->a_fdvp, ap->a_fvp, ap->a_tdvp, ap->a_tvp); 28654753Sjohnh vprint("ap->a_fdvp", ap->a_fdvp); 28754753Sjohnh vprint("ap->a_fvp", ap->a_fvp); 28854753Sjohnh vprint("ap->a_tdvp", ap->a_tdvp); 28954753Sjohnh if (ap->a_tvp) vprint("ap->a_tvp", ap->a_tvp); 29054753Sjohnh DELAY(16000000); 29154753Sjohnh #endif 29254753Sjohnh 29354753Sjohnh error = VOP_RENAME(ap->a_fdvp, ap->a_fvp, ap->a_fcnp, ap->a_tdvp, ap->a_tvp, ap->a_tcnp); 29454753Sjohnh 29554753Sjohnh /* 29654753Sjohnh * Put everything back... 29754753Sjohnh */ 29854753Sjohnh 29954753Sjohnh #if 0 30054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 30154754Sjohnh printf("null_rename - restore target startdir\n"); 30254753Sjohnh #endif 30354753Sjohnh 30454753Sjohnh if (tsvp) { 30554753Sjohnh if (tndp->ni_startdir) 30654753Sjohnh vrele(tndp->ni_startdir); 30754753Sjohnh tndp->ni_startdir = tsvp; 30854753Sjohnh } 30954753Sjohnh #endif 31054753Sjohnh 31154754Sjohnh #ifdef NULLFS_DIAGNOSTIC 31254754Sjohnh printf("null_rename - restore target vp\n"); 31354753Sjohnh #endif 31454753Sjohnh 31554753Sjohnh if (tvp) { 31654753Sjohnh ap->a_tvp = tvp; 31754753Sjohnh vrele(ap->a_tvp); 31854753Sjohnh } 31954753Sjohnh 32054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 32154754Sjohnh printf("null_rename - restore target dvp\n"); 32254753Sjohnh #endif 32354753Sjohnh 32454753Sjohnh if (tdvp) { 32554753Sjohnh ap->a_tdvp = tdvp; 32654753Sjohnh vrele(ap->a_tdvp); 32754753Sjohnh } 32854753Sjohnh 32954753Sjohnh #if 0 33054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 33154754Sjohnh printf("null_rename - restore source startdir\n"); 33254753Sjohnh #endif 33354753Sjohnh 33454753Sjohnh if (fsvp) { 33554753Sjohnh if (fndp->ni_startdir) 33654753Sjohnh vrele(fndp->ni_startdir); 33754753Sjohnh fndp->ni_startdir = fsvp; 33854753Sjohnh } 33954753Sjohnh #endif 34054753Sjohnh 34154754Sjohnh #ifdef NULLFS_DIAGNOSTIC 34254754Sjohnh printf("null_rename - restore source vp\n"); 34354753Sjohnh #endif 34454753Sjohnh 34554753Sjohnh 34654753Sjohnh if (fvp) { 34754753Sjohnh ap->a_fvp = fvp; 34854753Sjohnh vrele(ap->a_fvp); 34954753Sjohnh } 35054753Sjohnh 35154754Sjohnh #ifdef NULLFS_DIAGNOSTIC 35254754Sjohnh printf("null_rename - restore source dvp\n"); 35354753Sjohnh #endif 35454753Sjohnh 35554753Sjohnh POP(fdvp, ap->a_fdvp); 35654753Sjohnh vrele(ap->a_fdvp); 35754753Sjohnh 35854753Sjohnh return (error); 35954753Sjohnh } 36054753Sjohnh #endif 36154753Sjohnh 36254753Sjohnh 363*54766Sjohnh int 36454754Sjohnh null_inactive (ap) 36554753Sjohnh struct vop_inactive_args *ap; 36654753Sjohnh { 36754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 368*54766Sjohnh printf("null_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp)); 36954753Sjohnh #endif 370*54766Sjohnh /* 371*54766Sjohnh * Do nothing (and _don't_ bypass). 372*54766Sjohnh * Wait to vrele lowervp until reclaim, 373*54766Sjohnh * so that until then our null_node is in the 374*54766Sjohnh * cache and reusable. 375*54766Sjohnh * 376*54766Sjohnh * NEEDSWORK: Someday, consider inactive'ing 377*54766Sjohnh * the lowervp and then trying to reactivate it 378*54766Sjohnh * like they do in the name lookup cache code. 379*54766Sjohnh * That's too much work for now. 380*54766Sjohnh */ 381*54766Sjohnh return 0; 38254753Sjohnh } 38354753Sjohnh 38454754Sjohnh null_reclaim (ap) 38554753Sjohnh struct vop_reclaim_args *ap; 38654753Sjohnh { 38754753Sjohnh USES_VOP_RECLAIM; 38854753Sjohnh struct vnode *targetvp; 38954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 39054754Sjohnh printf("null_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp)); 39154753Sjohnh #endif 392*54766Sjohnh remque(VTONULLNODE(ap->a_vp)); /* NEEDSWORK: What? */ 393*54766Sjohnh vrele (NULLTOLOWERVP(ap->a_vp)); /* release lower layer */ 39454753Sjohnh FREE(ap->a_vp->v_data, M_TEMP); 39554753Sjohnh ap->a_vp->v_data = 0; 39654753Sjohnh return (0); 39754753Sjohnh } 39854753Sjohnh 39954754Sjohnh null_bmap (ap) 40054753Sjohnh struct vop_bmap_args *ap; 40154753Sjohnh { 40254753Sjohnh USES_VOP_BMAP; 40354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 40454754Sjohnh printf("null_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, NULLTOLOWERVP(ap->a_vp)); 40554753Sjohnh #endif 40654753Sjohnh 40754754Sjohnh return VOP_BMAP(NULLTOLOWERVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp); 40854753Sjohnh } 40954753Sjohnh 41054754Sjohnh null_strategy (ap) 41154753Sjohnh struct vop_strategy_args *ap; 41254753Sjohnh { 41354753Sjohnh USES_VOP_STRATEGY; 41454753Sjohnh int error; 415*54766Sjohnh struct vnode *savedvp; 41654753Sjohnh 41754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 41854754Sjohnh printf("null_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, NULLTOLOWERVP(ap->a_bp->b_vp)); 41954753Sjohnh #endif 42054753Sjohnh 421*54766Sjohnh savedvp = ap->a_bp->b_vp; 42254753Sjohnh 42354753Sjohnh error = VOP_STRATEGY(ap->a_bp); 42454753Sjohnh 425*54766Sjohnh ap->a_bp->b_vp = savedvp; 42654753Sjohnh 427*54766Sjohnh return error; 42854753Sjohnh } 42954753Sjohnh 430*54766Sjohnh 431*54766Sjohnh int 43254754Sjohnh null_print (ap) 43354753Sjohnh struct vop_print_args *ap; 43454753Sjohnh { 435*54766Sjohnh register struct vnode *vp = ap->a_vp; 436*54766Sjohnh printf ("tag VT_NULLFS, vp=%x, lowervp=%x\n", vp, NULLTOLOWERVP(vp)); 437*54766Sjohnh return 0; 43854753Sjohnh } 43954753Sjohnh 44054753Sjohnh 44154753Sjohnh /* 442*54766Sjohnh * Global vfs data structures 44354753Sjohnh */ 44454753Sjohnh /* 445*54766Sjohnh * NEEDSWORK: strategy,bmap are hand coded currently. They should 446*54766Sjohnh * go away with a merged buffer/block cache. 447*54766Sjohnh * 44854753Sjohnh */ 449*54766Sjohnh int (**null_vnodeop_p)(); 450*54766Sjohnh struct vnodeopv_entry_desc lofs_vnodeop_entries[] = { 451*54766Sjohnh { &vop_default_desc, null_bypass }, 45254753Sjohnh 453*54766Sjohnh { &vop_getattr_desc, null_getattr }, 454*54766Sjohnh { &vop_inactive_desc, null_inactive }, 455*54766Sjohnh { &vop_reclaim_desc, null_reclaim }, 456*54766Sjohnh { &vop_print_desc, null_print }, 45754753Sjohnh 458*54766Sjohnh { &vop_bmap_desc, null_bmap }, 459*54766Sjohnh { &vop_strategy_desc, null_strategy }, 46054753Sjohnh 46154753Sjohnh { (struct vnodeop_desc*)NULL, (int(*)())NULL } 46254753Sjohnh }; 46354753Sjohnh struct vnodeopv_desc lofs_vnodeop_opv_desc = 46454754Sjohnh { &null_vnodeop_p, lofs_vnodeop_entries }; 465