date and time created 92/07/11 09:21:16 by heideman
authorJohn Heidemann <heideman@ucbvax.Berkeley.EDU>
Sun, 12 Jul 1992 00:21:16 +0000 (16:21 -0800)
committerJohn Heidemann <heideman@ucbvax.Berkeley.EDU>
Sun, 12 Jul 1992 00:21:16 +0000 (16:21 -0800)
SCCS-vsn: sys/miscfs/umapfs/umap_vnops.c 1.1

usr/src/sys/miscfs/umapfs/umap_vnops.c [new file with mode: 0644]

diff --git a/usr/src/sys/miscfs/umapfs/umap_vnops.c b/usr/src/sys/miscfs/umapfs/umap_vnops.c
new file mode 100644 (file)
index 0000000..f03b2d9
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 1992 The Regents of the University of California
+ * All rights reserved.
+ *
+ * This code is derived from the null layer of
+ * John Heidemann from the UCLA Ficus project and
+ * Jan-Simon Pendry's loopback file system.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)umap_vnops.c        1.1 (Berkeley) %G%
+ *
+ * Ancestors:
+ *     @(#)lofs_vnops.c        1.2 (Berkeley) 6/18/92
+ *     $Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
+ *     ...and...
+ *     @(#)umap_vnodeops.c 1.20 92/07/07 UCLA Ficus project
+ */
+
+/*
+ * Umap Layer
+ *
+ * The umap layer duplicates a portion of the file system
+ * name space under a new name.  In this respect, it is
+ * similar to the loopback file system.  It differs from
+ * the loopback fs in two respects:  it is implemented using
+ * a bypass operation, and it's "umap-node"s stack above
+ * all lower-layer vnodes, not just over directory vnodes.
+ *
+ * The umap layer is the minimum file system layer,
+ * simply bypassing all possible operations to the lower layer
+ * for processing there.  All but vop_getattr, _inactive, _reclaim,
+ * and _print are bypassed.
+ *
+ * Vop_getattr is not bypassed so that we can change the fsid being
+ * returned.  Vop_{inactive,reclaim} are bypassed so that
+ * they can handle freeing umap-layer specific data.
+ * Vop_print is not bypassed for debugging.
+ *
+ *
+ * INVOKING OPERATIONS ON LOWER LAYERS
+ *
+ * NEEDSWORK: Describe methods to invoke operations on the lower layer
+ * (bypass vs. VOP).
+ *
+ *
+ * CREATING NEW FILESYSTEM LAYERS
+ *
+ * One of the easiest ways to construct new file system layers is to make
+ * a copy of the umap layer, rename all files and variables, and
+ * then begin modifing the copy.  Sed can be used to easily rename
+ * all variables.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/user.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <umapfs/umap.h>
+
+
+int umap_bug_bypass = 0;   /* for debugging: enables bypass printf'ing */
+
+/*
+ * This is the 10-Apr-92 bypass routine.
+ *    This version has been optimized for speed, throwing away some
+ * safety checks.  It should still always work, but it's not as
+ * robust to programmer errors.
+ *    Define SAFETY to include some error checking code.
+ *
+ * In general, we map all vnodes going down and unmap them on the way back.
+ * As an exception to this, vnodes can be marked "unmapped" by setting
+ * the Nth bit in operation's vdesc_flags.
+ *
+ * Also, some BSD vnode operations have the side effect of vrele'ing
+ * their arguments.  With stacking, the reference counts are held
+ * by the upper node, not the lower one, so we must handle these
+ * side-effects here.  This is not of concern in Sun-derived systems
+ * since there are no such side-effects.
+ *
+ * This makes the following assumptions:
+ * - only one returned vpp
+ * - no INOUT vpp's (Sun's vop_open has one of these)
+ * - the vnode operation vector of the first vnode should be used
+ *   to determine what implementation of the op should be invoked
+ * - all mapped vnodes are of our vnode-type (NEEDSWORK:
+ *   problems on rmdir'ing mount points and renaming?)
+ */ 
+int
+umap_bypass(ap)
+       struct vop_generic_args *ap;
+{
+       extern int (**umap_vnodeop_p)();  /* not extern, really "forward" */
+       int *mapdata, nentries ;
+       int *gmapdata, gnentries ;
+       struct ucred **credpp,*credp, *savecredp, *saveucredp ;
+       register struct vnode **this_vp_p;
+       int error;
+       struct vnode *old_vps[VDESC_MAX_VPS];
+       struct vnode **vps_p[VDESC_MAX_VPS];
+       struct vnode ***vppp;
+       struct vnodeop_desc *descp = ap->a_desc;
+       int reles, i;
+
+       if (umap_bug_bypass)
+               printf ("umap_bypass: %s\n", descp->vdesc_name);
+
+#ifdef SAFETY
+       /*
+        * We require at least one vp.
+        */
+       if (descp->vdesc_vp_offsets==UMAP ||
+           descp->vdesc_vp_offsets[0]==VDESC_NO_OFFSET)
+               panic ("umap_bypass: no vp's in map.\n");
+#endif
+
+       /*
+        * Map the vnodes going in.
+        * Later, we'll invoke the operation based on
+        * the first mapped vnode's operation vector.
+        */
+       reles = descp->vdesc_flags;
+       for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) {
+               if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET)
+                       break;   /* bail out at end of list */
+               vps_p[i] = this_vp_p = 
+                       VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap);
+
+               if (i == 0)
+               {
+                       vp1 = *vps_p[0];
+               }
+
+               /*
+                * We're not guaranteed that any but the first vnode
+                * are of our type.  Check for and don't map any
+                * that aren't.
+                */
+
+               if ((*this_vp_p)->v_op != umap_vnodeop_p) {
+                       old_vps[i] = UMAP;
+               } else {
+                       old_vps[i] = *this_vp_p;
+                       *(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p);
+                       if (reles & 1)
+                               VREF(*this_vp_p);
+               };
+                       
+       };
+
+       /* Doctor the credentials.  (That's the purpose of this layer.) */
+
+       if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
+
+               credpp = VOPARG_OFFSETTO(struct ucred**, 
+                   descp->vdesc_cred_offset, ap);
+
+               /* Save old values */
+
+               savecredp = (*credpp);
+               saveucredp = u.u_cred;
+               (*credpp) = u.u_cred = crdup(savecredp);
+               credp = *credpp;
+
+               if (umap_bug_bypass && credp->cr_uid != 0 )
+                       printf("umap_bypass: user was %d, group %d\n", 
+                           credp->cr_uid,credp->cr_gid);
+
+               nentries =  MOUNTTOUMAPMOUNT(vp1->v_vfsp)->info_nentries;
+               mapdata =  &(MOUNTTOUMAPMOUNT(vp1->v_vfsp)->info_mapdata[0][0]);
+               gnentries =  MOUNTTOUMAPMOUNT(vp1->v_vfsp)->info_gnentries;
+               gmapdata =  &(MOUNTTOUMAPMOUNT(vp1->v_vfsp)->info_gmapdata[0][0]);
+
+               if (umap_bug_bypass && credp->cr_uid != 0 )
+                       printf("nentries = %d, gnentries = %d\n", nentries, 
+                           gnentries);
+
+               /* Map all ids in the credential structure. */
+
+               umap_mapids(credp,mapdata,nentries,gmapdata,gnentries);
+
+               if (umap_bug_bypass && credp->cr_uid != 0 )
+                       printf("umap_bypass: user now %d, group %d\n", 
+                           credp->cr_uid,credp->cr_gid);
+       }
+
+       /*
+        * Call the operation on the lower layer
+        * with the modified argument structure.
+        */
+       error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
+
+       /*
+        * Maintain the illusion of call-by-value
+        * by restoring vnodes in the argument structure
+        * to their original value.
+        */
+       reles = descp->vdesc_flags;
+       for (i=0; i<VDESC_MAX_VPS; reles>>=1, i++) {
+               if (descp->vdesc_vp_offsets[i]==VDESC_NO_OFFSET)
+                       break;   /* bail out at end of list */
+               if (old_vps[i]) {
+                       *(vps_p[i]) = old_vps[i];
+                       if (reles & 1)
+                               vrele(*(vps_p[i]));
+               };
+       };
+
+       /*
+        * Map the possible out-going vpp
+        * (Assumes that the lower layer always returns
+        * a VREF'ed vpp unless it gets an error.)
+        */
+       if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
+           !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
+           !error) {
+               /*
+                * XXX - even though symlink has a vpp arg,
+                * it doesn't return a VREF'ed vpp in that
+                * field.  The vpp arg should become a vp
+                * arg.
+                */
+               if (descp == VDESC(vop_symlink)) {
+#ifdef UMAPFS_DIAGNOSTIC
+                       printf("umap_bypass (symlink), lowervp->usecount = %d\n", (**vppp)->v_usecount);
+#endif
+                       return (error);
+               };
+               vppp=VOPARG_OFFSETTO(struct vnode***,
+                                descp->vdesc_vpp_offset,ap);
+               error = umap_node_create(old_vps[0]->v_mount, **vppp, *vppp);
+       };
+
+       /* 
+        * Free duplicate cred structure and restore old one.
+        */
+       if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
+               if (umap_bug_bypass && credp->cr_uid != 0 )
+               printf("umap_bypass: returning-user was %d\n", credp->cr_uid);
+
+               crfree(credp);
+               (*credpp) = savecredp;
+               u.u_cred = saveucredp;
+               if (umap_bug_bypass && (*credpp)->cr_uid != 0 )
+                       printf("umap_bypass: returning-user now %d\n\n", 
+                           (*credpp)->cr_uid);
+       }
+
+       return (error);
+}
+
+
+/*
+ *  We handle getattr to change the fsid.
+ */
+int
+umap_getattr(ap)
+       struct vop_getattr_args *ap;
+{
+       short uid, gid;
+       int error, tmpid, *mapdata, nentries, *gmapdata, gnentries;
+
+       if (error=umap_bypass(ap))
+               return error;
+       /* Requires that arguments be restored. */
+       ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
+
+       /* umap needs to map the uid and gid returned by a stat
+               into the proper values for this site.  This involves
+               finding the returned uid in the mapping information,
+               translating it into the uid on the other end,
+               and filling in the proper field in the vattr
+               structure pointed to by ap->a_vap.  The group
+               is easier, since currently all groups will be
+               translate to the NULLGROUP. */
+
+       /* Find entry in map */
+
+       uid = ap->a_vap->va_uid;
+       gid = ap->a_vap->va_gid;
+       if (umap_bug_bypass)
+               printf("umap_getattr: mapped uid = %d, mapped gid = %d\n",uid, 
+                   gid);
+
+       vp1p = VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[0],ap);
+       nentries =  MOUNTTOUMAPMOUNT((*vp1p)->v_vfsp)->info_nentries;
+       mapdata =  &(MOUNTTOUMAPMOUNT((*vp1p)->v_vfsp)->info_mapdata[0][0]);
+       gnentries =  MOUNTTOUMAPMOUNT((*vp1p)->v_vfsp)->info_gnentries;
+       gmapdata =  &(MOUNTTOUMAPMOUNT((*vp1p)->v_vfsp)->info_gmapdata[0][0]);
+
+       /* Reverse map the uid for the vnode.  Since it's a reverse
+               map, we can't use umap_mapids() to do it. */
+
+       tmpid = umap_reverse_findid(uid,mapdata,nentries);
+
+       if (tmpid != -1 ) {
+
+               ap->a_vap->va_uid = (uid_t)tmpid;
+               if (umap_bug_bypass)
+                       printf("umap_getattr: original uid = %d\n",uid);
+       } else 
+               ap->a_vap->va_uid = (uid_t)NOBODY;
+
+       /* Reverse map the gid for the vnode. */
+
+       tmpid = umap_reverse_findid(gid,gmapdata,gnentries);
+
+       if (tmpid != -1) {
+
+               ap->a_vap->va_gid = (gid_t)tmpid;
+               if (umap_bug_bypass)
+                       printf("umap_getattr: original gid = %d\n",gid);
+       } else
+               ap->a_vap->va_gid = (gid_t)NULLGROUP;
+       
+       return 0;
+}
+
+int
+umap_inactive (ap)
+       struct vop_inactive_args *ap;
+{
+#ifdef UMAPFS_DIAGNOSTIC
+       printf("umap_inactive(ap->a_vp = %x->%x)\n", ap->a_vp, UMAPVPTOLOWERVP(ap->a_vp));
+#endif
+       /*
+        * Do nothing (and _don't_ bypass).
+        * Wait to vrele lowervp until reclaim,
+        * so that until then our umap_node is in the
+        * cache and reusable.
+        *
+        * NEEDSWORK: Someday, consider inactive'ing
+        * the lowervp and then trying to reactivate it
+        * like they do in the name lookup cache code.
+        * That's too much work for now.
+        */
+       return 0;
+}
+
+int
+umap_reclaim (ap)
+       struct vop_reclaim_args *ap;
+{
+       struct vnode *targetvp;
+
+       /*
+        * Note: at this point, ap->a_vp->v_op == dead_vnodeop_p.
+        */
+#ifdef UMAPFS_DIAGNOSTIC
+       printf("umap_reclaim(ap->a_vp = %x->%x)\n", ap->a_vp, UMAPVPTOLOWERVP(ap->a_vp));
+#endif
+       remque(VTOUMAP(ap->a_vp));           /* NEEDSWORK: What? */
+       vrele (UMAPVPTOLOWERVP(ap->a_vp));   /* release lower layer */
+       FREE(ap->a_vp->v_data, M_TEMP);
+       ap->a_vp->v_data = 0;
+       return (0);
+}
+
+int
+umap_bmap (ap)
+       struct vop_bmap_args *ap;
+{
+#ifdef UMAPFS_DIAGNOSTIC
+       printf("umap_bmap(ap->a_vp = %x->%x)\n", ap->a_vp, UMAPVPTOLOWERVP(ap->a_vp));
+#endif
+
+       return VOP_BMAP(UMAPVPTOLOWERVP(ap->a_vp), ap->a_bn, ap->a_vpp, ap->a_bnp);
+}
+
+int
+umap_strategy (ap)
+       struct vop_strategy_args *ap;
+{
+       int error;
+       struct vnode *savedvp;
+
+#ifdef UMAPFS_DIAGNOSTIC
+       printf("umap_strategy(vp = %x->%x)\n", ap->a_bp->b_vp, UMAPVPTOLOWERVP(ap->a_bp->b_vp));
+#endif
+
+       savedvp = ap->a_bp->b_vp;
+
+       error = VOP_STRATEGY(ap->a_bp);
+
+       ap->a_bp->b_vp = savedvp;
+
+       return error;
+}
+
+
+int
+umap_print (ap)
+       struct vop_print_args *ap;
+{
+       register struct vnode *vp = ap->a_vp;
+       printf ("\ttag VT_UMAPFS, vp=%x, lowervp=%x\n", vp, UMAPVPTOLOWERVP(vp));
+       return 0;
+}
+
+
+/*
+ * Global vfs data structures
+ */
+/*
+ * NEEDSWORK: strategy,bmap are hand coded currently.  They should
+ * go away with a merged buffer/block cache.
+ *
+ */
+int (**umap_vnodeop_p)();
+struct vnodeopv_entry_desc umap_vnodeop_entries[] = {
+       { &vop_default_desc, umap_bypass },
+
+       { &vop_getattr_desc, umap_getattr },
+       { &vop_inactive_desc, umap_inactive },
+       { &vop_reclaim_desc, umap_reclaim },
+       { &vop_print_desc, umap_print },
+
+       { &vop_bmap_desc, umap_bmap },
+       { &vop_strategy_desc, umap_strategy },
+
+       { (struct vnodeop_desc*)UMAP, (int(*)())UMAP }
+};
+struct vnodeopv_desc umap_vnodeop_opv_desc =
+       { &umap_vnodeop_p, umap_vnodeop_entries };