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  -  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_namecache.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
   30  * $FreeBSD: releng/5.0/sys/coda/coda_namecache.c 103937 2002-09-25 02:33:29Z jeff $
   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 filesystem at Carnegie Mellon University.
   44  * Contributers include David Steere, James Kistler, and M. Satyanarayanan.
   45  */
   46 
   47 /*
   48  * This module contains the routines to implement the CODA name cache. The
   49  * purpose of this cache is to reduce the cost of translating pathnames 
   50  * into Vice FIDs. Each entry in the cache contains the name of the file,
   51  * the vnode (FID) of the parent directory, and the cred structure of the
   52  * user accessing the file.
   53  *
   54  * The first time a file is accessed, it is looked up by the local Venus
   55  * which first insures that the user has access to the file. In addition
   56  * we are guaranteed that Venus will invalidate any name cache entries in
   57  * case the user no longer should be able to access the file. For these
   58  * reasons we do not need to keep access list information as well as a
   59  * cred structure for each entry.
   60  *
   61  * The table can be accessed through the routines cnc_init(), cnc_enter(),
   62  * cnc_lookup(), cnc_rmfidcred(), cnc_rmfid(), cnc_rmcred(), and cnc_purge().
   63  * There are several other routines which aid in the implementation of the
   64  * hash table.
   65  */
   66 
   67 /*
   68  * NOTES: rvb@cs
   69  * 1.   The name cache holds a reference to every vnode in it.  Hence files can not be
   70  *       closed or made inactive until they are released.
   71  * 2.   coda_nc_name(cp) was added to get a name for a cnode pointer for debugging.
   72  * 3.   coda_nc_find() has debug code to detect when entries are stored with different
   73  *       credentials.  We don't understand yet, if/how entries are NOT EQ but still
   74  *       EQUAL
   75  * 4.   I wonder if this name cache could be replace by the vnode name cache.
   76  *      The latter has no zapping functions, so probably not.
   77  */
   78 
   79 #include <sys/param.h>
   80 #include <sys/systm.h>
   81 #include <sys/errno.h>
   82 #include <sys/lock.h>
   83 #include <sys/malloc.h>
   84 #include <sys/mutex.h>
   85 #include <sys/ucred.h>
   86 
   87 #include <vm/vm.h>
   88 #include <vm/vm_object.h>
   89 
   90 #include <coda/coda.h>
   91 #include <coda/cnode.h>
   92 #include <coda/coda_namecache.h>
   93 
   94 #ifdef  DEBUG
   95 #include <coda/coda_vnops.h>
   96 #endif
   97 
   98 /* 
   99  * Declaration of the name cache data structure.
  100  */
  101 
  102 int     coda_nc_use = 1;                         /* Indicate use of CODA Name Cache */
  103 int     coda_nc_size = CODA_NC_CACHESIZE;        /* size of the cache */
  104 int     coda_nc_hashsize = CODA_NC_HASHSIZE; /* size of the primary hash */
  105 
  106 struct  coda_cache *coda_nc_heap;       /* pointer to the cache entries */
  107 struct  coda_hash  *coda_nc_hash;       /* hash table of coda_cache pointers */
  108 struct  coda_lru   coda_nc_lru;         /* head of lru chain */
  109 
  110 struct coda_nc_statistics coda_nc_stat; /* Keep various stats */
  111 
  112 /* 
  113  * for testing purposes
  114  */
  115 int coda_nc_debug = 0;
  116 
  117 /*
  118  * Entry points for the CODA Name Cache
  119  */
  120 static struct coda_cache *coda_nc_find(struct cnode *dcp, const char *name, int namelen,
  121         struct ucred *cred, int hash);
  122 static void coda_nc_remove(struct coda_cache *cncp, enum dc_status dcstat);
  123 
  124 /*  
  125  * Initialize the cache, the LRU structure and the Hash structure(s)
  126  */
  127 
  128 #define TOTAL_CACHE_SIZE        (sizeof(struct coda_cache) * coda_nc_size)
  129 #define TOTAL_HASH_SIZE         (sizeof(struct coda_hash)  * coda_nc_hashsize)
  130 
  131 int coda_nc_initialized = 0;      /* Initially the cache has not been initialized */
  132 
  133 void
  134 coda_nc_init(void)
  135 {
  136     int i;
  137 
  138     /* zero the statistics structure */
  139     
  140     bzero(&coda_nc_stat, (sizeof(struct coda_nc_statistics)));
  141 
  142 #ifdef  CODA_VERBOSE
  143     printf("CODA NAME CACHE: CACHE %d, HASH TBL %d\n", CODA_NC_CACHESIZE, CODA_NC_HASHSIZE);
  144 #endif
  145     CODA_ALLOC(coda_nc_heap, struct coda_cache *, TOTAL_CACHE_SIZE);
  146     CODA_ALLOC(coda_nc_hash, struct coda_hash *, TOTAL_HASH_SIZE);
  147     
  148     coda_nc_lru.lru_next = 
  149         coda_nc_lru.lru_prev = (struct coda_cache *)LRU_PART(&coda_nc_lru);
  150     
  151     
  152     for (i=0; i < coda_nc_size; i++) {  /* initialize the heap */
  153         CODA_NC_LRUINS(&coda_nc_heap[i], &coda_nc_lru);
  154         CODA_NC_HSHNUL(&coda_nc_heap[i]);
  155         coda_nc_heap[i].cp = coda_nc_heap[i].dcp = (struct cnode *)0;
  156     }
  157     
  158     for (i=0; i < coda_nc_hashsize; i++) {      /* initialize the hashtable */
  159         CODA_NC_HSHNUL((struct coda_cache *)&coda_nc_hash[i]);
  160     }
  161     
  162     coda_nc_initialized++;
  163 }
  164 
  165 /*
  166  * Auxillary routines -- shouldn't be entry points
  167  */
  168 
  169 static struct coda_cache *
  170 coda_nc_find(dcp, name, namelen, cred, hash)
  171         struct cnode *dcp;
  172         const char *name;
  173         int namelen;
  174         struct ucred *cred;
  175         int hash;
  176 {
  177         /* 
  178          * hash to find the appropriate bucket, look through the chain
  179          * for the right entry (especially right cred, unless cred == 0) 
  180          */
  181         struct coda_cache *cncp;
  182         int count = 1;
  183 
  184         CODA_NC_DEBUG(CODA_NC_FIND, 
  185                     myprintf(("coda_nc_find(dcp %p, name %s, len %d, cred %p, hash %d\n",
  186                            dcp, name, namelen, cred, hash));)
  187 
  188         for (cncp = coda_nc_hash[hash].hash_next; 
  189              cncp != (struct coda_cache *)&coda_nc_hash[hash];
  190              cncp = cncp->hash_next, count++) 
  191         {
  192 
  193             if ((CODA_NAMEMATCH(cncp, name, namelen, dcp)) &&
  194                 ((cred == 0) || (cncp->cred == cred))) 
  195             { 
  196                 /* compare cr_uid instead */
  197                 coda_nc_stat.Search_len += count;
  198                 return(cncp);
  199             }
  200 #ifdef  DEBUG
  201             else if (CODA_NAMEMATCH(cncp, name, namelen, dcp)) {
  202                 printf("coda_nc_find: name %s, new cred = %p, cred = %p\n",
  203                         name, cred, cncp->cred);
  204                 printf("nref %d, nuid %d, ngid %d // oref %d, ocred %d, ogid %d\n",
  205                         cred->cr_ref, cred->cr_uid, cred->cr_gid,
  206                         cncp->cred->cr_ref, cncp->cred->cr_uid, cncp->cred->cr_gid);
  207                 print_cred(cred);
  208                 print_cred(cncp->cred);
  209             }
  210 #endif
  211         }
  212 
  213         return((struct coda_cache *)0);
  214 }
  215 
  216 /*
  217  * Enter a new (dir cnode, name) pair into the cache, updating the
  218  * LRU and Hash as needed.
  219  */
  220 void
  221 coda_nc_enter(dcp, name, namelen, cred, cp)
  222     struct cnode *dcp;
  223     const char *name;
  224     int namelen;
  225     struct ucred *cred;
  226     struct cnode *cp;
  227 {
  228     struct coda_cache *cncp;
  229     int hash;
  230     
  231     if (coda_nc_use == 0)                       /* Cache is off */
  232         return;
  233     
  234     CODA_NC_DEBUG(CODA_NC_ENTER, 
  235                 myprintf(("Enter: dcp %p cp %p name %s cred %p \n",
  236                        dcp, cp, name, cred)); )
  237         
  238     if (namelen > CODA_NC_NAMELEN) {
  239         CODA_NC_DEBUG(CODA_NC_ENTER, 
  240                     myprintf(("long name enter %s\n",name));)
  241             coda_nc_stat.long_name_enters++;    /* record stats */
  242         return;
  243     }
  244     
  245     hash = CODA_NC_HASH(name, namelen, dcp);
  246     cncp = coda_nc_find(dcp, name, namelen, cred, hash);
  247     if (cncp != (struct coda_cache *) 0) {      
  248         coda_nc_stat.dbl_enters++;              /* duplicate entry */
  249         return;
  250     }
  251     
  252     coda_nc_stat.enters++;              /* record the enters statistic */
  253     
  254     /* Grab the next element in the lru chain */
  255     cncp = CODA_NC_LRUGET(coda_nc_lru);
  256     
  257     CODA_NC_LRUREM(cncp);       /* remove it from the lists */
  258     
  259     if (CODA_NC_VALID(cncp)) {
  260         /* Seems really ugly, but we have to decrement the appropriate
  261            hash bucket length here, so we have to find the hash bucket
  262            */
  263         coda_nc_hash[CODA_NC_HASH(cncp->name, cncp->namelen, cncp->dcp)].length--;
  264         
  265         coda_nc_stat.lru_rm++;  /* zapped a valid entry */
  266         CODA_NC_HSHREM(cncp);
  267         vrele(CTOV(cncp->dcp)); 
  268         vrele(CTOV(cncp->cp));
  269         crfree(cncp->cred);
  270     }
  271     
  272     /*
  273      * Put a hold on the current vnodes and fill in the cache entry.
  274      */
  275     vref(CTOV(cp));
  276     vref(CTOV(dcp));
  277     cncp->dcp = dcp;
  278     cncp->cp = cp;
  279     cncp->namelen = namelen;
  280     cncp->cred = crhold(cred);
  281     
  282     bcopy(name, cncp->name, (unsigned)namelen);
  283     
  284     /* Insert into the lru and hash chains. */
  285     
  286     CODA_NC_LRUINS(cncp, &coda_nc_lru);
  287     CODA_NC_HSHINS(cncp, &coda_nc_hash[hash]);
  288     coda_nc_hash[hash].length++;                      /* Used for tuning */
  289     
  290     CODA_NC_DEBUG(CODA_NC_PRINTCODA_NC, print_coda_nc(); )
  291 }
  292 
  293 /*
  294  * Find the (dir cnode, name) pair in the cache, if it's cred
  295  * matches the input, return it, otherwise return 0
  296  */
  297 struct cnode *
  298 coda_nc_lookup(dcp, name, namelen, cred)
  299         struct cnode *dcp;
  300         const char *name;
  301         int namelen;
  302         struct ucred *cred;
  303 {
  304         int hash;
  305         struct coda_cache *cncp;
  306 
  307         if (coda_nc_use == 0)                   /* Cache is off */
  308                 return((struct cnode *) 0);
  309 
  310         if (namelen > CODA_NC_NAMELEN) {
  311                 CODA_NC_DEBUG(CODA_NC_LOOKUP, 
  312                             myprintf(("long name lookup %s\n",name));)
  313                 coda_nc_stat.long_name_lookups++;               /* record stats */
  314                 return((struct cnode *) 0);
  315         }
  316 
  317         /* Use the hash function to locate the starting point,
  318            then the search routine to go down the list looking for
  319            the correct cred.
  320          */
  321 
  322         hash = CODA_NC_HASH(name, namelen, dcp);
  323         cncp = coda_nc_find(dcp, name, namelen, cred, hash);
  324         if (cncp == (struct coda_cache *) 0) {
  325                 coda_nc_stat.misses++;                  /* record miss */
  326                 return((struct cnode *) 0);
  327         }
  328 
  329         coda_nc_stat.hits++;
  330 
  331         /* put this entry at the end of the LRU */
  332         CODA_NC_LRUREM(cncp);
  333         CODA_NC_LRUINS(cncp, &coda_nc_lru);
  334 
  335         /* move it to the front of the hash chain */
  336         /* don't need to change the hash bucket length */
  337         CODA_NC_HSHREM(cncp);
  338         CODA_NC_HSHINS(cncp, &coda_nc_hash[hash]);
  339 
  340         CODA_NC_DEBUG(CODA_NC_LOOKUP, 
  341                 printf("lookup: dcp %p, name %s, cred %p = cp %p\n",
  342                         dcp, name, cred, cncp->cp); )
  343 
  344         return(cncp->cp);
  345 }
  346 
  347 static void
  348 coda_nc_remove(cncp, dcstat)
  349         struct coda_cache *cncp;
  350         enum dc_status dcstat;
  351 {
  352         /* 
  353          * remove an entry -- vrele(cncp->dcp, cp), crfree(cred),
  354          * remove it from it's hash chain, and
  355          * place it at the head of the lru list.
  356          */
  357         CODA_NC_DEBUG(CODA_NC_REMOVE,
  358                     myprintf(("coda_nc_remove %s from parent %lx.%lx.%lx\n",
  359                            cncp->name, (cncp->dcp)->c_fid.Volume,
  360                            (cncp->dcp)->c_fid.Vnode, (cncp->dcp)->c_fid.Unique));)
  361 
  362         CODA_NC_HSHREM(cncp);
  363 
  364         CODA_NC_HSHNUL(cncp);           /* have it be a null chain */
  365         if ((dcstat == IS_DOWNCALL) && (vrefcnt(CTOV(cncp->dcp)) == 1)) {
  366                 cncp->dcp->c_flags |= C_PURGING;
  367         }
  368         vrele(CTOV(cncp->dcp)); 
  369 
  370         if ((dcstat == IS_DOWNCALL) && (vrefcnt(CTOV(cncp->cp)) == 1)) {
  371                 cncp->cp->c_flags |= C_PURGING;
  372         }
  373         vrele(CTOV(cncp->cp)); 
  374 
  375         crfree(cncp->cred); 
  376         bzero(DATA_PART(cncp),DATA_SIZE);
  377 
  378         /* Put the null entry just after the least-recently-used entry */
  379         /* LRU_TOP adjusts the pointer to point to the top of the structure. */
  380         CODA_NC_LRUREM(cncp);
  381         CODA_NC_LRUINS(cncp, LRU_TOP(coda_nc_lru.lru_prev));
  382 }
  383 
  384 /*
  385  * Remove all entries with a parent which has the input fid.
  386  */
  387 void
  388 coda_nc_zapParentfid(fid, dcstat)
  389         ViceFid *fid;
  390         enum dc_status dcstat;
  391 {
  392         /* To get to a specific fid, we might either have another hashing
  393            function or do a sequential search through the cache for the
  394            appropriate entries. The later may be acceptable since I don't
  395            think callbacks or whatever Case 1 covers are frequent occurences.
  396          */
  397         struct coda_cache *cncp, *ncncp;
  398         int i;
  399 
  400         if (coda_nc_use == 0)                   /* Cache is off */
  401                 return;
  402 
  403         CODA_NC_DEBUG(CODA_NC_ZAPPFID, 
  404                 myprintf(("ZapParent: fid 0x%lx, 0x%lx, 0x%lx \n",
  405                         fid->Volume, fid->Vnode, fid->Unique)); )
  406 
  407         coda_nc_stat.zapPfids++;
  408 
  409         for (i = 0; i < coda_nc_hashsize; i++) {
  410 
  411                 /*
  412                  * Need to save the hash_next pointer in case we remove the
  413                  * entry. remove causes hash_next to point to itself.
  414                  */
  415 
  416                 for (cncp = coda_nc_hash[i].hash_next; 
  417                      cncp != (struct coda_cache *)&coda_nc_hash[i];
  418                      cncp = ncncp) {
  419                         ncncp = cncp->hash_next;
  420                         if ((cncp->dcp->c_fid.Volume == fid->Volume) &&
  421                             (cncp->dcp->c_fid.Vnode == fid->Vnode)   &&
  422                             (cncp->dcp->c_fid.Unique == fid->Unique)) {
  423                                 coda_nc_hash[i].length--;      /* Used for tuning */
  424                                 coda_nc_remove(cncp, dcstat); 
  425                         }
  426                 }
  427         }
  428 }
  429 
  430 
  431 /*
  432  * Remove all entries which have the same fid as the input
  433  */
  434 void
  435 coda_nc_zapfid(fid, dcstat)
  436         ViceFid *fid;
  437         enum dc_status dcstat;
  438 {
  439         /* See comment for zapParentfid. This routine will be used
  440            if attributes are being cached. 
  441          */
  442         struct coda_cache *cncp, *ncncp;
  443         int i;
  444 
  445         if (coda_nc_use == 0)                   /* Cache is off */
  446                 return;
  447 
  448         CODA_NC_DEBUG(CODA_NC_ZAPFID, 
  449                 myprintf(("Zapfid: fid 0x%lx, 0x%lx, 0x%lx \n",
  450                         fid->Volume, fid->Vnode, fid->Unique)); )
  451 
  452         coda_nc_stat.zapFids++;
  453 
  454         for (i = 0; i < coda_nc_hashsize; i++) {
  455                 for (cncp = coda_nc_hash[i].hash_next; 
  456                      cncp != (struct coda_cache *)&coda_nc_hash[i];
  457                      cncp = ncncp) {
  458                         ncncp = cncp->hash_next;
  459                         if ((cncp->cp->c_fid.Volume == fid->Volume) &&
  460                             (cncp->cp->c_fid.Vnode == fid->Vnode)   &&
  461                             (cncp->cp->c_fid.Unique == fid->Unique)) {
  462                                 coda_nc_hash[i].length--;     /* Used for tuning */
  463                                 coda_nc_remove(cncp, dcstat); 
  464                         }
  465                 }
  466         }
  467 }
  468 
  469 /* 
  470  * Remove all entries which match the fid and the cred
  471  */
  472 void
  473 coda_nc_zapvnode(fid, cred, dcstat)     
  474         ViceFid *fid;
  475         struct ucred *cred;
  476         enum dc_status dcstat;
  477 {
  478         /* See comment for zapfid. I don't think that one would ever
  479            want to zap a file with a specific cred from the kernel.
  480            We'll leave this one unimplemented.
  481          */
  482         if (coda_nc_use == 0)                   /* Cache is off */
  483                 return;
  484 
  485         CODA_NC_DEBUG(CODA_NC_ZAPVNODE, 
  486                 myprintf(("Zapvnode: fid 0x%lx, 0x%lx, 0x%lx cred %p\n",
  487                           fid->Volume, fid->Vnode, fid->Unique, cred)); )
  488 
  489 }
  490 
  491 /*
  492  * Remove all entries which have the (dir vnode, name) pair
  493  */
  494 void
  495 coda_nc_zapfile(dcp, name, namelen)
  496         struct cnode *dcp;
  497         const char *name;
  498         int namelen;
  499 {
  500         /* use the hash function to locate the file, then zap all
  501            entries of it regardless of the cred.
  502          */
  503         struct coda_cache *cncp;
  504         int hash;
  505 
  506         if (coda_nc_use == 0)                   /* Cache is off */
  507                 return;
  508 
  509         CODA_NC_DEBUG(CODA_NC_ZAPFILE, 
  510                 myprintf(("Zapfile: dcp %p name %s \n",
  511                           dcp, name)); )
  512 
  513         if (namelen > CODA_NC_NAMELEN) {
  514                 coda_nc_stat.long_remove++;             /* record stats */
  515                 return;
  516         }
  517 
  518         coda_nc_stat.zapFile++;
  519 
  520         hash = CODA_NC_HASH(name, namelen, dcp);
  521         cncp = coda_nc_find(dcp, name, namelen, 0, hash);
  522 
  523         while (cncp) {
  524           coda_nc_hash[hash].length--;                 /* Used for tuning */
  525 
  526           coda_nc_remove(cncp, NOT_DOWNCALL);
  527           cncp = coda_nc_find(dcp, name, namelen, 0, hash);
  528         }
  529 }
  530 
  531 /* 
  532  * Remove all the entries for a particular user. Used when tokens expire.
  533  * A user is determined by his/her effective user id (id_uid).
  534  */
  535 void
  536 coda_nc_purge_user(uid, dcstat)
  537         vuid_t  uid;
  538         enum dc_status  dcstat;
  539 {
  540         /* 
  541          * I think the best approach is to go through the entire cache
  542          * via HASH or whatever and zap all entries which match the
  543          * input cred. Or just flush the whole cache.  It might be
  544          * best to go through on basis of LRU since cache will almost
  545          * always be full and LRU is more straightforward.  
  546          */
  547 
  548         struct coda_cache *cncp, *ncncp;
  549         int hash;
  550 
  551         if (coda_nc_use == 0)                   /* Cache is off */
  552                 return;
  553 
  554         CODA_NC_DEBUG(CODA_NC_PURGEUSER, 
  555                 myprintf(("ZapDude: uid %x\n", uid)); )
  556         coda_nc_stat.zapUsers++;
  557 
  558         for (cncp = CODA_NC_LRUGET(coda_nc_lru);
  559              cncp != (struct coda_cache *)(&coda_nc_lru);
  560              cncp = ncncp) {
  561                 ncncp = CODA_NC_LRUGET(*cncp);
  562 
  563                 if ((CODA_NC_VALID(cncp)) &&
  564                    ((cncp->cred)->cr_uid == uid)) {
  565                         /* Seems really ugly, but we have to decrement the appropriate
  566                            hash bucket length here, so we have to find the hash bucket
  567                            */
  568                         hash = CODA_NC_HASH(cncp->name, cncp->namelen, cncp->dcp);
  569                         coda_nc_hash[hash].length--;     /* For performance tuning */
  570 
  571                         coda_nc_remove(cncp, dcstat); 
  572                 }
  573         }
  574 }
  575 
  576 /*
  577  * Flush the entire name cache. In response to a flush of the Venus cache.
  578  */
  579 void
  580 coda_nc_flush(dcstat)
  581         enum dc_status dcstat;
  582 {
  583         /* One option is to deallocate the current name cache and
  584            call init to start again. Or just deallocate, then rebuild.
  585            Or again, we could just go through the array and zero the 
  586            appropriate fields. 
  587          */
  588         
  589         /* 
  590          * Go through the whole lru chain and kill everything as we go.
  591          * I don't use remove since that would rebuild the lru chain
  592          * as it went and that seemed unneccesary.
  593          */
  594         struct coda_cache *cncp;
  595         int i;
  596 
  597         if (coda_nc_use == 0)                   /* Cache is off */
  598                 return;
  599 
  600         coda_nc_stat.Flushes++;
  601 
  602         for (cncp = CODA_NC_LRUGET(coda_nc_lru);
  603              cncp != (struct coda_cache *)&coda_nc_lru;
  604              cncp = CODA_NC_LRUGET(*cncp)) {
  605                 if (CODA_NC_VALID(cncp)) {
  606 
  607                         CODA_NC_HSHREM(cncp);   /* only zero valid nodes */
  608                         CODA_NC_HSHNUL(cncp);
  609                         if ((dcstat == IS_DOWNCALL) 
  610                             && (vrefcnt(CTOV(cncp->dcp)) == 1))
  611                         {
  612                                 cncp->dcp->c_flags |= C_PURGING;
  613                         }
  614                         vrele(CTOV(cncp->dcp)); 
  615 
  616                         ASSERT_VOP_LOCKED(CTOV(cncp->cp), "coda_nc_flush");
  617                         if (CTOV(cncp->cp)->v_vflag & VV_TEXT) {
  618                             if (coda_vmflush(cncp->cp))
  619                                 CODADEBUG(CODA_FLUSH, 
  620                                          myprintf(("coda_nc_flush: (%lx.%lx.%lx) busy\n", cncp->cp->c_fid.Volume, cncp->cp->c_fid.Vnode, cncp->cp->c_fid.Unique)); )
  621                         }
  622 
  623                         if ((dcstat == IS_DOWNCALL) 
  624                             && (vrefcnt(CTOV(cncp->cp)) == 1))
  625                         {
  626                                 cncp->cp->c_flags |= C_PURGING;
  627                         }
  628                         vrele(CTOV(cncp->cp));  
  629 
  630                         crfree(cncp->cred); 
  631                         bzero(DATA_PART(cncp),DATA_SIZE);
  632                 }
  633         }
  634 
  635         for (i = 0; i < coda_nc_hashsize; i++)
  636           coda_nc_hash[i].length = 0;
  637 }
  638 
  639 /*
  640  * Debugging routines
  641  */
  642 
  643 /* 
  644  * This routine should print out all the hash chains to the console.
  645  */
  646 void
  647 print_coda_nc(void)
  648 {
  649         int hash;
  650         struct coda_cache *cncp;
  651 
  652         for (hash = 0; hash < coda_nc_hashsize; hash++) {
  653                 myprintf(("\nhash %d\n",hash));
  654 
  655                 for (cncp = coda_nc_hash[hash].hash_next; 
  656                      cncp != (struct coda_cache *)&coda_nc_hash[hash];
  657                      cncp = cncp->hash_next) {
  658                         myprintf(("cp %p dcp %p cred %p name %s\n",
  659                                   cncp->cp, cncp->dcp,
  660                                   cncp->cred, cncp->name));
  661                      }
  662         }
  663 }
  664 
  665 void
  666 coda_nc_gather_stats(void)
  667 {
  668     int i, max = 0, sum = 0, temp, zeros = 0, ave, n;
  669 
  670         for (i = 0; i < coda_nc_hashsize; i++) {
  671           if (coda_nc_hash[i].length) {
  672             sum += coda_nc_hash[i].length;
  673           } else {
  674             zeros++;
  675           }
  676 
  677           if (coda_nc_hash[i].length > max)
  678             max = coda_nc_hash[i].length;
  679         }
  680 
  681         /*
  682          * When computing the Arithmetic mean, only count slots which 
  683          * are not empty in the distribution.
  684          */
  685         coda_nc_stat.Sum_bucket_len = sum;
  686         coda_nc_stat.Num_zero_len = zeros;
  687         coda_nc_stat.Max_bucket_len = max;
  688 
  689         if ((n = coda_nc_hashsize - zeros) > 0) 
  690           ave = sum / n;
  691         else
  692           ave = 0;
  693 
  694         sum = 0;
  695         for (i = 0; i < coda_nc_hashsize; i++) {
  696           if (coda_nc_hash[i].length) {
  697             temp = coda_nc_hash[i].length - ave;
  698             sum += temp * temp;
  699           }
  700         }
  701         coda_nc_stat.Sum2_bucket_len = sum;
  702 }
  703 
  704 /*
  705  * The purpose of this routine is to allow the hash and cache sizes to be
  706  * changed dynamically. This should only be used in controlled environments,
  707  * it makes no effort to lock other users from accessing the cache while it
  708  * is in an improper state (except by turning the cache off).
  709  */
  710 int
  711 coda_nc_resize(hashsize, heapsize, dcstat)
  712      int hashsize, heapsize;
  713      enum dc_status dcstat;
  714 {
  715     if ((hashsize % 2) || (heapsize % 2)) { /* Illegal hash or cache sizes */
  716         return(EINVAL);
  717     }                 
  718     
  719     coda_nc_use = 0;                       /* Turn the cache off */
  720     
  721     coda_nc_flush(dcstat);                 /* free any cnodes in the cache */
  722     
  723     /* WARNING: free must happen *before* size is reset */
  724     CODA_FREE(coda_nc_heap,TOTAL_CACHE_SIZE);
  725     CODA_FREE(coda_nc_hash,TOTAL_HASH_SIZE);
  726     
  727     coda_nc_hashsize = hashsize;
  728     coda_nc_size = heapsize;
  729     
  730     coda_nc_init();                        /* Set up a cache with the new size */
  731     
  732     coda_nc_use = 1;                       /* Turn the cache back on */
  733     return(0);
  734 }
  735 
  736 #ifdef  DEBUG
  737 char coda_nc_name_buf[CODA_MAXNAMLEN+1];
  738 
  739 void
  740 coda_nc_name(struct cnode *cp)
  741 {
  742         struct coda_cache *cncp, *ncncp;
  743         int i;
  744 
  745         if (coda_nc_use == 0)                   /* Cache is off */
  746                 return;
  747 
  748         for (i = 0; i < coda_nc_hashsize; i++) {
  749                 for (cncp = coda_nc_hash[i].hash_next; 
  750                      cncp != (struct coda_cache *)&coda_nc_hash[i];
  751                      cncp = ncncp) {
  752                         ncncp = cncp->hash_next;
  753                         if (cncp->cp == cp) {
  754                                 bcopy(cncp->name, coda_nc_name_buf, cncp->namelen);
  755                                 coda_nc_name_buf[cncp->namelen] = 0;
  756                                 printf(" is %s (%p,%p)@%p",
  757                                         coda_nc_name_buf, cncp->cp, cncp->dcp, cncp);
  758                         }
  759 
  760                 }
  761         }
  762 }
  763 #endif

Cache object: 9cc3bb38b0b120b3092ff73bd67764cb


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