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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  *             Coda: an Experimental Distributed File System
    3  *                              Release 3.1
    4  * 
    5  *           Copyright (c) 1987-1998 Carnegie Mellon University
    6  *                          All Rights Reserved
    7  * 
    8  * Permission  to  use, copy, modify and distribute this software and its
    9  * documentation is hereby granted,  provided  that  both  the  copyright
   10  * notice  and  this  permission  notice  appear  in  all  copies  of the
   11  * software, derivative works or  modified  versions,  and  any  portions
   12  * thereof, and that both notices appear in supporting documentation, and
   13  * that credit is given to Carnegie Mellon University  in  all  documents
   14  * and publicity pertaining to direct or indirect use of this code or its
   15  * derivatives.
   16  * 
   17  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
   18  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
   19  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
   20  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
   21  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
   22  * ANY DERIVATIVE WORK.
   23  * 
   24  * Carnegie  Mellon  encourages  users  of  this  software  to return any
   25  * improvements or extensions that  they  make,  and  to  grant  Carnegie
   26  * Mellon the rights to redistribute these changes without encumbrance.
   27  * 
   28  *      @(#) src/sys/coda/coda_subr.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
   29  */
   30 /*-
   31  * Mach Operating System
   32  * Copyright (c) 1989 Carnegie-Mellon University
   33  * All rights reserved.  The CMU software License Agreement specifies
   34  * the terms and conditions for use and redistribution.
   35  */
   36 
   37 /*
   38  * This code was written for the Coda filesystem at Carnegie Mellon
   39  * University.  Contributers include David Steere, James Kistler, and
   40  * M. Satyanarayanan.
   41  */
   42 
   43 /* NOTES: rvb
   44  * 1.   Added coda_unmounting to mark all cnodes as being UNMOUNTING.  This has to
   45  *       be done before dounmount is called.  Because some of the routines that
   46  *       dounmount calls before coda_unmounted might try to force flushes to venus.
   47  *       The vnode pager does this.
   48  * 2.   coda_unmounting marks all cnodes scanning coda_cache.
   49  * 3.   cfs_checkunmounting (under DEBUG) checks all cnodes by chasing the vnodes
   50  *       under the /coda mount point.
   51  * 4.   coda_cacheprint (under DEBUG) prints names with vnode/cnode address
   52  */
   53 
   54 #include <sys/cdefs.h>
   55 __FBSDID("$FreeBSD: releng/6.2/sys/coda/coda_subr.c 143510 2005-03-13 12:14:56Z jeff $");
   56 
   57 #include <sys/param.h>
   58 #include <sys/systm.h>
   59 #include <sys/lock.h>
   60 #include <sys/malloc.h>
   61 #include <sys/mutex.h>
   62 #include <sys/mount.h>
   63 
   64 #include <coda/coda.h>
   65 #include <coda/cnode.h>
   66 #include <coda/coda_subr.h>
   67 #include <coda/coda_namecache.h>
   68 
   69 int coda_active = 0;
   70 int coda_reuse = 0;
   71 int coda_new = 0;
   72 
   73 struct cnode *coda_freelist = NULL;
   74 struct cnode *coda_cache[CODA_CACHESIZE];
   75 
   76 #define CNODE_NEXT(cp)  ((cp)->c_next)
   77 
   78 #ifdef CODA_COMPAT_5
   79 #define coda_hash(fid) \
   80     (((fid)->Volume + (fid)->Vnode) & (CODA_CACHESIZE-1))
   81 #define IS_DIR(cnode)        (cnode.Vnode & 0x1)
   82 #else
   83 #define coda_hash(fid) (coda_f2i(fid) & (CODA_CACHESIZE-1))
   84 #define IS_DIR(cnode)        (cnode.opaque[2] & 0x1)
   85 #endif
   86 
   87 /*
   88  * Allocate a cnode.
   89  */
   90 struct cnode *
   91 coda_alloc(void)
   92 {
   93     struct cnode *cp;
   94 
   95     if (coda_freelist) {
   96         cp = coda_freelist;
   97         coda_freelist = CNODE_NEXT(cp);
   98         coda_reuse++;
   99     }
  100     else {
  101         CODA_ALLOC(cp, struct cnode *, sizeof(struct cnode));
  102         /* NetBSD vnodes don't have any Pager info in them ('cause there are
  103            no external pagers, duh!) */
  104 #define VNODE_VM_INFO_INIT(vp)         /* MT */
  105         VNODE_VM_INFO_INIT(CTOV(cp));
  106         coda_new++;
  107     }
  108     bzero(cp, sizeof (struct cnode));
  109 
  110     return(cp);
  111 }
  112 
  113 /*
  114  * Deallocate a cnode.
  115  */
  116 void
  117 coda_free(cp)
  118      register struct cnode *cp;
  119 {
  120 
  121     CNODE_NEXT(cp) = coda_freelist;
  122     coda_freelist = cp;
  123 }
  124 
  125 /*
  126  * Put a cnode in the hash table
  127  */
  128 void
  129 coda_save(cp)
  130      struct cnode *cp;
  131 {
  132         CNODE_NEXT(cp) = coda_cache[coda_hash(&cp->c_fid)];
  133         coda_cache[coda_hash(&cp->c_fid)] = cp;
  134 }
  135 
  136 /*
  137  * Remove a cnode from the hash table
  138  */
  139 void
  140 coda_unsave(cp)
  141      struct cnode *cp;
  142 {
  143     struct cnode *ptr;
  144     struct cnode *ptrprev = NULL;
  145     
  146     ptr = coda_cache[coda_hash(&cp->c_fid)]; 
  147     while (ptr != NULL) { 
  148         if (ptr == cp) { 
  149             if (ptrprev == NULL) {
  150                 coda_cache[coda_hash(&cp->c_fid)] 
  151                     = CNODE_NEXT(ptr);
  152             } else {
  153                 CNODE_NEXT(ptrprev) = CNODE_NEXT(ptr);
  154             }
  155             CNODE_NEXT(cp) = (struct cnode *)NULL;
  156             
  157             return; 
  158         }       
  159         ptrprev = ptr;
  160         ptr = CNODE_NEXT(ptr);
  161     }   
  162 }
  163 
  164 /*
  165  * Lookup a cnode by fid. If the cnode is dying, it is bogus so skip it.
  166  * NOTE: this allows multiple cnodes with same fid -- dcs 1/25/95
  167  */
  168 struct cnode *
  169 coda_find(fid) 
  170      CodaFid *fid;
  171 {
  172     struct cnode *cp;
  173 
  174     cp = coda_cache[coda_hash(fid)];
  175     while (cp) {
  176             if (coda_fid_eq(&(cp->c_fid), fid) &&
  177             (!IS_UNMOUNTING(cp)))
  178             {
  179                 coda_active++;
  180                 return(cp); 
  181             }               
  182         cp = CNODE_NEXT(cp);
  183     }
  184     return(NULL);
  185 }
  186 
  187 /*
  188  * coda_kill is called as a side effect to vcopen. To prevent any
  189  * cnodes left around from an earlier run of a venus or warden from
  190  * causing problems with the new instance, mark any outstanding cnodes
  191  * as dying. Future operations on these cnodes should fail (excepting
  192  * coda_inactive of course!). Since multiple venii/wardens can be
  193  * running, only kill the cnodes for a particular entry in the
  194  * coda_mnttbl. -- DCS 12/1/94 */
  195 
  196 int
  197 coda_kill(whoIam, dcstat)
  198         struct mount *whoIam;
  199         enum dc_status dcstat;
  200 {
  201         int hash, count = 0;
  202         struct cnode *cp;
  203         
  204         /* 
  205          * Algorithm is as follows: 
  206          *     Second, flush whatever vnodes we can from the name cache.
  207          * 
  208          *     Finally, step through whatever is left and mark them dying.
  209          *        This prevents any operation at all.
  210          */
  211         
  212         /* This is slightly overkill, but should work. Eventually it'd be
  213          * nice to only flush those entries from the namecache that
  214          * reference a vnode in this vfs.  */
  215         coda_nc_flush(dcstat);
  216         
  217         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  218                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  219                         if (CTOV(cp)->v_mount == whoIam) {
  220 #ifdef  DEBUG
  221                                 printf("coda_kill: vp %p, cp %p\n", CTOV(cp), cp);
  222 #endif
  223                                 count++;
  224                                 CODADEBUG(CODA_FLUSH, 
  225                                           myprintf(("Live cnode fid %s flags %d count %d\n",
  226                                                     coda_f2s(&cp->c_fid),
  227                                                     cp->c_flags,
  228                                                     vrefcnt(CTOV(cp)))); );
  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 (!IS_DIR(cp->c_fid)) /* 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 %s count %d\n",
  274                       coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount));
  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         struct vnode *vp, *nvp;
  312         struct cnode *cp;
  313         int count = 0, bad = 0;
  314 
  315         MNT_ILOCK(mp);
  316         MNT_VNODE_FOREACH(vp, mp, nvp) {
  317                 VI_LOCK(vp);
  318                 if (vp->v_iflag & VI_DOOMED) {
  319                         VI_UNLOCK(vp);
  320                         continue;
  321                 }
  322                 cp = VTOC(vp);
  323                 count++;
  324                 if (!(cp->c_flags & C_UNMOUNTING)) {
  325                         bad++;
  326                         printf("vp %p, cp %p missed\n", vp, cp);
  327                         cp->c_flags |= C_UNMOUNTING;
  328                 }
  329                 VI_UNLOCK(vp);
  330         }
  331         MNT_IUNLOCK(mp);
  332 }
  333 
  334 void
  335 coda_cacheprint(whoIam)
  336         struct mount *whoIam;
  337 {       
  338         int hash;
  339         struct cnode *cp;
  340         int count = 0;
  341 
  342         printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
  343         coda_nc_name(VTOC(coda_ctlvp));
  344         printf("\n");
  345 
  346         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  347                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  348                         if (CTOV(cp)->v_mount == whoIam) {
  349                                 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
  350                                 coda_nc_name(cp);
  351                                 printf("\n");
  352                                 count++;
  353                         }
  354                 }
  355         }
  356         printf("coda_cacheprint: count %d\n", count);
  357 }
  358 #endif
  359 
  360 /*
  361  * There are 6 cases where invalidations occur. The semantics of each
  362  * is listed here.
  363  *
  364  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
  365  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
  366  *                  This call is a result of token expiration.
  367  *
  368  * The next two are the result of callbacks on a file or directory.
  369  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
  370  *                  Zap all children of this directory from the namecache.
  371  * CODA_ZAPFILE   -- flush the attributes for a file.
  372  *
  373  * The fifth is a result of Venus detecting an inconsistent file.
  374  * CODA_PURGEFID  -- flush the attribute for the file
  375  *                  If it is a dir (odd vnode), purge its 
  376  *                  children from the namecache
  377  *                  remove the file from the namecache.
  378  *
  379  * The sixth allows Venus to replace local fids with global ones
  380  * during reintegration.
  381  *
  382  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache 
  383  */
  384 
  385 int handleDownCall(opcode, out)
  386      int opcode; union outputArgs *out;
  387 {
  388     int error;
  389 
  390     /* Handle invalidate requests. */
  391     switch (opcode) {
  392       case CODA_FLUSH : {
  393 
  394           coda_flush(IS_DOWNCALL);
  395           
  396           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
  397               return(0);
  398       }
  399         
  400       case CODA_PURGEUSER : {
  401           coda_clstat.ncalls++;
  402           coda_clstat.reqs[CODA_PURGEUSER]++;
  403           
  404           /* XXX - need to prevent fsync's */
  405 #ifdef CODA_COMPAT_5
  406           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
  407 #else
  408           coda_nc_purge_user(out->coda_purgeuser.uid, IS_DOWNCALL);
  409 #endif
  410           return(0);
  411       }
  412         
  413       case CODA_ZAPFILE : {
  414           struct cnode *cp;
  415 
  416           error = 0;
  417           coda_clstat.ncalls++;
  418           coda_clstat.reqs[CODA_ZAPFILE]++;
  419           
  420           cp = coda_find(&out->coda_zapfile.Fid);
  421           if (cp != NULL) {
  422               vref(CTOV(cp));
  423               
  424               cp->c_flags &= ~C_VATTR;
  425               ASSERT_VOP_LOCKED(CTOV(cp), "coda HandleDownCall");
  426               if (CTOV(cp)->v_vflag & VV_TEXT)
  427                   error = coda_vmflush(cp);
  428               CODADEBUG(CODA_ZAPFILE, 
  429                         myprintf(("zapfile: fid = %s, refcnt = %d, error = %d\n",
  430                                   coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error)););
  431     if (vrefcnt(CTOV(cp)) == 1) {
  432                   cp->c_flags |= C_PURGING;
  433               }
  434               vrele(CTOV(cp));
  435           }
  436           
  437           return(error);
  438       }
  439         
  440       case CODA_ZAPDIR : {
  441           struct cnode *cp;
  442 
  443           coda_clstat.ncalls++;
  444           coda_clstat.reqs[CODA_ZAPDIR]++;
  445           
  446           cp = coda_find(&out->coda_zapdir.Fid);
  447           if (cp != NULL) {
  448               vref(CTOV(cp));
  449               
  450               cp->c_flags &= ~C_VATTR;
  451               coda_nc_zapParentfid(&out->coda_zapdir.Fid, IS_DOWNCALL);
  452 
  453               CODADEBUG(CODA_ZAPDIR, myprintf((
  454                   "zapdir: fid = %s, refcnt = %d\n",
  455                   coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1)););
  456               if (vrefcnt(CTOV(cp)) == 1) {
  457                   cp->c_flags |= C_PURGING;
  458               }
  459               vrele(CTOV(cp));
  460           }
  461           
  462           return(0);
  463       }
  464         
  465       case CODA_PURGEFID : {
  466           struct cnode *cp;
  467 
  468           error = 0;
  469           coda_clstat.ncalls++;
  470           coda_clstat.reqs[CODA_PURGEFID]++;
  471 
  472           cp = coda_find(&out->coda_purgefid.Fid);
  473           if (cp != NULL) {
  474               vref(CTOV(cp));
  475               if (IS_DIR(out->coda_purgefid.Fid)) { /* Vnode is a directory */
  476                       coda_nc_zapParentfid(&out->coda_purgefid.Fid,IS_DOWNCALL);     
  477               }
  478               cp->c_flags &= ~C_VATTR;
  479               coda_nc_zapfid(&out->coda_purgefid.Fid, IS_DOWNCALL);
  480               ASSERT_VOP_LOCKED(CTOV(cp), "coda HandleDownCall");
  481               if (!(IS_DIR(out->coda_purgefid.Fid)) 
  482                   && (CTOV(cp)->v_vflag & VV_TEXT)) {
  483                   
  484                   error = coda_vmflush(cp);
  485               }
  486               CODADEBUG(CODA_PURGEFID, myprintf((
  487                          "purgefid: fid = %s, refcnt = %d, error = %d\n",
  488                          coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error)););
  489               if (vrefcnt(CTOV(cp)) == 1) {
  490                   cp->c_flags |= C_PURGING;
  491               }
  492               vrele(CTOV(cp));
  493           }
  494           return(error);
  495       }
  496 
  497       case CODA_REPLACE : {
  498           struct cnode *cp = NULL;
  499 
  500           coda_clstat.ncalls++;
  501           coda_clstat.reqs[CODA_REPLACE]++;
  502           
  503           cp = coda_find(&out->coda_replace.OldFid);
  504           if (cp != NULL) { 
  505               /* remove the cnode from the hash table, replace the fid, and reinsert */
  506               vref(CTOV(cp));
  507               coda_unsave(cp);
  508               cp->c_fid = out->coda_replace.NewFid;
  509               coda_save(cp);
  510 
  511               CODADEBUG(CODA_REPLACE, myprintf((
  512                         "replace: oldfid = %s, newfid = %s, cp = %p\n",
  513                         coda_f2s(&out->coda_replace.OldFid),
  514                         coda_f2s(&cp->c_fid), cp));)          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: 097952ea737853c3b88a94e27e96955c


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