154753Sjohnh /* 263245Sbostic * Copyright (c) 1992, 1993 363245Sbostic * The Regents of the University of California. All rights reserved. 454753Sjohnh * 554951Sheideman * This code is derived from software contributed to Berkeley by 654951Sheideman * John Heidemann of the UCLA Ficus project. 754753Sjohnh * 854753Sjohnh * %sccs.include.redist.c% 954753Sjohnh * 10*69614Smckusick * @(#)null_vnops.c 8.5 (Berkeley) 05/22/95 1154766Sjohnh * 1254766Sjohnh * Ancestors: 1354753Sjohnh * @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92 1454766Sjohnh * $Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 1554766Sjohnh * ...and... 1654766Sjohnh * @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project 1754753Sjohnh */ 1854753Sjohnh 1954753Sjohnh /* 2054766Sjohnh * Null Layer 2154766Sjohnh * 2254951Sheideman * (See mount_null(8) for more information.) 2354951Sheideman * 2454766Sjohnh * The null layer duplicates a portion of the file system 2554766Sjohnh * name space under a new name. In this respect, it is 2654766Sjohnh * similar to the loopback file system. It differs from 2754766Sjohnh * the loopback fs in two respects: it is implemented using 2854951Sheideman * a stackable layers techniques, and it's "null-node"s stack above 2954766Sjohnh * all lower-layer vnodes, not just over directory vnodes. 3054766Sjohnh * 3154951Sheideman * The null layer has two purposes. First, it serves as a demonstration 3254951Sheideman * of layering by proving a layer which does nothing. (It actually 3354951Sheideman * does everything the loopback file system does, which is slightly 3454951Sheideman * more than nothing.) Second, the null layer can serve as a prototype 3554951Sheideman * layer. Since it provides all necessary layer framework, 3654951Sheideman * new file system layers can be created very easily be starting 3754951Sheideman * with a null layer. 3854951Sheideman * 3954951Sheideman * The remainder of this man page examines the null layer as a basis 4054951Sheideman * for constructing new layers. 4154951Sheideman * 4254951Sheideman * 4354951Sheideman * INSTANTIATING NEW NULL LAYERS 4454951Sheideman * 4554951Sheideman * New null layers are created with mount_null(8). 4654951Sheideman * Mount_null(8) takes two arguments, the pathname 4754951Sheideman * of the lower vfs (target-pn) and the pathname where the null 4854951Sheideman * layer will appear in the namespace (alias-pn). After 4954951Sheideman * the null layer is put into place, the contents 5054951Sheideman * of target-pn subtree will be aliased under alias-pn. 5154951Sheideman * 5254951Sheideman * 5354951Sheideman * OPERATION OF A NULL LAYER 5454951Sheideman * 5554766Sjohnh * The null layer is the minimum file system layer, 5654766Sjohnh * simply bypassing all possible operations to the lower layer 5754951Sheideman * for processing there. The majority of its activity centers 5854951Sheideman * on the bypass routine, though which nearly all vnode operations 5954951Sheideman * pass. 6054766Sjohnh * 6154951Sheideman * The bypass routine accepts arbitrary vnode operations for 6254951Sheideman * handling by the lower layer. It begins by examing vnode 6354951Sheideman * operation arguments and replacing any null-nodes by their 6454951Sheideman * lower-layer equivlants. It then invokes the operation 6554951Sheideman * on the lower layer. Finally, it replaces the null-nodes 6654951Sheideman * in the arguments and, if a vnode is return by the operation, 6754951Sheideman * stacks a null-node on top of the returned vnode. 6854951Sheideman * 69*69614Smckusick * Although bypass handles most operations, vop_getattr, vop_lock, 70*69614Smckusick * vop_unlock, vop_inactive, vop_reclaim, and vop_print are not 71*69614Smckusick * bypassed. Vop_getattr must change the fsid being returned. 72*69614Smckusick * Vop_lock and vop_unlock must handle any locking for the 73*69614Smckusick * current vnode as well as pass the lock request down. 7454951Sheideman * Vop_inactive and vop_reclaim are not bypassed so that 75*69614Smckusick * they can handle freeing null-layer specific data. Vop_print 76*69614Smckusick * is not bypassed to avoid excessive debugging information. 77*69614Smckusick * Also, certain vnode operations change the locking state within 78*69614Smckusick * the operation (create, mknod, remove, link, rename, mkdir, rmdir, 79*69614Smckusick * and symlink). Ideally these operations should not change the 80*69614Smckusick * lock state, but should be changed to let the caller of the 81*69614Smckusick * function unlock them. Otherwise all intermediate vnode layers 82*69614Smckusick * (such as union, umapfs, etc) must catch these functions to do 83*69614Smckusick * the necessary locking at their layer. 8454766Sjohnh * 8554893Sheideman * 8654951Sheideman * INSTANTIATING VNODE STACKS 8754893Sheideman * 8854951Sheideman * Mounting associates the null layer with a lower layer, 8954951Sheideman * effect stacking two VFSes. Vnode stacks are instead 9054951Sheideman * created on demand as files are accessed. 9154893Sheideman * 9254951Sheideman * The initial mount creates a single vnode stack for the 9354951Sheideman * root of the new null layer. All other vnode stacks 9454951Sheideman * are created as a result of vnode operations on 9554951Sheideman * this or other null vnode stacks. 9654893Sheideman * 9754951Sheideman * New vnode stacks come into existance as a result of 9854951Sheideman * an operation which returns a vnode. 9954951Sheideman * The bypass routine stacks a null-node above the new 10054951Sheideman * vnode before returning it to the caller. 10154893Sheideman * 10254951Sheideman * For example, imagine mounting a null layer with 10354951Sheideman * "mount_null /usr/include /dev/layer/null". 10455025Smckusick * Changing directory to /dev/layer/null will assign 10554951Sheideman * the root null-node (which was created when the null layer was mounted). 10654951Sheideman * Now consider opening "sys". A vop_lookup would be 10754951Sheideman * done on the root null-node. This operation would bypass through 10854951Sheideman * to the lower layer which would return a vnode representing 10954951Sheideman * the UFS "sys". Null_bypass then builds a null-node 11054951Sheideman * aliasing the UFS "sys" and returns this to the caller. 11154951Sheideman * Later operations on the null-node "sys" will repeat this 11254951Sheideman * process when constructing other vnode stacks. 11354951Sheideman * 11454951Sheideman * 11554951Sheideman * CREATING OTHER FILE SYSTEM LAYERS 11654951Sheideman * 11754893Sheideman * One of the easiest ways to construct new file system layers is to make 11854893Sheideman * a copy of the null layer, rename all files and variables, and 11954893Sheideman * then begin modifing the copy. Sed can be used to easily rename 12054893Sheideman * all variables. 12154893Sheideman * 12254951Sheideman * The umap layer is an example of a layer descended from the 12354951Sheideman * null layer. 12454951Sheideman * 12554951Sheideman * 12654951Sheideman * INVOKING OPERATIONS ON LOWER LAYERS 12754951Sheideman * 12854951Sheideman * There are two techniques to invoke operations on a lower layer 12954951Sheideman * when the operation cannot be completely bypassed. Each method 13054951Sheideman * is appropriate in different situations. In both cases, 13154951Sheideman * it is the responsibility of the aliasing layer to make 13254951Sheideman * the operation arguments "correct" for the lower layer 13354951Sheideman * by mapping an vnode arguments to the lower layer. 13454951Sheideman * 13554951Sheideman * The first approach is to call the aliasing layer's bypass routine. 13654951Sheideman * This method is most suitable when you wish to invoke the operation 13754951Sheideman * currently being hanldled on the lower layer. It has the advantage 13855025Smckusick * that the bypass routine already must do argument mapping. 13954951Sheideman * An example of this is null_getattrs in the null layer. 14054951Sheideman * 14154951Sheideman * A second approach is to directly invoked vnode operations on 14254951Sheideman * the lower layer with the VOP_OPERATIONNAME interface. 14354951Sheideman * The advantage of this method is that it is easy to invoke 14454951Sheideman * arbitrary operations on the lower layer. The disadvantage 14554951Sheideman * is that vnodes arguments must be manualy mapped. 14654951Sheideman * 14754753Sjohnh */ 14854753Sjohnh 14954753Sjohnh #include <sys/param.h> 15054753Sjohnh #include <sys/systm.h> 15154753Sjohnh #include <sys/proc.h> 15254753Sjohnh #include <sys/time.h> 15354753Sjohnh #include <sys/types.h> 15454753Sjohnh #include <sys/vnode.h> 15554753Sjohnh #include <sys/mount.h> 15654753Sjohnh #include <sys/namei.h> 15754753Sjohnh #include <sys/malloc.h> 15854753Sjohnh #include <sys/buf.h> 15955025Smckusick #include <miscfs/nullfs/null.h> 16054753Sjohnh 16154753Sjohnh 16254766Sjohnh int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */ 16354753Sjohnh 16454753Sjohnh /* 16554766Sjohnh * This is the 10-Apr-92 bypass routine. 16654766Sjohnh * This version has been optimized for speed, throwing away some 16754766Sjohnh * safety checks. It should still always work, but it's not as 16854766Sjohnh * robust to programmer errors. 16954766Sjohnh * Define SAFETY to include some error checking code. 17054766Sjohnh * 17154766Sjohnh * In general, we map all vnodes going down and unmap them on the way back. 17254766Sjohnh * As an exception to this, vnodes can be marked "unmapped" by setting 17354766Sjohnh * the Nth bit in operation's vdesc_flags. 17454766Sjohnh * 17554766Sjohnh * Also, some BSD vnode operations have the side effect of vrele'ing 17654766Sjohnh * their arguments. With stacking, the reference counts are held 17754766Sjohnh * by the upper node, not the lower one, so we must handle these 17854766Sjohnh * side-effects here. This is not of concern in Sun-derived systems 17954766Sjohnh * since there are no such side-effects. 18054766Sjohnh * 18154766Sjohnh * This makes the following assumptions: 18254766Sjohnh * - only one returned vpp 18354766Sjohnh * - no INOUT vpp's (Sun's vop_open has one of these) 18454766Sjohnh * - the vnode operation vector of the first vnode should be used 18554766Sjohnh * to determine what implementation of the op should be invoked 18654766Sjohnh * - all mapped vnodes are of our vnode-type (NEEDSWORK: 18754766Sjohnh * problems on rmdir'ing mount points and renaming?) 18854766Sjohnh */ 18954766Sjohnh int 19054766Sjohnh null_bypass(ap) 19155025Smckusick struct vop_generic_args /* { 19255025Smckusick struct vnodeop_desc *a_desc; 19355025Smckusick <other random data follows, presumably> 19455025Smckusick } */ *ap; 19554753Sjohnh { 19654893Sheideman extern int (**null_vnodeop_p)(); /* not extern, really "forward" */ 19754893Sheideman register struct vnode **this_vp_p; 19854753Sjohnh int error; 19954766Sjohnh struct vnode *old_vps[VDESC_MAX_VPS]; 20054766Sjohnh struct vnode **vps_p[VDESC_MAX_VPS]; 20154766Sjohnh struct vnode ***vppp; 20254766Sjohnh struct vnodeop_desc *descp = ap->a_desc; 20354893Sheideman int reles, i; 20454753Sjohnh 20554766Sjohnh if (null_bug_bypass) 20654766Sjohnh printf ("null_bypass: %s\n", descp->vdesc_name); 20754753Sjohnh 20854766Sjohnh #ifdef SAFETY 20954753Sjohnh /* 21054766Sjohnh * We require at least one vp. 21154753Sjohnh */ 21254938Sheideman if (descp->vdesc_vp_offsets == NULL || 21354938Sheideman descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET) 21454766Sjohnh panic ("null_bypass: no vp's in map.\n"); 21554753Sjohnh #endif 21654753Sjohnh 21754753Sjohnh /* 21854766Sjohnh * Map the vnodes going in. 21954766Sjohnh * Later, we'll invoke the operation based on 22054766Sjohnh * the first mapped vnode's operation vector. 22154753Sjohnh */ 22254893Sheideman reles = descp->vdesc_flags; 22354938Sheideman for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { 22454938Sheideman if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) 22554766Sjohnh break; /* bail out at end of list */ 22654766Sjohnh vps_p[i] = this_vp_p = 22754766Sjohnh VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap); 22854893Sheideman /* 22954893Sheideman * We're not guaranteed that any but the first vnode 23054893Sheideman * are of our type. Check for and don't map any 23154951Sheideman * that aren't. (We must always map first vp or vclean fails.) 23254893Sheideman */ 23368349Smckusick if (i && (*this_vp_p == NULL || 23468349Smckusick (*this_vp_p)->v_op != null_vnodeop_p)) { 23554893Sheideman old_vps[i] = NULL; 23654893Sheideman } else { 23754893Sheideman old_vps[i] = *this_vp_p; 23854893Sheideman *(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p); 23954938Sheideman /* 24054938Sheideman * XXX - Several operations have the side effect 24154938Sheideman * of vrele'ing their vp's. We must account for 24254938Sheideman * that. (This should go away in the future.) 24354938Sheideman */ 24454893Sheideman if (reles & 1) 24554893Sheideman VREF(*this_vp_p); 24654938Sheideman } 24754766Sjohnh 24854938Sheideman } 24954753Sjohnh 25054753Sjohnh /* 25154766Sjohnh * Call the operation on the lower layer 25254766Sjohnh * with the modified argument structure. 25354753Sjohnh */ 25454766Sjohnh error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap); 25554753Sjohnh 25654753Sjohnh /* 25754766Sjohnh * Maintain the illusion of call-by-value 25854766Sjohnh * by restoring vnodes in the argument structure 25954766Sjohnh * to their original value. 26054753Sjohnh */ 26154893Sheideman reles = descp->vdesc_flags; 26254938Sheideman for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) { 26354938Sheideman if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET) 26454766Sjohnh break; /* bail out at end of list */ 26554893Sheideman if (old_vps[i]) { 26654893Sheideman *(vps_p[i]) = old_vps[i]; 26754893Sheideman if (reles & 1) 26854893Sheideman vrele(*(vps_p[i])); 26954938Sheideman } 27054938Sheideman } 27154766Sjohnh 27254753Sjohnh /* 27354938Sheideman * Map the possible out-going vpp 27454938Sheideman * (Assumes that the lower layer always returns 27554938Sheideman * a VREF'ed vpp unless it gets an error.) 27654753Sjohnh */ 27754766Sjohnh if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET && 27854766Sjohnh !(descp->vdesc_flags & VDESC_NOMAP_VPP) && 27954766Sjohnh !error) { 28054938Sheideman /* 28154938Sheideman * XXX - even though some ops have vpp returned vp's, 28254938Sheideman * several ops actually vrele this before returning. 28354938Sheideman * We must avoid these ops. 28454951Sheideman * (This should go away when these ops are regularized.) 28554938Sheideman */ 28654951Sheideman if (descp->vdesc_flags & VDESC_VPP_WILLRELE) 28754951Sheideman goto out; 28854938Sheideman vppp = VOPARG_OFFSETTO(struct vnode***, 28954766Sjohnh descp->vdesc_vpp_offset,ap); 29054893Sheideman error = null_node_create(old_vps[0]->v_mount, **vppp, *vppp); 29154938Sheideman } 29254753Sjohnh 29354951Sheideman out: 29454766Sjohnh return (error); 29554753Sjohnh } 29654753Sjohnh 29754753Sjohnh /* 298*69614Smckusick * We have to carry on the locking protocol on the null layer vnodes 299*69614Smckusick * as we progress through the tree. 300*69614Smckusick */ 301*69614Smckusick null_lookup(ap) 302*69614Smckusick struct vop_lookup_args /* { 303*69614Smckusick struct vnode * a_dvp; 304*69614Smckusick struct vnode ** a_vpp; 305*69614Smckusick struct componentname * a_cnp; 306*69614Smckusick } */ *ap; 307*69614Smckusick { 308*69614Smckusick struct proc *p = ap->a_cnp->cn_proc; 309*69614Smckusick struct vop_lock_args lockargs; 310*69614Smckusick struct vop_unlock_args unlockargs; 311*69614Smckusick struct vnode *dvp, *vp; 312*69614Smckusick int error; 313*69614Smckusick 314*69614Smckusick error = null_bypass(ap); 315*69614Smckusick /* 316*69614Smckusick * We must do the same locking and unlocking at this layer as 317*69614Smckusick * is done in the layers below us. We could figure this out 318*69614Smckusick * based on the error return and the LASTCN, LOCKPARENT, and 319*69614Smckusick * LOCKLEAF flags. However, it is more expidient to just find 320*69614Smckusick * out the state of the lower level vnodes and set ours to the 321*69614Smckusick * same state. 322*69614Smckusick */ 323*69614Smckusick dvp = ap->a_dvp; 324*69614Smckusick vp = *ap->a_vpp; 325*69614Smckusick if (dvp == vp) 326*69614Smckusick return (error); 327*69614Smckusick if (!VOP_ISLOCKED(dvp)) { 328*69614Smckusick unlockargs.a_vp = dvp; 329*69614Smckusick unlockargs.a_flags = 0; 330*69614Smckusick unlockargs.a_p = p; 331*69614Smckusick vop_nounlock(&unlockargs); 332*69614Smckusick } 333*69614Smckusick if (vp != NULL && VOP_ISLOCKED(vp)) { 334*69614Smckusick lockargs.a_vp = vp; 335*69614Smckusick lockargs.a_flags = LK_SHARED; 336*69614Smckusick lockargs.a_p = p; 337*69614Smckusick vop_nolock(&lockargs); 338*69614Smckusick } 339*69614Smckusick return (error); 340*69614Smckusick } 341*69614Smckusick 342*69614Smckusick /* 34354951Sheideman * We handle getattr only to change the fsid. 34454753Sjohnh */ 34554766Sjohnh int 34654766Sjohnh null_getattr(ap) 34755025Smckusick struct vop_getattr_args /* { 34855025Smckusick struct vnode *a_vp; 34955025Smckusick struct vattr *a_vap; 35055025Smckusick struct ucred *a_cred; 35155025Smckusick struct proc *a_p; 35255025Smckusick } */ *ap; 35354753Sjohnh { 35454753Sjohnh int error; 355*69614Smckusick 35654938Sheideman if (error = null_bypass(ap)) 35755025Smckusick return (error); 35854766Sjohnh /* Requires that arguments be restored. */ 35954766Sjohnh ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0]; 36055025Smckusick return (0); 36154766Sjohnh } 36254753Sjohnh 36369437Smckusick /* 364*69614Smckusick * We need to process our own vnode lock and then clear the 365*69614Smckusick * interlock flag as it applies only to our vnode, not the 36669437Smckusick * vnodes below us on the stack. 36769437Smckusick */ 36869437Smckusick int 36969437Smckusick null_lock(ap) 370*69614Smckusick struct vop_lock_args /* { 371*69614Smckusick struct vnode *a_vp; 372*69614Smckusick int a_flags; 373*69614Smckusick struct proc *a_p; 374*69614Smckusick } */ *ap; 37569437Smckusick { 376*69614Smckusick 377*69614Smckusick vop_nolock(ap); 378*69614Smckusick if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN) 379*69614Smckusick return (0); 380*69614Smckusick ap->a_flags &= ~LK_INTERLOCK; 381*69614Smckusick return (null_bypass(ap)); 382*69614Smckusick } 383*69614Smckusick 384*69614Smckusick /* 385*69614Smckusick * We need to process our own vnode unlock and then clear the 386*69614Smckusick * interlock flag as it applies only to our vnode, not the 387*69614Smckusick * vnodes below us on the stack. 388*69614Smckusick */ 389*69614Smckusick int 390*69614Smckusick null_unlock(ap) 391*69614Smckusick struct vop_unlock_args /* { 392*69614Smckusick struct vnode *a_vp; 393*69614Smckusick int a_flags; 394*69614Smckusick struct proc *a_p; 395*69614Smckusick } */ *ap; 396*69614Smckusick { 39769437Smckusick struct vnode *vp = ap->a_vp; 39854753Sjohnh 399*69614Smckusick vop_nounlock(ap); 40069437Smckusick ap->a_flags &= ~LK_INTERLOCK; 401*69614Smckusick return (null_bypass(ap)); 40269437Smckusick } 40369437Smckusick 40454766Sjohnh int 40555025Smckusick null_inactive(ap) 40655025Smckusick struct vop_inactive_args /* { 40755025Smckusick struct vnode *a_vp; 408*69614Smckusick struct proc *a_p; 40955025Smckusick } */ *ap; 41054753Sjohnh { 41154766Sjohnh /* 41254766Sjohnh * Do nothing (and _don't_ bypass). 41354766Sjohnh * Wait to vrele lowervp until reclaim, 41454766Sjohnh * so that until then our null_node is in the 41554766Sjohnh * cache and reusable. 41654766Sjohnh * 41754766Sjohnh * NEEDSWORK: Someday, consider inactive'ing 41854766Sjohnh * the lowervp and then trying to reactivate it 41954951Sheideman * with capabilities (v_id) 42054766Sjohnh * like they do in the name lookup cache code. 42154766Sjohnh * That's too much work for now. 42254766Sjohnh */ 423*69614Smckusick VOP_UNLOCK(ap->a_vp, 0, ap->a_p); 42455025Smckusick return (0); 42554753Sjohnh } 42654753Sjohnh 42754938Sheideman int 42855025Smckusick null_reclaim(ap) 42955025Smckusick struct vop_reclaim_args /* { 43055025Smckusick struct vnode *a_vp; 43169437Smckusick struct proc *a_p; 43255025Smckusick } */ *ap; 43354753Sjohnh { 43454938Sheideman struct vnode *vp = ap->a_vp; 43554938Sheideman struct null_node *xp = VTONULL(vp); 43654938Sheideman struct vnode *lowervp = xp->null_lowervp; 43754938Sheideman 43854938Sheideman /* 43954951Sheideman * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p, 44054938Sheideman * so we can't call VOPs on ourself. 44154938Sheideman */ 44254938Sheideman /* After this assignment, this node will not be re-used. */ 44354938Sheideman xp->null_lowervp = NULL; 44467716Smckusick LIST_REMOVE(xp, null_hash); 44554938Sheideman FREE(vp->v_data, M_TEMP); 44654938Sheideman vp->v_data = NULL; 44754938Sheideman vrele (lowervp); 44855025Smckusick return (0); 44954753Sjohnh } 45054753Sjohnh 45154938Sheideman int 45255025Smckusick null_print(ap) 45355025Smckusick struct vop_print_args /* { 45455025Smckusick struct vnode *a_vp; 45555025Smckusick } */ *ap; 45654753Sjohnh { 45754951Sheideman register struct vnode *vp = ap->a_vp; 45854951Sheideman printf ("\ttag VT_NULLFS, vp=%x, lowervp=%x\n", vp, NULLVPTOLOWERVP(vp)); 45955025Smckusick return (0); 46054753Sjohnh } 46154753Sjohnh 46254951Sheideman /* 46354951Sheideman * XXX - vop_strategy must be hand coded because it has no 46454951Sheideman * vnode in its arguments. 46554951Sheideman * This goes away with a merged VM/buffer cache. 46654951Sheideman */ 46754938Sheideman int 46855025Smckusick null_strategy(ap) 46955025Smckusick struct vop_strategy_args /* { 47055025Smckusick struct buf *a_bp; 47155025Smckusick } */ *ap; 47254753Sjohnh { 47354951Sheideman struct buf *bp = ap->a_bp; 47454753Sjohnh int error; 47554766Sjohnh struct vnode *savedvp; 47654753Sjohnh 47754951Sheideman savedvp = bp->b_vp; 47854951Sheideman bp->b_vp = NULLVPTOLOWERVP(bp->b_vp); 47954753Sjohnh 48054951Sheideman error = VOP_STRATEGY(bp); 48154753Sjohnh 48254951Sheideman bp->b_vp = savedvp; 48354753Sjohnh 48455025Smckusick return (error); 48554753Sjohnh } 48654753Sjohnh 48754951Sheideman /* 48854951Sheideman * XXX - like vop_strategy, vop_bwrite must be hand coded because it has no 48954951Sheideman * vnode in its arguments. 49054951Sheideman * This goes away with a merged VM/buffer cache. 49154951Sheideman */ 49254766Sjohnh int 49355025Smckusick null_bwrite(ap) 49455025Smckusick struct vop_bwrite_args /* { 49555025Smckusick struct buf *a_bp; 49655025Smckusick } */ *ap; 49754753Sjohnh { 49854951Sheideman struct buf *bp = ap->a_bp; 49954951Sheideman int error; 50054951Sheideman struct vnode *savedvp; 50154753Sjohnh 50254951Sheideman savedvp = bp->b_vp; 50354951Sheideman bp->b_vp = NULLVPTOLOWERVP(bp->b_vp); 50454753Sjohnh 50554951Sheideman error = VOP_BWRITE(bp); 50654951Sheideman 50754951Sheideman bp->b_vp = savedvp; 50854951Sheideman 50955025Smckusick return (error); 51054944Sheideman } 51154944Sheideman 51254753Sjohnh /* 51354766Sjohnh * Global vfs data structures 51454753Sjohnh */ 51554766Sjohnh int (**null_vnodeop_p)(); 51654893Sheideman struct vnodeopv_entry_desc null_vnodeop_entries[] = { 51754766Sjohnh { &vop_default_desc, null_bypass }, 51854753Sjohnh 519*69614Smckusick { &vop_lookup_desc, null_lookup }, 52054766Sjohnh { &vop_getattr_desc, null_getattr }, 52169437Smckusick { &vop_lock_desc, null_lock }, 522*69614Smckusick { &vop_unlock_desc, null_unlock }, 52354766Sjohnh { &vop_inactive_desc, null_inactive }, 52454766Sjohnh { &vop_reclaim_desc, null_reclaim }, 52554766Sjohnh { &vop_print_desc, null_print }, 52654753Sjohnh 52754766Sjohnh { &vop_strategy_desc, null_strategy }, 52854951Sheideman { &vop_bwrite_desc, null_bwrite }, 52954753Sjohnh 53054753Sjohnh { (struct vnodeop_desc*)NULL, (int(*)())NULL } 53154753Sjohnh }; 53254893Sheideman struct vnodeopv_desc null_vnodeop_opv_desc = 53354893Sheideman { &null_vnodeop_p, null_vnodeop_entries }; 534