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

Cache object: 48b84d5b278150b0f29a3180bd484fa1


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