The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/umapfs/umap_vnops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1992, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software donated to Berkeley by
    6  * the UCLA Ficus project.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)umap_vnops.c        8.6 (Berkeley) 5/22/95
   33  * $FreeBSD: releng/6.4/sys/fs/umapfs/umap_vnops.c 143513 2005-03-13 12:18:25Z jeff $
   34  */
   35 
   36 /*
   37  * Umap Layer
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/lock.h>
   44 #include <sys/malloc.h>
   45 #include <sys/mount.h>
   46 #include <sys/namei.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/vnode.h>
   49 
   50 #include <fs/umapfs/umap.h>
   51 #include <fs/nullfs/null.h>
   52 
   53 static int umap_bug_bypass = 0;   /* for debugging: enables bypass printf'ing */
   54 SYSCTL_INT(_debug, OID_AUTO, umapfs_bug_bypass, CTLFLAG_RW,
   55         &umap_bug_bypass, 0, "");
   56 
   57 static vop_generic_t    umap_bypass;
   58 static vop_getattr_t    umap_getattr;
   59 static vop_inactive_t   umap_inactive;
   60 static vop_lock_t       umap_lock;
   61 static vop_print_t      umap_print;
   62 static vop_reclaim_t    umap_reclaim;
   63 static vop_rename_t     umap_rename;
   64 static vop_unlock_t     umap_unlock;
   65 
   66 /*
   67  * This is the 10-Apr-92 bypass routine.
   68  * See null_vnops.c:null_bypass for more details.
   69  */
   70 static int
   71 umap_bypass(ap)
   72         struct vop_generic_args /* {
   73                 struct vnodeop_desc *a_desc;
   74                 <other random data follows, presumably>
   75         } */ *ap;
   76 {
   77         struct ucred **credpp = 0, *credp = 0;
   78         struct ucred *savecredp = 0, *savecompcredp = 0;
   79         struct ucred *compcredp = 0;
   80         struct vnode **this_vp_p;
   81         int error;
   82         struct vnode *old_vps[VDESC_MAX_VPS];
   83         struct vnode *vp1 = 0;
   84         struct vnode **vps_p[VDESC_MAX_VPS];
   85         struct vnode ***vppp;
   86         struct vnodeop_desc *descp = ap->a_desc;
   87         int reles, i;
   88         struct componentname **compnamepp = 0;
   89 
   90         if (umap_bug_bypass)
   91                 printf ("umap_bypass: %s\n", descp->vdesc_name);
   92 
   93 #ifdef DIAGNOSTIC
   94         /*
   95          * We require at least one vp.
   96          */
   97         if (descp->vdesc_vp_offsets == NULL ||
   98             descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
   99                 panic ("umap_bypass: no vp's in map");
  100 #endif
  101 
  102         /*
  103          * Map the vnodes going in.
  104          * Later, we'll invoke the operation based on
  105          * the first mapped vnode's operation vector.
  106          */
  107         reles = descp->vdesc_flags;
  108         for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
  109                 if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
  110                         break;   /* bail out at end of list */
  111                 vps_p[i] = this_vp_p =
  112                         VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[i], ap);
  113 
  114                 if (i == 0) {
  115                         vp1 = *vps_p[0];
  116                 }
  117 
  118                 /*
  119                  * We're not guaranteed that any but the first vnode
  120                  * are of our type.  Check for and don't map any
  121                  * that aren't.  (Must map first vp or vclean fails.)
  122                  */
  123 
  124                 if (i && (*this_vp_p)->v_op != umap_vnodeop_p) {
  125                         old_vps[i] = NULL;
  126                 } else {
  127                         old_vps[i] = *this_vp_p;
  128                         *(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p);
  129                         if (reles & 1)
  130                                 VREF(*this_vp_p);
  131                 }
  132 
  133         }
  134 
  135         /*
  136          * Fix the credentials.  (That's the purpose of this layer.)
  137          */
  138 
  139         if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
  140 
  141                 credpp = VOPARG_OFFSETTO(struct ucred**,
  142                     descp->vdesc_cred_offset, ap);
  143 
  144                 /* Save old values */
  145 
  146                 savecredp = (*credpp);
  147                 if (savecredp != NOCRED)
  148                         (*credpp) = crdup(savecredp);
  149                 credp = *credpp;
  150 
  151                 if (umap_bug_bypass && credp->cr_uid != 0)
  152                         printf("umap_bypass: user was %lu, group %lu\n",
  153                             (u_long)credp->cr_uid, (u_long)credp->cr_gid);
  154 
  155                 /* Map all ids in the credential structure. */
  156 
  157                 umap_mapids(vp1->v_mount, credp);
  158 
  159                 if (umap_bug_bypass && credp->cr_uid != 0)
  160                         printf("umap_bypass: user now %lu, group %lu\n",
  161                             (u_long)credp->cr_uid, (u_long)credp->cr_gid);
  162         }
  163 
  164         /* BSD often keeps a credential in the componentname structure
  165          * for speed.  If there is one, it better get mapped, too.
  166          */
  167 
  168         if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) {
  169 
  170                 compnamepp = VOPARG_OFFSETTO(struct componentname**,
  171                     descp->vdesc_componentname_offset, ap);
  172 
  173                 compcredp = (*compnamepp)->cn_cred;
  174                 savecompcredp = compcredp;
  175                 if (savecompcredp != NOCRED)
  176                         (*compnamepp)->cn_cred = crdup(savecompcredp);
  177                 compcredp = (*compnamepp)->cn_cred;
  178 
  179                 if (umap_bug_bypass && compcredp->cr_uid != 0)
  180                         printf(
  181                     "umap_bypass: component credit user was %lu, group %lu\n",
  182                             (u_long)compcredp->cr_uid,
  183                             (u_long)compcredp->cr_gid);
  184 
  185                 /* Map all ids in the credential structure. */
  186 
  187                 umap_mapids(vp1->v_mount, compcredp);
  188 
  189                 if (umap_bug_bypass && compcredp->cr_uid != 0)
  190                         printf(
  191                     "umap_bypass: component credit user now %lu, group %lu\n",
  192                             (u_long)compcredp->cr_uid,
  193                             (u_long)compcredp->cr_gid);
  194         }
  195 
  196         /*
  197          * Call the operation on the lower layer
  198          * with the modified argument structure.
  199          */
  200         error = VCALL(ap);
  201 
  202         /*
  203          * Maintain the illusion of call-by-value
  204          * by restoring vnodes in the argument structure
  205          * to their original value.
  206          */
  207         reles = descp->vdesc_flags;
  208         for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
  209                 if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
  210                         break;   /* bail out at end of list */
  211                 if (old_vps[i]) {
  212                         *(vps_p[i]) = old_vps[i];
  213                         if (reles & 1)
  214                                 vrele(*(vps_p[i]));
  215                 };
  216         };
  217 
  218         /*
  219          * Map the possible out-going vpp
  220          * (Assumes that the lower layer always returns
  221          * a VREF'ed vpp unless it gets an error.)
  222          */
  223         if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
  224             !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
  225             !error) {
  226                 if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
  227                         goto out;
  228                 vppp = VOPARG_OFFSETTO(struct vnode***,
  229                                  descp->vdesc_vpp_offset, ap);
  230                 if (*vppp)
  231                         error = umap_node_create(old_vps[0]->v_mount, **vppp, *vppp);
  232         };
  233 
  234  out:
  235         /*
  236          * Free duplicate cred structure and restore old one.
  237          */
  238         if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
  239                 if (umap_bug_bypass && credp && credp->cr_uid != 0)
  240                         printf("umap_bypass: returning-user was %lu\n",
  241                             (u_long)credp->cr_uid);
  242 
  243                 if (savecredp != NOCRED) {
  244                         crfree(credp);
  245                         (*credpp) = savecredp;
  246                         if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0)
  247                                 printf(
  248                                     "umap_bypass: returning-user now %lu\n\n",
  249                                     (u_long)(*credpp)->cr_uid);
  250                 }
  251         }
  252 
  253         if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) {
  254                 if (umap_bug_bypass && compcredp && compcredp->cr_uid != 0)
  255                         printf(
  256                             "umap_bypass: returning-component-user was %lu\n",
  257                             (u_long)compcredp->cr_uid);
  258 
  259                 if (savecompcredp != NOCRED) {
  260                         crfree(compcredp);
  261                         (*compnamepp)->cn_cred = savecompcredp;
  262                         if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0)
  263                                 printf(
  264                             "umap_bypass: returning-component-user now %lu\n",
  265                                     (u_long)compcredp->cr_uid);
  266                 }
  267         }
  268 
  269         return (error);
  270 }
  271 
  272 
  273 /*
  274  *  We handle getattr to change the fsid.
  275  */
  276 static int
  277 umap_getattr(ap)
  278         struct vop_getattr_args /* {
  279                 struct vnode *a_vp;
  280                 struct vattr *a_vap;
  281                 struct ucred *a_cred;
  282                 struct thread *a_td;
  283         } */ *ap;
  284 {
  285         short uid, gid;
  286         int error, tmpid, nentries, gnentries;
  287         u_long (*mapdata)[2], (*gmapdata)[2];
  288         struct vnode **vp1p;
  289         struct vnodeop_desc *descp = ap->a_desc;
  290 
  291         error = umap_bypass((struct vop_generic_args *)ap);
  292         if (error)
  293                 return (error);
  294 
  295         /*
  296          * Umap needs to map the uid and gid returned by a stat
  297          * into the proper values for this site.  This involves
  298          * finding the returned uid in the mapping information,
  299          * translating it into the uid on the other end,
  300          * and filling in the proper field in the vattr
  301          * structure pointed to by ap->a_vap.  The group
  302          * is easier, since currently all groups will be
  303          * translate to the NULLGROUP.
  304          */
  305 
  306         /* Find entry in map */
  307 
  308         uid = ap->a_vap->va_uid;
  309         gid = ap->a_vap->va_gid;
  310         if (umap_bug_bypass)
  311                 printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid,
  312                     gid);
  313 
  314         vp1p = VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[0], ap);
  315         nentries =  MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_nentries;
  316         mapdata =  (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_mapdata);
  317         gnentries =  MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gnentries;
  318         gmapdata =  (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata);
  319 
  320         /* Reverse map the uid for the vnode.  Since it's a reverse
  321                 map, we can't use umap_mapids() to do it. */
  322 
  323         tmpid = umap_reverse_findid(uid, mapdata, nentries);
  324 
  325         if (tmpid != -1) {
  326 
  327                 ap->a_vap->va_uid = (uid_t) tmpid;
  328                 if (umap_bug_bypass)
  329                         printf("umap_getattr: original uid = %d\n", uid);
  330         } else
  331                 ap->a_vap->va_uid = (uid_t) NOBODY;
  332 
  333         /* Reverse map the gid for the vnode. */
  334 
  335         tmpid = umap_reverse_findid(gid, gmapdata, gnentries);
  336 
  337         if (tmpid != -1) {
  338 
  339                 ap->a_vap->va_gid = (gid_t) tmpid;
  340                 if (umap_bug_bypass)
  341                         printf("umap_getattr: original gid = %d\n", gid);
  342         } else
  343                 ap->a_vap->va_gid = (gid_t) NULLGROUP;
  344 
  345         return (0);
  346 }
  347 
  348 /*
  349  * We need to process our own vnode lock and then clear the
  350  * interlock flag as it applies only to our vnode, not the
  351  * vnodes below us on the stack.
  352  */
  353 static int
  354 umap_lock(ap)
  355         struct vop_lock_args /* {
  356                 struct vnode *a_vp;
  357                 int a_flags;
  358                 struct thread *a_td;
  359         } */ *ap;
  360 {
  361 
  362         /*
  363          * vop_nolock no longer exists.  I could have pasted the code
  364          * in so that it compiles, but that would be doing our users a
  365          * great disservice.  umapfs is about 5 years behind the nullfs
  366          * code that it is derived from.  The stub locking here guarantees
  367          * a deadlock the moment a VOP_INACTIVE arrives.  There is no point
  368          * pasting the code that makes it compile either, because that just
  369          * makes it Even More Wrong.
  370          */
  371         vop_nolock(ap);
  372         if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN)
  373                 return (0);
  374         ap->a_flags &= ~LK_INTERLOCK;
  375         return (null_bypass((struct vop_generic_args *)ap));
  376 }
  377 
  378 /*
  379  * We need to process our own vnode unlock and then clear the
  380  * interlock flag as it applies only to our vnode, not the
  381  * vnodes below us on the stack.
  382  */
  383 static int
  384 umap_unlock(ap)
  385         struct vop_unlock_args /* {
  386                 struct vnode *a_vp;
  387                 int a_flags;
  388                 struct thread *a_td;
  389         } */ *ap;
  390 {
  391         vop_nounlock(ap);
  392         ap->a_flags &= ~LK_INTERLOCK;
  393         return (null_bypass((struct vop_generic_args *)ap));
  394 }
  395 
  396 static int
  397 umap_inactive(ap)
  398         struct vop_inactive_args /* {
  399                 struct vnode *a_vp;
  400                 struct thread *a_td;
  401         } */ *ap;
  402 {
  403         struct vnode *vp = ap->a_vp;
  404         struct umap_node *xp = VTOUMAP(vp);
  405         struct vnode *lowervp = xp->umap_lowervp;
  406         /*
  407          * Do nothing (and _don't_ bypass).
  408          * Wait to vrele lowervp until reclaim,
  409          * so that until then our umap_node is in the
  410          * cache and reusable.
  411          *
  412          */
  413         VOP_INACTIVE(lowervp, ap->a_td);
  414         return (0);
  415 }
  416 
  417 static int
  418 umap_reclaim(ap)
  419         struct vop_reclaim_args /* {
  420                 struct vnode *a_vp;
  421         } */ *ap;
  422 {
  423         struct vnode *vp = ap->a_vp;
  424         struct umap_node *xp = VTOUMAP(vp);
  425         struct vnode *lowervp = xp->umap_lowervp;
  426 
  427         /* After this assignment, this node will not be re-used. */
  428         xp->umap_lowervp = NULL;
  429         LIST_REMOVE(xp, umap_hash);
  430         FREE(vp->v_data, M_TEMP);
  431         vp->v_data = NULL;
  432         vp->v_object = NULL;
  433         vrele(lowervp);
  434         return (0);
  435 }
  436 
  437 static int
  438 umap_print(ap)
  439         struct vop_print_args /* {
  440                 struct vnode *a_vp;
  441         } */ *ap;
  442 {
  443         struct vnode *vp = ap->a_vp;
  444         printf("\tvp=%p, lowervp=%p\n", vp, UMAPVPTOLOWERVP(vp));
  445         return (0);
  446 }
  447 
  448 static int
  449 umap_rename(ap)
  450         struct vop_rename_args  /* {
  451                 struct vnode *a_fdvp;
  452                 struct vnode *a_fvp;
  453                 struct componentname *a_fcnp;
  454                 struct vnode *a_tdvp;
  455                 struct vnode *a_tvp;
  456                 struct componentname *a_tcnp;
  457         } */ *ap;
  458 {
  459         int error;
  460         struct componentname *compnamep;
  461         struct ucred *compcredp, *savecompcredp;
  462         struct vnode *vp;
  463 
  464         /*
  465          * Rename is irregular, having two componentname structures.
  466          * We need to map the cre in the second structure,
  467          * and then bypass takes care of the rest.
  468          */
  469 
  470         vp = ap->a_fdvp;
  471         compnamep = ap->a_tcnp;
  472         compcredp = compnamep->cn_cred;
  473 
  474         savecompcredp = compcredp;
  475         compcredp = compnamep->cn_cred = crdup(savecompcredp);
  476 
  477         if (umap_bug_bypass && compcredp->cr_uid != 0)
  478                 printf(
  479             "umap_rename: rename component credit user was %lu, group %lu\n",
  480                     (u_long)compcredp->cr_uid, (u_long)compcredp->cr_gid);
  481 
  482         /* Map all ids in the credential structure. */
  483 
  484         umap_mapids(vp->v_mount, compcredp);
  485 
  486         if (umap_bug_bypass && compcredp->cr_uid != 0)
  487                 printf(
  488             "umap_rename: rename component credit user now %lu, group %lu\n",
  489                     (u_long)compcredp->cr_uid, (u_long)compcredp->cr_gid);
  490 
  491         error = umap_bypass((struct vop_generic_args *)ap);
  492 
  493         /* Restore the additional mapped componentname cred structure. */
  494 
  495         crfree(compcredp);
  496         compnamep->cn_cred = savecompcredp;
  497 
  498         return error;
  499 }
  500 
  501 /*
  502  * Global vfs data structures
  503  */
  504 /*
  505  * XXX - strategy, bwrite are hand coded currently.  They should
  506  * go away with a merged buffer/block cache.
  507  *
  508  */
  509 static struct vop_vector umap_vnodeops = {
  510         .vop_default =          umap_bypass,
  511 
  512         .vop_getattr =          umap_getattr,
  513         .vop_inactive =         umap_inactive,
  514         .vop_lock =             umap_lock,
  515         .vop_print =            umap_print,
  516         .vop_reclaim =          umap_reclaim,
  517         .vop_rename =           umap_rename,
  518         .vop_unlock =           umap_unlock,
  519 };

Cache object: 3cf17ae81186524283193a0df5c10bb9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.