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

Cache object: 40255a4d8d2560ce2255577523d407fa


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