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

Cache object: a9f365a0a51e0340c52156086bcc1eba


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