1 /* 2 * Copyright (c) 1992 The Regents of the University of California 3 * All rights reserved. 4 * 5 * This code is derived from the null layer of 6 * John Heidemann from the UCLA Ficus project and 7 * Jan-Simon Pendry's loopback file system. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)null_vnops.c 1.4 (Berkeley) 07/10/92 12 * 13 * Ancestors: 14 * @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92 15 * $Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 16 * ...and... 17 * @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project 18 */ 19 20 /* 21 * Null Layer 22 * 23 * The null layer duplicates a portion of the file system 24 * name space under a new name. In this respect, it is 25 * similar to the loopback file system. It differs from 26 * the loopback fs in two respects: it is implemented using 27 * a bypass operation, and it's "null-node"s stack above 28 * all lower-layer vnodes, not just over directory vnodes. 29 * 30 * The null layer is the minimum file system layer, 31 * simply bypassing all possible operations to the lower layer 32 * for processing there. All but vop_getattr, _inactive, _reclaim, 33 * and _print are bypassed. 34 * 35 * Vop_getattr is not bypassed so that we can change the fsid being 36 * returned. Vop_{inactive,reclaim} are bypassed so that 37 * they can handle freeing null-layer specific data. 38 * Vop_print is not bypassed for debugging. 39 * 40 * 41 * INVOKING OPERATIONS ON LOWER LAYERS 42 * 43 * NEEDSWORK: Describe methods to invoke operations on the lower layer 44 * (bypass vs. VOP). 45 * 46 * 47 * CREATING NEW FILESYSTEM LAYERS 48 * 49 * One of the easiest ways to construct new file system layers is to make 50 * a copy of the null layer, rename all files and variables, and 51 * then begin modifing the copy. Sed can be used to easily rename 52 * all variables. 53 * 54 */ 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/proc.h> 59 #include <sys/time.h> 60 #include <sys/types.h> 61 #include <sys/vnode.h> 62 #include <sys/mount.h> 63 #include <sys/namei.h> 64 #include <sys/malloc.h> 65 #include <sys/buf.h> 66 #include <nullfs/null.h> 67 68 69 int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ 70 71 /* 72 * This is the 10-Apr-92 bypass routine. 73 * This version has been optimized for speed, throwing away some 74 * safety checks. It should still always work, but it's not as 75 * robust to programmer errors. 76 * Define SAFETY to include some error checking code. 77 * 78 * In general, we map all vnodes going down and unmap them on the way back. 79 * As an exception to this, vnodes can be marked "unmapped" by setting 80 * the Nth bit in operation's vdesc_flags. 81 * 82 * Also, some BSD vnode operations have the side effect of vrele'ing 83 * their arguments. With stacking, the reference counts are held 84 * by the upper node, not the lower one, so we must handle these 85 * side-effects here. This is not of concern in Sun-derived systems 86 * since there are no such side-effects. 87 * 88 * This makes the following assumptions: 89 * - only one returned vpp 90 * - no INOUT vpp's (Sun's vop_open has one of these) 91 * - the vnode operation vector of the first vnode should be used 92 * to determine what implementation of the op should be invoked 93 * - all mapped vnodes are of our vnode-type (NEEDSWORK: 94 * problems on rmdir'ing mount points and renaming?) 95 */ 96 int 97 null_bypass(ap) 98 struct vop_generic_args *ap; 99 { 100 extern int (**null_vnodeop_p)(); /* not extern, really "forward" */ 101 register struct vnode **this_vp_p; 102 int error; 103 struct vnode *old_vps[VDESC_MAX_VPS]; 104 struct vnode **vps_p[VDESC_MAX_VPS]; 105 struct vnode ***vppp; 106 struct vnodeop_desc *descp = ap->a_desc; 107 int reles, i; 108 109 if (null_bug_bypass) 110 printf ("null_bypass: %s\n", descp->vdesc_name); 111 112 #ifdef SAFETY 113 /* 114 * We require at least one vp. 115 */ 116 if (descp->vdesc_vp_offsets==NULL || 117 descp->vdesc_vp_offsets[0]==VDESC_NO_OFFSET) 118 panic ("null_bypass: no vp's in map.\n"); 119 #endif 120 121 /* 122 * Map the vnodes going in. 123 * Later, we'll invoke the operation based on 124 * the first mapped vnode's operation vector. 125 */ 126 reles = descp->vdesc_flags; 127 for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) { 128 if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET) 129 break; /* bail out at end of list */ 130 vps_p[i] = this_vp_p = 131 VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap); 132 /* 133 * We're not guaranteed that any but the first vnode 134 * are of our type. Check for and don't map any 135 * that aren't. 136 */ 137 if ((*this_vp_p)->v_op != null_vnodeop_p) { 138 old_vps[i] = NULL; 139 } else { 140 old_vps[i] = *this_vp_p; 141 *(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p); 142 if (reles & 1) 143 VREF(*this_vp_p); 144 }; 145 146 }; 147 148 /* 149 * Call the operation on the lower layer 150 * with the modified argument structure. 151 */ 152 error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap); 153 154 /* 155 * Maintain the illusion of call-by-value 156 * by restoring vnodes in the argument structure 157 * to their original value. 158 */ 159 reles = descp->vdesc_flags; 160 for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) { 161 if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET) 162 break; /* bail out at end of list */ 163 if (old_vps[i]) { 164 *(vps_p[i]) = old_vps[i]; 165 if (reles & 1) 166 vrele(*(vps_p[i])); 167 }; 168 }; 169 170 /* 171 * Map the possible out-going vpp. 172 */ 173 if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && 174 !(descp->vdesc_flags & VDESC_NOMAP_VPP) && 175 !error) { 176 vppp=VOPARG_OFFSETTO(struct vnode***, 177 descp->vdesc_vpp_offset,ap); 178 error = null_node_create(old_vps[0]->v_mount, **vppp, *vppp); 179 }; 180 181 return (error); 182 } 183 184 185 /* 186 * We handle getattr to change the fsid. 187 */ 188 int 189 null_getattr(ap) 190 struct vop_getattr_args *ap; 191 { 192 int error; 193 if (error=null_bypass(ap)) 194 return error; 195 /* Requires that arguments be restored. */ 196 ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 197 return 0; 198 } 199 200 201 int 202 null_inactive (ap) 203 struct vop_inactive_args *ap; 204 { 205 #ifdef NULLFS_DIAGNOSTIC 206 printf("null_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp)); 207 #endif 208 /* 209 * Do nothing (and _don't_ bypass). 210 * Wait to vrele lowervp until reclaim, 211 * so that until then our null_node is in the 212 * cache and reusable. 213 * 214 * NEEDSWORK: Someday, consider inactive'ing 215 * the lowervp and then trying to reactivate it 216 * like they do in the name lookup cache code. 217 * That's too much work for now. 218 */ 219 return 0; 220 } 221 222 null_reclaim (ap) 223 struct vop_reclaim_args *ap; 224 { 225 struct vnode *targetvp; 226 #ifdef NULLFS_DIAGNOSTIC 227 printf("null_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp)); 228 #endif 229 remque(VTONULL(ap->a_vp)); /* NEEDSWORK: What? */ 230 vrele (NULLVPTOLOWERVP(ap->a_vp)); /* release lower layer */ 231 FREE(ap->a_vp->v_data, M_TEMP); 232 ap->a_vp->v_data = 0; 233 return (0); 234 } 235 236 null_bmap (ap) 237 struct vop_bmap_args *ap; 238 { 239 #ifdef NULLFS_DIAGNOSTIC 240 printf("null_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, NULLVPTOLOWERVP(ap->a_vp)); 241 #endif 242 243 return VOP_BMAP(NULLVPTOLOWERVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp); 244 } 245 246 null_strategy (ap) 247 struct vop_strategy_args *ap; 248 { 249 int error; 250 struct vnode *savedvp; 251 252 #ifdef NULLFS_DIAGNOSTIC 253 printf("null_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, NULLVPTOLOWERVP(ap->a_bp->b_vp)); 254 #endif 255 256 savedvp = ap->a_bp->b_vp; 257 258 error = VOP_STRATEGY(ap->a_bp); 259 260 ap->a_bp->b_vp = savedvp; 261 262 return error; 263 } 264 265 266 int 267 null_print (ap) 268 struct vop_print_args *ap; 269 { 270 register struct vnode *vp = ap->a_vp; 271 printf ("tag VT_NULLFS, vp=%x, lowervp=%x\n", vp, NULLVPTOLOWERVP(vp)); 272 return 0; 273 } 274 275 276 /* 277 * Global vfs data structures 278 */ 279 /* 280 * NEEDSWORK: strategy,bmap are hand coded currently. They should 281 * go away with a merged buffer/block cache. 282 * 283 */ 284 int (**null_vnodeop_p)(); 285 struct vnodeopv_entry_desc null_vnodeop_entries[] = { 286 { &vop_default_desc, null_bypass }, 287 288 { &vop_getattr_desc, null_getattr }, 289 { &vop_inactive_desc, null_inactive }, 290 { &vop_reclaim_desc, null_reclaim }, 291 { &vop_print_desc, null_print }, 292 293 { &vop_bmap_desc, null_bmap }, 294 { &vop_strategy_desc, null_strategy }, 295 296 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 297 }; 298 struct vnodeopv_desc null_vnodeop_opv_desc = 299 { &null_vnodeop_p, null_vnodeop_entries }; 300