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

Cache object: 379c451fce25cd6b0589cb0bf7e805b2


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