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_namecache.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  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  * 
    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_namecache.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
   30  * $FreeBSD: src/sys/coda/coda_namecache.c,v 1.8.2.1 1999/08/29 16:21:55 peter Exp $
   31  * 
   32  */
   33 
   34 /* 
   35  * Mach Operating System
   36  * Copyright (c) 1990 Carnegie-Mellon University
   37  * Copyright (c) 1989 Carnegie-Mellon University
   38  * All rights reserved.  The CMU software License Agreement specifies
   39  * the terms and conditions for use and redistribution.
   40  */
   41 
   42 /*
   43  * This code was written for the Coda file system at Carnegie Mellon University.
   44  * Contributers include David Steere, James Kistler, and M. Satyanarayanan.
   45  */
   46 
   47 /*
   48  * HISTORY
   49  * $Log: coda_namecache.c,v $
   50  * Revision 1.8  1998/10/28 19:33:50  rvb
   51  * Venus must be passed O_CREAT flag on VOP_OPEN iff this is
   52  * a creat so that we can will allow a mode 444 file to be
   53  * written into.  Sync with the latest coda.h and deal with
   54  * collateral damage.
   55  *
   56  * Revision 1.7  1998/09/28 20:52:58  rvb
   57  * Cleanup and fix THE bug
   58  *
   59  * Revision 1.6  1998/09/25 17:38:31  rvb
   60  * Put "stray" printouts under DIAGNOSTIC.  Make everything build
   61  * with DEBUG on.  Add support for lkm.  (The macro's don't work
   62  * for me; for a good chuckle look at the end of coda_fbsd.c.)
   63  *
   64  * Revision 1.5  1998/09/13 13:57:59  rvb
   65  * Finish conversion of cfs -> coda
   66  *
   67  * Revision 1.4  1998/09/11 18:50:17  rvb
   68  * All the references to cfs, in symbols, structs, and strings
   69  * have been changed to coda.  (Same for CFS.)
   70  *
   71  * Revision 1.2  1998/09/02 19:09:53  rvb
   72  * Pass2 complete
   73  *
   74  * Revision 1.1.1.1  1998/08/29 21:14:52  rvb
   75  * Very Preliminary Coda
   76  *
   77  * Revision 1.11  1998/08/28 18:12:16  rvb
   78  * Now it also works on FreeBSD -current.  This code will be
   79  * committed to the FreeBSD -current and NetBSD -current
   80  * trees.  It will then be tailored to the particular platform
   81  * by flushing conditional code.
   82  *
   83  * Revision 1.10  1998/08/18 17:05:14  rvb
   84  * Don't use __RCSID now
   85  *
   86  * Revision 1.9  1998/08/18 16:31:39  rvb
   87  * Sync the code for NetBSD -current; test on 1.3 later
   88  *
   89  * Revision 1.8  98/01/31  20:53:10  rvb
   90  * First version that works on FreeBSD 2.2.5
   91  * 
   92  * Revision 1.7  98/01/23  11:53:39  rvb
   93  * Bring RVB_CODA1_1 to HEAD
   94  * 
   95  * Revision 1.6.2.4  98/01/23  11:21:02  rvb
   96  * Sync with 2.2.5
   97  * 
   98  * Revision 1.6.2.3  97/12/16  12:40:03  rvb
   99  * Sync with 1.3
  100  * 
  101  * Revision 1.6.2.2  97/12/09  16:07:10  rvb
  102  * Sync with vfs/include/coda.h
  103  * 
  104  * Revision 1.6.2.1  97/12/06  17:41:18  rvb
  105  * Sync with peters coda.h
  106  * 
  107  * Revision 1.6  97/12/05  10:39:13  rvb
  108  * Read CHANGES
  109  * 
  110  * Revision 1.5.4.7  97/11/25  08:08:43  rvb
  111  * cfs_venus ... done; until cred/vattr change
  112  * 
  113  * Revision 1.5.4.6  97/11/24  15:44:43  rvb
  114  * Final cfs_venus.c w/o macros, but one locking bug
  115  * 
  116  * Revision 1.5.4.5  97/11/20  11:46:38  rvb
  117  * Capture current cfs_venus
  118  * 
  119  * Revision 1.5.4.4  97/11/18  10:27:13  rvb
  120  * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c
  121  * cfs_nb_foo and cfs_foo are joined
  122  * 
  123  * Revision 1.5.4.3  97/11/13  22:02:57  rvb
  124  * pass2 cfs_NetBSD.h mt
  125  * 
  126  * Revision 1.5.4.2  97/11/12  12:09:35  rvb
  127  * reorg pass1
  128  * 
  129  * Revision 1.5.4.1  97/10/28  23:10:12  rvb
  130  * >64Meg; venus can be killed!
  131  * 
  132  * Revision 1.5  97/08/05  11:08:01  lily
  133  * Removed cfsnc_replace, replaced it with a coda_find, unhash, and
  134  * rehash.  This fixes a cnode leak and a bug in which the fid is
  135  * not actually replaced.  (cfs_namecache.c, cfsnc.h, cfs_subr.c)
  136  * 
  137  * Revision 1.4  96/12/12  22:10:57  bnoble
  138  * Fixed the "downcall invokes venus operation" deadlock in all known cases.
  139  * There may be more
  140  * 
  141  * Revision 1.3  1996/11/08 18:06:09  bnoble
  142  * Minor changes in vnode operation signature, VOP_UPDATE signature, and
  143  * some newly defined bits in the include files.
  144  *
  145  * Revision 1.2  1996/01/02 16:56:50  bnoble
  146  * Added support for Coda MiniCache and raw inode calls (final commit)
  147  *
  148  * Revision 1.1.2.1  1995/12/20 01:57:15  bnoble
  149  * Added CODA-specific files
  150  *
  151  * Revision 3.1.1.1  1995/03/04  19:07:57  bnoble
  152  * Branch for NetBSD port revisions
  153  *
  154  * Revision 3.1  1995/03/04  19:07:56  bnoble
  155  * Bump to major revision 3 to prepare for NetBSD port
  156  *
  157  * Revision 2.3  1994/10/14  09:57:54  dcs
  158  * Made changes 'cause sun4s have braindead compilers
  159  *
  160  * Revision 2.2  94/08/28  19:37:35  luqi
  161  * Add a new CODA_REPLACE call to allow venus to replace a ViceFid in the
  162  * mini-cache. 
  163  * 
  164  * In "cfs.h":
  165  * Add CODA_REPLACE decl.
  166  * 
  167  * In "cfs_namecache.c":
  168  * Add routine cfsnc_replace.
  169  * 
  170  * In "cfs_subr.c":
  171  * Add case-statement to process CODA_REPLACE.
  172  * 
  173  * In "cfsnc.h":
  174  * Add decl for CODA_NC_REPLACE.
  175  * 
  176  * 
  177  * Revision 2.1  94/07/21  16:25:15  satya
  178  * Conversion to C++ 3.0; start of Coda Release 2.0
  179  *
  180  * Revision 1.2  92/10/27  17:58:21  lily
  181  * merge kernel/latest and alpha/src/cfs
  182  * 
  183  * Revision 2.3  92/09/30  14:16:20  mja
  184  *      call coda_flush instead of calling inode_uncache_try directly 
  185  *      (from dcs). Also...
  186  * 
  187  *      Substituted rvb's history blurb so that we agree with Mach 2.5 sources.
  188  *      [91/02/09            jjk]
  189  * 
  190  *      Added contributors blurb.
  191  *      [90/12/13            jjk]
  192  * 
  193  * Revision 2.2  90/07/05  11:26:30  mrt
  194  *      Created for the Coda File System.
  195  *      [90/05/23            dcs]
  196  * 
  197  * Revision 1.3  90/05/31  17:01:24  dcs
  198  * Prepare for merge with facilities kernel.
  199  * 
  200  * 
  201  */
  202 
  203 /*
  204  * This module contains the routines to implement the CODA name cache. The
  205  * purpose of this cache is to reduce the cost of translating pathnames 
  206  * into Vice FIDs. Each entry in the cache contains the name of the file,
  207  * the vnode (FID) of the parent directory, and the cred structure of the
  208  * user accessing the file.
  209  *
  210  * The first time a file is accessed, it is looked up by the local Venus
  211  * which first insures that the user has access to the file. In addition
  212  * we are guaranteed that Venus will invalidate any name cache entries in
  213  * case the user no longer should be able to access the file. For these
  214  * reasons we do not need to keep access list information as well as a
  215  * cred structure for each entry.
  216  *
  217  * The table can be accessed through the routines cnc_init(), cnc_enter(),
  218  * cnc_lookup(), cnc_rmfidcred(), cnc_rmfid(), cnc_rmcred(), and cnc_purge().
  219  * There are several other routines which aid in the implementation of the
  220  * hash table.
  221  */
  222 
  223 /*
  224  * NOTES: rvb@cs
  225  * 1.   The name cache holds a reference to every vnode in it.  Hence files can not be
  226  *       closed or made inactive until they are released.
  227  * 2.   coda_nc_name(cp) was added to get a name for a cnode pointer for debugging.
  228  * 3.   coda_nc_find() has debug code to detect when entries are stored with different
  229  *       credentials.  We don't understand yet, if/how entries are NOT EQ but still
  230  *       EQUAL
  231  * 4.   I wonder if this name cache could be replace by the vnode name cache.
  232  *      The latter has no zapping functions, so probably not.
  233  */
  234 
  235 #include <sys/param.h>
  236 #include <sys/errno.h>
  237 #include <sys/malloc.h>
  238 #include <sys/ucred.h>
  239 #include <sys/select.h>
  240 
  241 #ifndef insque
  242 #include <sys/systm.h>
  243 #endif /* insque */
  244 
  245 #include <vm/vm.h>
  246 #include <vm/vm_object.h>
  247 
  248 #include <coda/coda.h>
  249 #include <coda/cnode.h>
  250 #include <coda/coda_namecache.h>
  251 
  252 #ifdef  DEBUG
  253 #include <coda/coda_vnops.h>
  254 #endif
  255 
  256 /* 
  257  * Declaration of the name cache data structure.
  258  */
  259 
  260 int     coda_nc_use = 1;                         /* Indicate use of CODA Name Cache */
  261 int     coda_nc_size = CODA_NC_CACHESIZE;        /* size of the cache */
  262 int     coda_nc_hashsize = CODA_NC_HASHSIZE; /* size of the primary hash */
  263 
  264 struct  coda_cache *coda_nc_heap;       /* pointer to the cache entries */
  265 struct  coda_hash  *coda_nc_hash;       /* hash table of coda_cache pointers */
  266 struct  coda_lru   coda_nc_lru;         /* head of lru chain */
  267 
  268 struct coda_nc_statistics coda_nc_stat; /* Keep various stats */
  269 
  270 /* 
  271  * for testing purposes
  272  */
  273 int coda_nc_debug = 0;
  274 
  275 /*
  276  * Entry points for the CODA Name Cache
  277  */
  278 static struct coda_cache *coda_nc_find(struct cnode *dcp, const char *name, int namelen,
  279         struct ucred *cred, int hash);
  280 static void coda_nc_remove(struct coda_cache *cncp, enum dc_status dcstat);
  281 
  282 /*  
  283  * Initialize the cache, the LRU structure and the Hash structure(s)
  284  */
  285 
  286 #define TOTAL_CACHE_SIZE        (sizeof(struct coda_cache) * coda_nc_size)
  287 #define TOTAL_HASH_SIZE         (sizeof(struct coda_hash)  * coda_nc_hashsize)
  288 
  289 int coda_nc_initialized = 0;      /* Initially the cache has not been initialized */
  290 
  291 void
  292 coda_nc_init(void)
  293 {
  294     int i;
  295 
  296     /* zero the statistics structure */
  297     
  298     bzero(&coda_nc_stat, (sizeof(struct coda_nc_statistics)));
  299 
  300 #ifdef  CODA_VERBOSE
  301     printf("CODA NAME CACHE: CACHE %d, HASH TBL %d\n", CODA_NC_CACHESIZE, CODA_NC_HASHSIZE);
  302 #endif
  303     CODA_ALLOC(coda_nc_heap, struct coda_cache *, TOTAL_CACHE_SIZE);
  304     CODA_ALLOC(coda_nc_hash, struct coda_hash *, TOTAL_HASH_SIZE);
  305     
  306     coda_nc_lru.lru_next = 
  307         coda_nc_lru.lru_prev = (struct coda_cache *)LRU_PART(&coda_nc_lru);
  308     
  309     
  310     for (i=0; i < coda_nc_size; i++) {  /* initialize the heap */
  311         CODA_NC_LRUINS(&coda_nc_heap[i], &coda_nc_lru);
  312         CODA_NC_HSHNUL(&coda_nc_heap[i]);
  313         coda_nc_heap[i].cp = coda_nc_heap[i].dcp = (struct cnode *)0;
  314     }
  315     
  316     for (i=0; i < coda_nc_hashsize; i++) {      /* initialize the hashtable */
  317         CODA_NC_HSHNUL((struct coda_cache *)&coda_nc_hash[i]);
  318     }
  319     
  320     coda_nc_initialized++;
  321 }
  322 
  323 /*
  324  * Auxillary routines -- shouldn't be entry points
  325  */
  326 
  327 static struct coda_cache *
  328 coda_nc_find(dcp, name, namelen, cred, hash)
  329         struct cnode *dcp;
  330         const char *name;
  331         int namelen;
  332         struct ucred *cred;
  333         int hash;
  334 {
  335         /* 
  336          * hash to find the appropriate bucket, look through the chain
  337          * for the right entry (especially right cred, unless cred == 0) 
  338          */
  339         struct coda_cache *cncp;
  340         int count = 1;
  341 
  342         CODA_NC_DEBUG(CODA_NC_FIND, 
  343                     myprintf(("coda_nc_find(dcp %p, name %s, len %d, cred %p, hash %d\n",
  344                            dcp, name, namelen, cred, hash));)
  345 
  346         for (cncp = coda_nc_hash[hash].hash_next; 
  347              cncp != (struct coda_cache *)&coda_nc_hash[hash];
  348              cncp = cncp->hash_next, count++) 
  349         {
  350 
  351             if ((CODA_NAMEMATCH(cncp, name, namelen, dcp)) &&
  352                 ((cred == 0) || (cncp->cred == cred))) 
  353             { 
  354                 /* compare cr_uid instead */
  355                 coda_nc_stat.Search_len += count;
  356                 return(cncp);
  357             }
  358 #ifdef  DEBUG
  359             else if (CODA_NAMEMATCH(cncp, name, namelen, dcp)) {
  360                 printf("coda_nc_find: name %s, new cred = %p, cred = %p\n",
  361                         name, cred, cncp->cred);
  362                 printf("nref %d, nuid %d, ngid %d // oref %d, ocred %d, ogid %d\n",
  363                         cred->cr_ref, cred->cr_uid, cred->cr_gid,
  364                         cncp->cred->cr_ref, cncp->cred->cr_uid, cncp->cred->cr_gid);
  365                 print_cred(cred);
  366                 print_cred(cncp->cred);
  367             }
  368 #endif
  369         }
  370 
  371         return((struct coda_cache *)0);
  372 }
  373 
  374 /*
  375  * Enter a new (dir cnode, name) pair into the cache, updating the
  376  * LRU and Hash as needed.
  377  */
  378 void
  379 coda_nc_enter(dcp, name, namelen, cred, cp)
  380     struct cnode *dcp;
  381     const char *name;
  382     int namelen;
  383     struct ucred *cred;
  384     struct cnode *cp;
  385 {
  386     struct coda_cache *cncp;
  387     int hash;
  388     
  389     if (coda_nc_use == 0)                       /* Cache is off */
  390         return;
  391     
  392     CODA_NC_DEBUG(CODA_NC_ENTER, 
  393                 myprintf(("Enter: dcp %p cp %p name %s cred %p \n",
  394                        dcp, cp, name, cred)); )
  395         
  396     if (namelen > CODA_NC_NAMELEN) {
  397         CODA_NC_DEBUG(CODA_NC_ENTER, 
  398                     myprintf(("long name enter %s\n",name));)
  399             coda_nc_stat.long_name_enters++;    /* record stats */
  400         return;
  401     }
  402     
  403     hash = CODA_NC_HASH(name, namelen, dcp);
  404     cncp = coda_nc_find(dcp, name, namelen, cred, hash);
  405     if (cncp != (struct coda_cache *) 0) {      
  406         coda_nc_stat.dbl_enters++;              /* duplicate entry */
  407         return;
  408     }
  409     
  410     coda_nc_stat.enters++;              /* record the enters statistic */
  411     
  412     /* Grab the next element in the lru chain */
  413     cncp = CODA_NC_LRUGET(coda_nc_lru);
  414     
  415     CODA_NC_LRUREM(cncp);       /* remove it from the lists */
  416     
  417     if (CODA_NC_VALID(cncp)) {
  418         /* Seems really ugly, but we have to decrement the appropriate
  419            hash bucket length here, so we have to find the hash bucket
  420            */
  421         coda_nc_hash[CODA_NC_HASH(cncp->name, cncp->namelen, cncp->dcp)].length--;
  422         
  423         coda_nc_stat.lru_rm++;  /* zapped a valid entry */
  424         CODA_NC_HSHREM(cncp);
  425         vrele(CTOV(cncp->dcp)); 
  426         vrele(CTOV(cncp->cp));
  427         crfree(cncp->cred);
  428     }
  429     
  430     /*
  431      * Put a hold on the current vnodes and fill in the cache entry.
  432      */
  433     vref(CTOV(cp));
  434     vref(CTOV(dcp));
  435     crhold(cred); 
  436     cncp->dcp = dcp;
  437     cncp->cp = cp;
  438     cncp->namelen = namelen;
  439     cncp->cred = cred;
  440     
  441     bcopy(name, cncp->name, (unsigned)namelen);
  442     
  443     /* Insert into the lru and hash chains. */
  444     
  445     CODA_NC_LRUINS(cncp, &coda_nc_lru);
  446     CODA_NC_HSHINS(cncp, &coda_nc_hash[hash]);
  447     coda_nc_hash[hash].length++;                      /* Used for tuning */
  448     
  449     CODA_NC_DEBUG(CODA_NC_PRINTCODA_NC, print_coda_nc(); )
  450 }
  451 
  452 /*
  453  * Find the (dir cnode, name) pair in the cache, if it's cred
  454  * matches the input, return it, otherwise return 0
  455  */
  456 struct cnode *
  457 coda_nc_lookup(dcp, name, namelen, cred)
  458         struct cnode *dcp;
  459         const char *name;
  460         int namelen;
  461         struct ucred *cred;
  462 {
  463         int hash;
  464         struct coda_cache *cncp;
  465 
  466         if (coda_nc_use == 0)                   /* Cache is off */
  467                 return((struct cnode *) 0);
  468 
  469         if (namelen > CODA_NC_NAMELEN) {
  470                 CODA_NC_DEBUG(CODA_NC_LOOKUP, 
  471                             myprintf(("long name lookup %s\n",name));)
  472                 coda_nc_stat.long_name_lookups++;               /* record stats */
  473                 return((struct cnode *) 0);
  474         }
  475 
  476         /* Use the hash function to locate the starting point,
  477            then the search routine to go down the list looking for
  478            the correct cred.
  479          */
  480 
  481         hash = CODA_NC_HASH(name, namelen, dcp);
  482         cncp = coda_nc_find(dcp, name, namelen, cred, hash);
  483         if (cncp == (struct coda_cache *) 0) {
  484                 coda_nc_stat.misses++;                  /* record miss */
  485                 return((struct cnode *) 0);
  486         }
  487 
  488         coda_nc_stat.hits++;
  489 
  490         /* put this entry at the end of the LRU */
  491         CODA_NC_LRUREM(cncp);
  492         CODA_NC_LRUINS(cncp, &coda_nc_lru);
  493 
  494         /* move it to the front of the hash chain */
  495         /* don't need to change the hash bucket length */
  496         CODA_NC_HSHREM(cncp);
  497         CODA_NC_HSHINS(cncp, &coda_nc_hash[hash]);
  498 
  499         CODA_NC_DEBUG(CODA_NC_LOOKUP, 
  500                 printf("lookup: dcp %p, name %s, cred %p = cp %p\n",
  501                         dcp, name, cred, cncp->cp); )
  502 
  503         return(cncp->cp);
  504 }
  505 
  506 static void
  507 coda_nc_remove(cncp, dcstat)
  508         struct coda_cache *cncp;
  509         enum dc_status dcstat;
  510 {
  511         /* 
  512          * remove an entry -- vrele(cncp->dcp, cp), crfree(cred),
  513          * remove it from it's hash chain, and
  514          * place it at the head of the lru list.
  515          */
  516         CODA_NC_DEBUG(CODA_NC_REMOVE,
  517                     myprintf(("coda_nc_remove %s from parent %lx.%lx.%lx\n",
  518                            cncp->name, (cncp->dcp)->c_fid.Volume,
  519                            (cncp->dcp)->c_fid.Vnode, (cncp->dcp)->c_fid.Unique));)
  520 
  521         CODA_NC_HSHREM(cncp);
  522 
  523         CODA_NC_HSHNUL(cncp);           /* have it be a null chain */
  524         if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->dcp)->v_usecount == 1)) {
  525                 cncp->dcp->c_flags |= C_PURGING;
  526         }
  527         vrele(CTOV(cncp->dcp)); 
  528 
  529         if ((dcstat == IS_DOWNCALL) && (CTOV(cncp->cp)->v_usecount == 1)) {
  530                 cncp->cp->c_flags |= C_PURGING;
  531         }
  532         vrele(CTOV(cncp->cp)); 
  533 
  534         crfree(cncp->cred); 
  535         bzero(DATA_PART(cncp),DATA_SIZE);
  536 
  537         /* Put the null entry just after the least-recently-used entry */
  538         /* LRU_TOP adjusts the pointer to point to the top of the structure. */
  539         CODA_NC_LRUREM(cncp);
  540         CODA_NC_LRUINS(cncp, LRU_TOP(coda_nc_lru.lru_prev));
  541 }
  542 
  543 /*
  544  * Remove all entries with a parent which has the input fid.
  545  */
  546 void
  547 coda_nc_zapParentfid(fid, dcstat)
  548         ViceFid *fid;
  549         enum dc_status dcstat;
  550 {
  551         /* To get to a specific fid, we might either have another hashing
  552            function or do a sequential search through the cache for the
  553            appropriate entries. The later may be acceptable since I don't
  554            think callbacks or whatever Case 1 covers are frequent occurences.
  555          */
  556         struct coda_cache *cncp, *ncncp;
  557         int i;
  558 
  559         if (coda_nc_use == 0)                   /* Cache is off */
  560                 return;
  561 
  562         CODA_NC_DEBUG(CODA_NC_ZAPPFID, 
  563                 myprintf(("ZapParent: fid 0x%lx, 0x%lx, 0x%lx \n",
  564                         fid->Volume, fid->Vnode, fid->Unique)); )
  565 
  566         coda_nc_stat.zapPfids++;
  567 
  568         for (i = 0; i < coda_nc_hashsize; i++) {
  569 
  570                 /*
  571                  * Need to save the hash_next pointer in case we remove the
  572                  * entry. remove causes hash_next to point to itself.
  573                  */
  574 
  575                 for (cncp = coda_nc_hash[i].hash_next; 
  576                      cncp != (struct coda_cache *)&coda_nc_hash[i];
  577                      cncp = ncncp) {
  578                         ncncp = cncp->hash_next;
  579                         if ((cncp->dcp->c_fid.Volume == fid->Volume) &&
  580                             (cncp->dcp->c_fid.Vnode == fid->Vnode)   &&
  581                             (cncp->dcp->c_fid.Unique == fid->Unique)) {
  582                                 coda_nc_hash[i].length--;      /* Used for tuning */
  583                                 coda_nc_remove(cncp, dcstat); 
  584                         }
  585                 }
  586         }
  587 }
  588 
  589 
  590 /*
  591  * Remove all entries which have the same fid as the input
  592  */
  593 void
  594 coda_nc_zapfid(fid, dcstat)
  595         ViceFid *fid;
  596         enum dc_status dcstat;
  597 {
  598         /* See comment for zapParentfid. This routine will be used
  599            if attributes are being cached. 
  600          */
  601         struct coda_cache *cncp, *ncncp;
  602         int i;
  603 
  604         if (coda_nc_use == 0)                   /* Cache is off */
  605                 return;
  606 
  607         CODA_NC_DEBUG(CODA_NC_ZAPFID, 
  608                 myprintf(("Zapfid: fid 0x%lx, 0x%lx, 0x%lx \n",
  609                         fid->Volume, fid->Vnode, fid->Unique)); )
  610 
  611         coda_nc_stat.zapFids++;
  612 
  613         for (i = 0; i < coda_nc_hashsize; i++) {
  614                 for (cncp = coda_nc_hash[i].hash_next; 
  615                      cncp != (struct coda_cache *)&coda_nc_hash[i];
  616                      cncp = ncncp) {
  617                         ncncp = cncp->hash_next;
  618                         if ((cncp->cp->c_fid.Volume == fid->Volume) &&
  619                             (cncp->cp->c_fid.Vnode == fid->Vnode)   &&
  620                             (cncp->cp->c_fid.Unique == fid->Unique)) {
  621                                 coda_nc_hash[i].length--;     /* Used for tuning */
  622                                 coda_nc_remove(cncp, dcstat); 
  623                         }
  624                 }
  625         }
  626 }
  627 
  628 /* 
  629  * Remove all entries which match the fid and the cred
  630  */
  631 void
  632 coda_nc_zapvnode(fid, cred, dcstat)     
  633         ViceFid *fid;
  634         struct ucred *cred;
  635         enum dc_status dcstat;
  636 {
  637         /* See comment for zapfid. I don't think that one would ever
  638            want to zap a file with a specific cred from the kernel.
  639            We'll leave this one unimplemented.
  640          */
  641         if (coda_nc_use == 0)                   /* Cache is off */
  642                 return;
  643 
  644         CODA_NC_DEBUG(CODA_NC_ZAPVNODE, 
  645                 myprintf(("Zapvnode: fid 0x%lx, 0x%lx, 0x%lx cred %p\n",
  646                           fid->Volume, fid->Vnode, fid->Unique, cred)); )
  647 
  648 }
  649 
  650 /*
  651  * Remove all entries which have the (dir vnode, name) pair
  652  */
  653 void
  654 coda_nc_zapfile(dcp, name, namelen)
  655         struct cnode *dcp;
  656         const char *name;
  657         int namelen;
  658 {
  659         /* use the hash function to locate the file, then zap all
  660            entries of it regardless of the cred.
  661          */
  662         struct coda_cache *cncp;
  663         int hash;
  664 
  665         if (coda_nc_use == 0)                   /* Cache is off */
  666                 return;
  667 
  668         CODA_NC_DEBUG(CODA_NC_ZAPFILE, 
  669                 myprintf(("Zapfile: dcp %p name %s \n",
  670                           dcp, name)); )
  671 
  672         if (namelen > CODA_NC_NAMELEN) {
  673                 coda_nc_stat.long_remove++;             /* record stats */
  674                 return;
  675         }
  676 
  677         coda_nc_stat.zapFile++;
  678 
  679         hash = CODA_NC_HASH(name, namelen, dcp);
  680         cncp = coda_nc_find(dcp, name, namelen, 0, hash);
  681 
  682         while (cncp) {
  683           coda_nc_hash[hash].length--;                 /* Used for tuning */
  684 
  685           coda_nc_remove(cncp, NOT_DOWNCALL);
  686           cncp = coda_nc_find(dcp, name, namelen, 0, hash);
  687         }
  688 }
  689 
  690 /* 
  691  * Remove all the entries for a particular user. Used when tokens expire.
  692  * A user is determined by his/her effective user id (id_uid).
  693  */
  694 void
  695 coda_nc_purge_user(uid, dcstat)
  696         vuid_t  uid;
  697         enum dc_status  dcstat;
  698 {
  699         /* 
  700          * I think the best approach is to go through the entire cache
  701          * via HASH or whatever and zap all entries which match the
  702          * input cred. Or just flush the whole cache.  It might be
  703          * best to go through on basis of LRU since cache will almost
  704          * always be full and LRU is more straightforward.  
  705          */
  706 
  707         struct coda_cache *cncp, *ncncp;
  708         int hash;
  709 
  710         if (coda_nc_use == 0)                   /* Cache is off */
  711                 return;
  712 
  713         CODA_NC_DEBUG(CODA_NC_PURGEUSER, 
  714                 myprintf(("ZapDude: uid %x\n", uid)); )
  715         coda_nc_stat.zapUsers++;
  716 
  717         for (cncp = CODA_NC_LRUGET(coda_nc_lru);
  718              cncp != (struct coda_cache *)(&coda_nc_lru);
  719              cncp = ncncp) {
  720                 ncncp = CODA_NC_LRUGET(*cncp);
  721 
  722                 if ((CODA_NC_VALID(cncp)) &&
  723                    ((cncp->cred)->cr_uid == uid)) {
  724                         /* Seems really ugly, but we have to decrement the appropriate
  725                            hash bucket length here, so we have to find the hash bucket
  726                            */
  727                         hash = CODA_NC_HASH(cncp->name, cncp->namelen, cncp->dcp);
  728                         coda_nc_hash[hash].length--;     /* For performance tuning */
  729 
  730                         coda_nc_remove(cncp, dcstat); 
  731                 }
  732         }
  733 }
  734 
  735 /*
  736  * Flush the entire name cache. In response to a flush of the Venus cache.
  737  */
  738 void
  739 coda_nc_flush(dcstat)
  740         enum dc_status dcstat;
  741 {
  742         /* One option is to deallocate the current name cache and
  743            call init to start again. Or just deallocate, then rebuild.
  744            Or again, we could just go through the array and zero the 
  745            appropriate fields. 
  746          */
  747         
  748         /* 
  749          * Go through the whole lru chain and kill everything as we go.
  750          * I don't use remove since that would rebuild the lru chain
  751          * as it went and that seemed unneccesary.
  752          */
  753         struct coda_cache *cncp;
  754         int i;
  755 
  756         if (coda_nc_use == 0)                   /* Cache is off */
  757                 return;
  758 
  759         coda_nc_stat.Flushes++;
  760 
  761         for (cncp = CODA_NC_LRUGET(coda_nc_lru);
  762              cncp != (struct coda_cache *)&coda_nc_lru;
  763              cncp = CODA_NC_LRUGET(*cncp)) {
  764                 if (CODA_NC_VALID(cncp)) {
  765 
  766                         CODA_NC_HSHREM(cncp);   /* only zero valid nodes */
  767                         CODA_NC_HSHNUL(cncp);
  768                         if ((dcstat == IS_DOWNCALL) 
  769                             && (CTOV(cncp->dcp)->v_usecount == 1))
  770                         {
  771                                 cncp->dcp->c_flags |= C_PURGING;
  772                         }
  773                         vrele(CTOV(cncp->dcp)); 
  774 
  775                         if (CTOV(cncp->cp)->v_flag & VTEXT) {
  776                             if (coda_vmflush(cncp->cp))
  777                                 CODADEBUG(CODA_FLUSH, 
  778                                          myprintf(("coda_nc_flush: (%lx.%lx.%lx) busy\n", cncp->cp->c_fid.Volume, cncp->cp->c_fid.Vnode, cncp->cp->c_fid.Unique)); )
  779                         }
  780 
  781                         if ((dcstat == IS_DOWNCALL) 
  782                             && (CTOV(cncp->cp)->v_usecount == 1))
  783                         {
  784                                 cncp->cp->c_flags |= C_PURGING;
  785                         }
  786                         vrele(CTOV(cncp->cp));  
  787 
  788                         crfree(cncp->cred); 
  789                         bzero(DATA_PART(cncp),DATA_SIZE);
  790                 }
  791         }
  792 
  793         for (i = 0; i < coda_nc_hashsize; i++)
  794           coda_nc_hash[i].length = 0;
  795 }
  796 
  797 /*
  798  * Debugging routines
  799  */
  800 
  801 /* 
  802  * This routine should print out all the hash chains to the console.
  803  */
  804 void
  805 print_coda_nc(void)
  806 {
  807         int hash;
  808         struct coda_cache *cncp;
  809 
  810         for (hash = 0; hash < coda_nc_hashsize; hash++) {
  811                 myprintf(("\nhash %d\n",hash));
  812 
  813                 for (cncp = coda_nc_hash[hash].hash_next; 
  814                      cncp != (struct coda_cache *)&coda_nc_hash[hash];
  815                      cncp = cncp->hash_next) {
  816                         myprintf(("cp %p dcp %p cred %p name %s\n",
  817                                   cncp->cp, cncp->dcp,
  818                                   cncp->cred, cncp->name));
  819                      }
  820         }
  821 }
  822 
  823 void
  824 coda_nc_gather_stats(void)
  825 {
  826     int i, max = 0, sum = 0, temp, zeros = 0, ave, n;
  827 
  828         for (i = 0; i < coda_nc_hashsize; i++) {
  829           if (coda_nc_hash[i].length) {
  830             sum += coda_nc_hash[i].length;
  831           } else {
  832             zeros++;
  833           }
  834 
  835           if (coda_nc_hash[i].length > max)
  836             max = coda_nc_hash[i].length;
  837         }
  838 
  839         /*
  840          * When computing the Arithmetic mean, only count slots which 
  841          * are not empty in the distribution.
  842          */
  843         coda_nc_stat.Sum_bucket_len = sum;
  844         coda_nc_stat.Num_zero_len = zeros;
  845         coda_nc_stat.Max_bucket_len = max;
  846 
  847         if ((n = coda_nc_hashsize - zeros) > 0) 
  848           ave = sum / n;
  849         else
  850           ave = 0;
  851 
  852         sum = 0;
  853         for (i = 0; i < coda_nc_hashsize; i++) {
  854           if (coda_nc_hash[i].length) {
  855             temp = coda_nc_hash[i].length - ave;
  856             sum += temp * temp;
  857           }
  858         }
  859         coda_nc_stat.Sum2_bucket_len = sum;
  860 }
  861 
  862 /*
  863  * The purpose of this routine is to allow the hash and cache sizes to be
  864  * changed dynamically. This should only be used in controlled environments,
  865  * it makes no effort to lock other users from accessing the cache while it
  866  * is in an improper state (except by turning the cache off).
  867  */
  868 int
  869 coda_nc_resize(hashsize, heapsize, dcstat)
  870      int hashsize, heapsize;
  871      enum dc_status dcstat;
  872 {
  873     if ((hashsize % 2) || (heapsize % 2)) { /* Illegal hash or cache sizes */
  874         return(EINVAL);
  875     }                 
  876     
  877     coda_nc_use = 0;                       /* Turn the cache off */
  878     
  879     coda_nc_flush(dcstat);                 /* free any cnodes in the cache */
  880     
  881     /* WARNING: free must happen *before* size is reset */
  882     CODA_FREE(coda_nc_heap,TOTAL_CACHE_SIZE);
  883     CODA_FREE(coda_nc_hash,TOTAL_HASH_SIZE);
  884     
  885     coda_nc_hashsize = hashsize;
  886     coda_nc_size = heapsize;
  887     
  888     coda_nc_init();                        /* Set up a cache with the new size */
  889     
  890     coda_nc_use = 1;                       /* Turn the cache back on */
  891     return(0);
  892 }
  893 
  894 #ifdef  DEBUG
  895 char coda_nc_name_buf[CODA_MAXNAMLEN+1];
  896 
  897 void
  898 coda_nc_name(struct cnode *cp)
  899 {
  900         struct coda_cache *cncp, *ncncp;
  901         int i;
  902 
  903         if (coda_nc_use == 0)                   /* Cache is off */
  904                 return;
  905 
  906         for (i = 0; i < coda_nc_hashsize; i++) {
  907                 for (cncp = coda_nc_hash[i].hash_next; 
  908                      cncp != (struct coda_cache *)&coda_nc_hash[i];
  909                      cncp = ncncp) {
  910                         ncncp = cncp->hash_next;
  911                         if (cncp->cp == cp) {
  912                                 bcopy(cncp->name, coda_nc_name_buf, cncp->namelen);
  913                                 coda_nc_name_buf[cncp->namelen] = 0;
  914                                 printf(" is %s (%p,%p)@%p",
  915                                         coda_nc_name_buf, cncp->cp, cncp->dcp, cncp);
  916                         }
  917 
  918                 }
  919         }
  920 }
  921 #endif

Cache object: e31ebd9564a6bde2ade5f4c16acf074c


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