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/coda/coda_subr.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  * 
    3  *             Coda: an Experimental Distributed File System
    4  *                              Release 3.1
    5  * 
    6  *           Copyright (c) 1987-1998 Carnegie Mellon University
    7  *                          All Rights Reserved
    8  * 
    9  * Permission  to  use, copy, modify and distribute this software and its
   10  * documentation is hereby granted,  provided  that  both  the  copyright
   11  * notice  and  this  permission  notice  appear  in  all  copies  of the
   12  * software, derivative works or  modified  versions,  and  any  portions
   13  * thereof, and that both notices appear in supporting documentation, and
   14  * that credit is given to Carnegie Mellon University  in  all  documents
   15  * and publicity pertaining to direct or indirect use of this code or its
   16  * derivatives.
   17  * 
   18  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
   19  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
   20  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
   21  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
   22  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
   23  * ANY DERIVATIVE WORK.
   24  * 
   25  * Carnegie  Mellon  encourages  users  of  this  software  to return any
   26  * improvements or extensions that  they  make,  and  to  grant  Carnegie
   27  * Mellon the rights to redistribute these changes without encumbrance.
   28  * 
   29  *      @(#) src/sys/coda/coda_subr.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
   30  * $FreeBSD: releng/5.0/sys/coda/coda_subr.c 103937 2002-09-25 02:33:29Z jeff $
   31  * 
   32   */
   33 
   34 /* 
   35  * Mach Operating System
   36  * Copyright (c) 1989 Carnegie-Mellon University
   37  * All rights reserved.  The CMU software License Agreement specifies
   38  * the terms and conditions for use and redistribution.
   39  */
   40 
   41 /*
   42  * This code was written for the Coda filesystem at Carnegie Mellon
   43  * University.  Contributers include David Steere, James Kistler, and
   44  * M. Satyanarayanan.
   45  */
   46 
   47 /* NOTES: rvb
   48  * 1.   Added coda_unmounting to mark all cnodes as being UNMOUNTING.  This has to
   49  *       be done before dounmount is called.  Because some of the routines that
   50  *       dounmount calls before coda_unmounted might try to force flushes to venus.
   51  *       The vnode pager does this.
   52  * 2.   coda_unmounting marks all cnodes scanning coda_cache.
   53  * 3.   cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes
   54  *       under the /coda mount point.
   55  * 4.   coda_cacheprint (under DEBUG) prints names with vnode/cnode address
   56  */
   57 
   58 #include <vcoda.h>
   59 
   60 #include <sys/param.h>
   61 #include <sys/systm.h>
   62 #include <sys/lock.h>
   63 #include <sys/malloc.h>
   64 #include <sys/mount.h>
   65 
   66 #include <coda/coda.h>
   67 #include <coda/cnode.h>
   68 #include <coda/coda_subr.h>
   69 #include <coda/coda_namecache.h>
   70 
   71 int coda_active = 0;
   72 int coda_reuse = 0;
   73 int coda_new = 0;
   74 
   75 struct cnode *coda_freelist = NULL;
   76 struct cnode *coda_cache[CODA_CACHESIZE];
   77 
   78 #define coda_hash(fid) (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1))
   79 #define CNODE_NEXT(cp)  ((cp)->c_next)
   80 #define ODD(vnode)        ((vnode) & 0x1)
   81 
   82 /*
   83  * Allocate a cnode.
   84  */
   85 struct cnode *
   86 coda_alloc(void)
   87 {
   88     struct cnode *cp;
   89 
   90     if (coda_freelist) {
   91         cp = coda_freelist;
   92         coda_freelist = CNODE_NEXT(cp);
   93         coda_reuse++;
   94     }
   95     else {
   96         CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode));
   97         /* NetBSD vnodes don't have any Pager info in them ('cause there are
   98            no external pagers, duh!) */
   99 #define VNODE_VM_INFO_INIT(vp)         /* MT */
  100         VNODE_VM_INFO_INIT(CTOV(cp));
  101         coda_new++;
  102     }
  103     bzero(cp, sizeof (struct cnode));
  104 
  105     return(cp);
  106 }
  107 
  108 /*
  109  * Deallocate a cnode.
  110  */
  111 void
  112 coda_free(cp)
  113      register struct cnode *cp;
  114 {
  115 
  116     CNODE_NEXT(cp) = coda_freelist;
  117     coda_freelist = cp;
  118 }
  119 
  120 /*
  121  * Put a cnode in the hash table
  122  */
  123 void
  124 coda_save(cp)
  125      struct cnode *cp;
  126 {
  127         CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)];
  128         coda_cache[coda_hash(&cp->c_fid)] = cp;
  129 }
  130 
  131 /*
  132  * Remove a cnode from the hash table
  133  */
  134 void
  135 coda_unsave(cp)
  136      struct cnode *cp;
  137 {
  138     struct cnode *ptr;
  139     struct cnode *ptrprev = NULL;
  140     
  141     ptr = coda_cache[coda_hash(&cp->c_fid)]; 
  142     while (ptr != NULL) { 
  143         if (ptr == cp) { 
  144             if (ptrprev == NULL) {
  145                 coda_cache[coda_hash(&cp->c_fid)] 
  146                     = CNODE_NEXT(ptr);
  147             } else {
  148                 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr);
  149             }
  150             CNODE_NEXT(cp) = (struct cnode *)NULL;
  151             
  152             return; 
  153         }       
  154         ptrprev = ptr;
  155         ptr = CNODE_NEXT(ptr);
  156     }   
  157 }
  158 
  159 /*
  160  * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it.
  161  * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95
  162  */
  163 struct cnode *
  164 coda_find(fid) 
  165      ViceFid *fid;
  166 {
  167     struct cnode *cp;
  168 
  169     cp = coda_cache[coda_hash(fid)];
  170     while (cp) {
  171         if ((cp->c_fid.Vnode == fid->Vnode) &&
  172             (cp->c_fid.Volume == fid->Volume) &&
  173             (cp->c_fid.Unique == fid->Unique) &&
  174             (!IS_UNMOUNTING(cp)))
  175             {
  176                 coda_active++;
  177                 return(cp); 
  178             }               
  179         cp = CNODE_NEXT(cp);
  180     }
  181     return(NULL);
  182 }
  183 
  184 /*
  185  * coda_kill is called as a side effect to vcopen. To prevent any
  186  * cnodes left around from an earlier run of a venus or warden from
  187  * causing problems with the new instance, mark any outstanding cnodes
  188  * as dying. Future operations on these cnodes should fail (excepting
  189  * coda_inactive of course!). Since multiple venii/wardens can be
  190  * running, only kill the cnodes for a particular entry in the
  191  * coda_mnttbl. -- DCS 12/1/94 */
  192 
  193 int
  194 coda_kill(whoIam, dcstat)
  195         struct mount *whoIam;
  196         enum dc_status dcstat;
  197 {
  198         int hash, count = 0;
  199         struct cnode *cp;
  200         
  201         /* 
  202          * Algorithm is as follows: 
  203          *     Second, flush whatever vnodes we can from the name cache.
  204          * 
  205          *     Finally, step through whatever is left and mark them dying.
  206          *        This prevents any operation at all.
  207          */
  208         
  209         /* This is slightly overkill, but should work. Eventually it'd be
  210          * nice to only flush those entries from the namecache that
  211          * reference a vnode in this vfs.  */
  212         coda_nc_flush(dcstat);
  213         
  214         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  215                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  216                         if (CTOV(cp)->v_mount == whoIam) {
  217 #ifdef  DEBUG
  218                                 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp);
  219 #endif
  220                                 count++;
  221                                 CODADEBUG(CODA_FLUSH, 
  222                                          myprintf(("Live cnode fid %lx.%lx.%lx flags %d count %d\n",
  223                                                    (cp->c_fid).Volume,
  224                                                    (cp->c_fid).Vnode,
  225                                                    (cp->c_fid).Unique, 
  226                                                    cp->c_flags,
  227                                                    vrefcnt(CTOV(cp)))); );
  228                         }
  229                 }
  230         }
  231         return count;
  232 }
  233 
  234 /*
  235  * There are two reasons why a cnode may be in use, it may be in the
  236  * name cache or it may be executing.  
  237  */
  238 void
  239 coda_flush(dcstat)
  240         enum dc_status dcstat;
  241 {
  242     int hash;
  243     struct cnode *cp;
  244     
  245     coda_clstat.ncalls++;
  246     coda_clstat.reqs[CODA_FLUSH]++;
  247     
  248     coda_nc_flush(dcstat);          /* flush files from the name cache */
  249 
  250     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  251         for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {  
  252             if (!ODD(cp->c_fid.Vnode)) /* only files can be executed */
  253                 coda_vmflush(cp);
  254         }
  255     }
  256 }
  257 
  258 /*
  259  * As a debugging measure, print out any cnodes that lived through a
  260  * name cache flush.  
  261  */
  262 void
  263 coda_testflush(void)
  264 {
  265     int hash;
  266     struct cnode *cp;
  267     
  268     for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  269         for (cp = coda_cache[hash];
  270              cp != NULL;
  271              cp = CNODE_NEXT(cp)) {  
  272             myprintf(("Live cnode fid %lx.%lx.%lx count %d\n",
  273                       (cp->c_fid).Volume,(cp->c_fid).Vnode,
  274                       (cp->c_fid).Unique, vrefcnt(CTOV(cp))));
  275         }
  276     }
  277 }
  278 
  279 /*
  280  *     First, step through all cnodes and mark them unmounting.
  281  *         NetBSD kernels may try to fsync them now that venus
  282  *         is dead, which would be a bad thing.
  283  *
  284  */
  285 void
  286 coda_unmounting(whoIam)
  287         struct mount *whoIam;
  288 {       
  289         int hash;
  290         struct cnode *cp;
  291 
  292         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  293                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  294                         if (CTOV(cp)->v_mount == whoIam) {
  295                                 if (cp->c_flags & (C_LOCKED|C_WANTED)) {
  296                                         printf("coda_unmounting: Unlocking %p\n", cp);
  297                                         cp->c_flags &= ~(C_LOCKED|C_WANTED);
  298                                         wakeup((caddr_t) cp);
  299                                 }
  300                                 cp->c_flags |= C_UNMOUNTING;
  301                         }
  302                 }
  303         }
  304 }
  305 
  306 #ifdef  DEBUG
  307 void
  308 coda_checkunmounting(mp)
  309         struct mount *mp;
  310 {       
  311         register struct vnode *vp, *nvp;
  312         struct cnode *cp;
  313         int count = 0, bad = 0;
  314 loop:
  315         for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) {
  316                 if (vp->v_mount != mp)
  317                         goto loop;
  318                 nvp = TAILQ_NEXT(vp, v_nmntvnodes);
  319                 cp = VTOC(vp);
  320                 count++;
  321                 if (!(cp->c_flags & C_UNMOUNTING)) {
  322                         bad++;
  323                         printf("vp %p, cp %p missed\n", vp, cp);
  324                         cp->c_flags |= C_UNMOUNTING;
  325                 }
  326         }
  327 }
  328 
  329 void
  330 coda_cacheprint(whoIam)
  331         struct mount *whoIam;
  332 {       
  333         int hash;
  334         struct cnode *cp;
  335         int count = 0;
  336 
  337         printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
  338         coda_nc_name(VTOC(coda_ctlvp));
  339         printf("\n");
  340 
  341         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  342                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  343                         if (CTOV(cp)->v_mount == whoIam) {
  344                                 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
  345                                 coda_nc_name(cp);
  346                                 printf("\n");
  347                                 count++;
  348                         }
  349                 }
  350         }
  351         printf("coda_cacheprint: count %d\n", count);
  352 }
  353 #endif
  354 
  355 /*
  356  * There are 6 cases where invalidations occur. The semantics of each
  357  * is listed here.
  358  *
  359  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
  360  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
  361  *                  This call is a result of token expiration.
  362  *
  363  * The next two are the result of callbacks on a file or directory.
  364  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
  365  *                  Zap all children of this directory from the namecache.
  366  * CODA_ZAPFILE   -- flush the attributes for a file.
  367  *
  368  * The fifth is a result of Venus detecting an inconsistent file.
  369  * CODA_PURGEFID  -- flush the attribute for the file
  370  *                  If it is a dir (odd vnode), purge its 
  371  *                  children from the namecache
  372  *                  remove the file from the namecache.
  373  *
  374  * The sixth allows Venus to replace local fids with global ones
  375  * during reintegration.
  376  *
  377  * CODA_REPLACE -- replace one ViceFid with another throughout the name cache 
  378  */
  379 
  380 int handleDownCall(opcode, out)
  381      int opcode; union outputArgs *out;
  382 {
  383     int error;
  384 
  385     /* Handle invalidate requests. */
  386     switch (opcode) {
  387       case CODA_FLUSH : {
  388 
  389           coda_flush(IS_DOWNCALL);
  390           
  391           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
  392               return(0);
  393       }
  394         
  395       case CODA_PURGEUSER : {
  396           coda_clstat.ncalls++;
  397           coda_clstat.reqs[CODA_PURGEUSER]++;
  398           
  399           /* XXX - need to prevent fsync's */
  400           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
  401           return(0);
  402       }
  403         
  404       case CODA_ZAPFILE : {
  405           struct cnode *cp;
  406 
  407           error = 0;
  408           coda_clstat.ncalls++;
  409           coda_clstat.reqs[CODA_ZAPFILE]++;
  410           
  411           cp = coda_find(&out->coda_zapfile.CodaFid);
  412           if (cp != NULL) {
  413               vref(CTOV(cp));
  414               
  415               cp->c_flags &= ~C_VATTR;
  416               ASSERT_VOP_LOCKED(CTOV(cp), "coda HandleDownCall");
  417               if (CTOV(cp)->v_vflag & VV_TEXT)
  418                   error = coda_vmflush(cp);
  419               CODADEBUG(CODA_ZAPFILE, myprintf((
  420 "zapfile: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
  421                   cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique,
  422                   vrefcnt(CTOV(cp)) - 1, error)););
  423               if (vrefcnt(CTOV(cp)) == 1) {
  424                   cp->c_flags |= C_PURGING;
  425               }
  426               vrele(CTOV(cp));
  427           }
  428           
  429           return(error);
  430       }
  431         
  432       case CODA_ZAPDIR : {
  433           struct cnode *cp;
  434 
  435           coda_clstat.ncalls++;
  436           coda_clstat.reqs[CODA_ZAPDIR]++;
  437           
  438           cp = coda_find(&out->coda_zapdir.CodaFid);
  439           if (cp != NULL) {
  440               vref(CTOV(cp));
  441               
  442               cp->c_flags &= ~C_VATTR;
  443               coda_nc_zapParentfid(&out->coda_zapdir.CodaFid, IS_DOWNCALL);
  444 
  445               CODADEBUG(CODA_ZAPDIR, myprintf((
  446 "zapdir: fid = (%lx.%lx.%lx), refcnt = %d\n",
  447                   cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique,
  448                   vrefcnt(CTOV(cp)) - 1)););
  449               if (vrefcnt(CTOV(cp)) == 1) {
  450                   cp->c_flags |= C_PURGING;
  451               }
  452               vrele(CTOV(cp));
  453           }
  454           
  455           return(0);
  456       }
  457         
  458       case CODA_PURGEFID : {
  459           struct cnode *cp;
  460 
  461           error = 0;
  462           coda_clstat.ncalls++;
  463           coda_clstat.reqs[CODA_PURGEFID]++;
  464 
  465           cp = coda_find(&out->coda_purgefid.CodaFid);
  466           if (cp != NULL) {
  467               vref(CTOV(cp));
  468               if (ODD(out->coda_purgefid.CodaFid.Vnode)) { /* Vnode is a directory */
  469                   coda_nc_zapParentfid(&out->coda_purgefid.CodaFid,
  470                                      IS_DOWNCALL);     
  471               }
  472               cp->c_flags &= ~C_VATTR;
  473               coda_nc_zapfid(&out->coda_purgefid.CodaFid, IS_DOWNCALL);
  474               ASSERT_VOP_LOCKED(CTOV(cp), "coda HandleDownCall");
  475               if (!(ODD(out->coda_purgefid.CodaFid.Vnode)) 
  476                   && (CTOV(cp)->v_vflag & VV_TEXT)) {
  477                   
  478                   error = coda_vmflush(cp);
  479               }
  480               CODADEBUG(CODA_PURGEFID, myprintf(("purgefid: fid = (%lx.%lx.%lx), refcnt = %d, error = %d\n",
  481                                             cp->c_fid.Volume, cp->c_fid.Vnode,
  482                                             cp->c_fid.Unique, 
  483                                             vrefcnt(CTOV(cp)) - 1, error)););
  484               if (vrefcnt(CTOV(cp)) == 1) {
  485                   cp->c_flags |= C_PURGING;
  486               }
  487               vrele(CTOV(cp));
  488           }
  489           return(error);
  490       }
  491 
  492       case CODA_REPLACE : {
  493           struct cnode *cp = NULL;
  494 
  495           coda_clstat.ncalls++;
  496           coda_clstat.reqs[CODA_REPLACE]++;
  497           
  498           cp = coda_find(&out->coda_replace.OldFid);
  499           if (cp != NULL) { 
  500               /* remove the cnode from the hash table, replace the fid, and reinsert */
  501               vref(CTOV(cp));
  502               coda_unsave(cp);
  503               cp->c_fid = out->coda_replace.NewFid;
  504               coda_save(cp);
  505 
  506               CODADEBUG(CODA_REPLACE, myprintf(("replace: oldfid = (%lx.%lx.%lx), newfid = (%lx.%lx.%lx), cp = %p\n",
  507                                            out->coda_replace.OldFid.Volume,
  508                                            out->coda_replace.OldFid.Vnode,
  509                                            out->coda_replace.OldFid.Unique,
  510                                            cp->c_fid.Volume, cp->c_fid.Vnode, 
  511                                            cp->c_fid.Unique, cp));)
  512               vrele(CTOV(cp));
  513           }
  514           return (0);
  515       }
  516       default:
  517         myprintf(("handleDownCall: unknown opcode %d\n", opcode));
  518         return (EINVAL);
  519     }
  520 }
  521 
  522 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */
  523 
  524 int
  525 coda_vmflush(cp)
  526      struct cnode *cp;
  527 {
  528     return 0;
  529 }
  530 
  531 
  532 /* 
  533  * kernel-internal debugging switches
  534  */
  535 void coda_debugon(void)
  536 {
  537     codadebug = -1;
  538     coda_nc_debug = -1;
  539     coda_vnop_print_entry = 1;
  540     coda_psdev_print_entry = 1;
  541     coda_vfsop_print_entry = 1;
  542 }
  543 
  544 void coda_debugoff(void)
  545 {
  546     codadebug = 0;
  547     coda_nc_debug = 0;
  548     coda_vnop_print_entry = 0;
  549     coda_psdev_print_entry = 0;
  550     coda_vfsop_print_entry = 0;
  551 }
  552 
  553 /*
  554  * Utilities used by both client and server
  555  * Standard levels:
  556  * 0) no debugging
  557  * 1) hard failures
  558  * 2) soft failures
  559  * 3) current test software
  560  * 4) main procedure entry points
  561  * 5) main procedure exit points
  562  * 6) utility procedure entry points
  563  * 7) utility procedure exit points
  564  * 8) obscure procedure entry points
  565  * 9) obscure procedure exit points
  566  * 10) random stuff
  567  * 11) all <= 1
  568  * 12) all <= 2
  569  * 13) all <= 3
  570  * ...
  571  */

Cache object: 6232952eb66ad9cb819efd5aa1a38577


[ 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.