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  *             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/5.2/sys/coda/coda_subr.c 122091 2003-11-05 04:30:08Z kan $");
   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         register struct vnode *vp, *nvp;
  312         struct cnode *cp;
  313         int count = 0, bad = 0;
  314 
  315         MNT_ILOCK(mp);
  316         for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) {
  317                 nvp = TAILQ_NEXT(vp, v_nmntvnodes);
  318                 if (vp->v_mount != mp)
  319                         continue;
  320                 VI_LOCK(vp);
  321                 if (vp->v_iflag & VI_XLOCK) {
  322                         VI_UNLOCK(vp);
  323                         continue;
  324                 }
  325                 cp = VTOC(vp);
  326                 count++;
  327                 if (!(cp->c_flags & C_UNMOUNTING)) {
  328                         bad++;
  329                         printf("vp %p, cp %p missed\n", vp, cp);
  330                         cp->c_flags |= C_UNMOUNTING;
  331                 }
  332                 VI_UNLOCK(vp);
  333         }
  334         MNT_IUNLOCK(mp);
  335 }
  336 
  337 void
  338 coda_cacheprint(whoIam)
  339         struct mount *whoIam;
  340 {       
  341         int hash;
  342         struct cnode *cp;
  343         int count = 0;
  344 
  345         printf("coda_cacheprint: coda_ctlvp %p, cp %p", coda_ctlvp, VTOC(coda_ctlvp));
  346         coda_nc_name(VTOC(coda_ctlvp));
  347         printf("\n");
  348 
  349         for (hash = 0; hash < CODA_CACHESIZE; hash++) {
  350                 for (cp = coda_cache[hash]; cp != NULL; cp = CNODE_NEXT(cp)) {
  351                         if (CTOV(cp)->v_mount == whoIam) {
  352                                 printf("coda_cacheprint: vp %p, cp %p", CTOV(cp), cp);
  353                                 coda_nc_name(cp);
  354                                 printf("\n");
  355                                 count++;
  356                         }
  357                 }
  358         }
  359         printf("coda_cacheprint: count %d\n", count);
  360 }
  361 #endif
  362 
  363 /*
  364  * There are 6 cases where invalidations occur. The semantics of each
  365  * is listed here.
  366  *
  367  * CODA_FLUSH     -- flush all entries from the name cache and the cnode cache.
  368  * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
  369  *                  This call is a result of token expiration.
  370  *
  371  * The next two are the result of callbacks on a file or directory.
  372  * CODA_ZAPDIR    -- flush the attributes for the dir from its cnode.
  373  *                  Zap all children of this directory from the namecache.
  374  * CODA_ZAPFILE   -- flush the attributes for a file.
  375  *
  376  * The fifth is a result of Venus detecting an inconsistent file.
  377  * CODA_PURGEFID  -- flush the attribute for the file
  378  *                  If it is a dir (odd vnode), purge its 
  379  *                  children from the namecache
  380  *                  remove the file from the namecache.
  381  *
  382  * The sixth allows Venus to replace local fids with global ones
  383  * during reintegration.
  384  *
  385  * CODA_REPLACE -- replace one CodaFid with another throughout the name cache 
  386  */
  387 
  388 int handleDownCall(opcode, out)
  389      int opcode; union outputArgs *out;
  390 {
  391     int error;
  392 
  393     /* Handle invalidate requests. */
  394     switch (opcode) {
  395       case CODA_FLUSH : {
  396 
  397           coda_flush(IS_DOWNCALL);
  398           
  399           CODADEBUG(CODA_FLUSH,coda_testflush();)    /* print remaining cnodes */
  400               return(0);
  401       }
  402         
  403       case CODA_PURGEUSER : {
  404           coda_clstat.ncalls++;
  405           coda_clstat.reqs[CODA_PURGEUSER]++;
  406           
  407           /* XXX - need to prevent fsync's */
  408 #ifdef CODA_COMPAT_5
  409           coda_nc_purge_user(out->coda_purgeuser.cred.cr_uid, IS_DOWNCALL);
  410 #else
  411           coda_nc_purge_user(out->coda_purgeuser.uid, IS_DOWNCALL);
  412 #endif
  413           return(0);
  414       }
  415         
  416       case CODA_ZAPFILE : {
  417           struct cnode *cp;
  418 
  419           error = 0;
  420           coda_clstat.ncalls++;
  421           coda_clstat.reqs[CODA_ZAPFILE]++;
  422           
  423           cp = coda_find(&out->coda_zapfile.Fid);
  424           if (cp != NULL) {
  425               vref(CTOV(cp));
  426               
  427               cp->c_flags &= ~C_VATTR;
  428               ASSERT_VOP_LOCKED(CTOV(cp), "coda HandleDownCall");
  429               if (CTOV(cp)->v_vflag & VV_TEXT)
  430                   error = coda_vmflush(cp);
  431               CODADEBUG(CODA_ZAPFILE, 
  432                         myprintf(("zapfile: fid = %s, refcnt = %d, error = %d\n",
  433                                   coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error)););
  434     if (vrefcnt(CTOV(cp)) == 1) {
  435                   cp->c_flags |= C_PURGING;
  436               }
  437               vrele(CTOV(cp));
  438           }
  439           
  440           return(error);
  441       }
  442         
  443       case CODA_ZAPDIR : {
  444           struct cnode *cp;
  445 
  446           coda_clstat.ncalls++;
  447           coda_clstat.reqs[CODA_ZAPDIR]++;
  448           
  449           cp = coda_find(&out->coda_zapdir.Fid);
  450           if (cp != NULL) {
  451               vref(CTOV(cp));
  452               
  453               cp->c_flags &= ~C_VATTR;
  454               coda_nc_zapParentfid(&out->coda_zapdir.Fid, IS_DOWNCALL);
  455 
  456               CODADEBUG(CODA_ZAPDIR, myprintf((
  457                   "zapdir: fid = %s, refcnt = %d\n",
  458                   coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1)););
  459               if (vrefcnt(CTOV(cp)) == 1) {
  460                   cp->c_flags |= C_PURGING;
  461               }
  462               vrele(CTOV(cp));
  463           }
  464           
  465           return(0);
  466       }
  467         
  468       case CODA_PURGEFID : {
  469           struct cnode *cp;
  470 
  471           error = 0;
  472           coda_clstat.ncalls++;
  473           coda_clstat.reqs[CODA_PURGEFID]++;
  474 
  475           cp = coda_find(&out->coda_purgefid.Fid);
  476           if (cp != NULL) {
  477               vref(CTOV(cp));
  478               if (IS_DIR(out->coda_purgefid.Fid)) { /* Vnode is a directory */
  479                       coda_nc_zapParentfid(&out->coda_purgefid.Fid,IS_DOWNCALL);     
  480               }
  481               cp->c_flags &= ~C_VATTR;
  482               coda_nc_zapfid(&out->coda_purgefid.Fid, IS_DOWNCALL);
  483               ASSERT_VOP_LOCKED(CTOV(cp), "coda HandleDownCall");
  484               if (!(IS_DIR(out->coda_purgefid.Fid)) 
  485                   && (CTOV(cp)->v_vflag & VV_TEXT)) {
  486                   
  487                   error = coda_vmflush(cp);
  488               }
  489               CODADEBUG(CODA_PURGEFID, myprintf((
  490                          "purgefid: fid = %s, refcnt = %d, error = %d\n",
  491                          coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount - 1, error)););
  492               if (vrefcnt(CTOV(cp)) == 1) {
  493                   cp->c_flags |= C_PURGING;
  494               }
  495               vrele(CTOV(cp));
  496           }
  497           return(error);
  498       }
  499 
  500       case CODA_REPLACE : {
  501           struct cnode *cp = NULL;
  502 
  503           coda_clstat.ncalls++;
  504           coda_clstat.reqs[CODA_REPLACE]++;
  505           
  506           cp = coda_find(&out->coda_replace.OldFid);
  507           if (cp != NULL) { 
  508               /* remove the cnode from the hash table, replace the fid, and reinsert */
  509               vref(CTOV(cp));
  510               coda_unsave(cp);
  511               cp->c_fid = out->coda_replace.NewFid;
  512               coda_save(cp);
  513 
  514               CODADEBUG(CODA_REPLACE, myprintf((
  515                         "replace: oldfid = %s, newfid = %s, cp = %p\n",
  516                         coda_f2s(&out->coda_replace.OldFid),
  517                         coda_f2s(&cp->c_fid), cp));)          vrele(CTOV(cp));
  518           }
  519           return (0);
  520       }
  521       default:
  522         myprintf(("handleDownCall: unknown opcode %d\n", opcode));
  523         return (EINVAL);
  524     }
  525 }
  526 
  527 /* coda_grab_vnode: lives in either cfs_mach.c or cfs_nbsd.c */
  528 
  529 int
  530 coda_vmflush(cp)
  531      struct cnode *cp;
  532 {
  533     return 0;
  534 }
  535 
  536 
  537 /* 
  538  * kernel-internal debugging switches
  539  */
  540 void coda_debugon(void)
  541 {
  542     codadebug = -1;
  543     coda_nc_debug = -1;
  544     coda_vnop_print_entry = 1;
  545     coda_psdev_print_entry = 1;
  546     coda_vfsop_print_entry = 1;
  547 }
  548 
  549 void coda_debugoff(void)
  550 {
  551     codadebug = 0;
  552     coda_nc_debug = 0;
  553     coda_vnop_print_entry = 0;
  554     coda_psdev_print_entry = 0;
  555     coda_vfsop_print_entry = 0;
  556 }
  557 
  558 /*
  559  * Utilities used by both client and server
  560  * Standard levels:
  561  * 0) no debugging
  562  * 1) hard failures
  563  * 2) soft failures
  564  * 3) current test software
  565  * 4) main procedure entry points
  566  * 5) main procedure exit points
  567  * 6) utility procedure entry points
  568  * 7) utility procedure exit points
  569  * 8) obscure procedure entry points
  570  * 9) obscure procedure exit points
  571  * 10) random stuff
  572  * 11) all <= 1
  573  * 12) all <= 2
  574  * 13) all <= 3
  575  * ...
  576  */

Cache object: 0fd84627a06c3306f34f5d936fc515cd


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