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

Cache object: 421ea4f94c8185754be465de34d6cdbf


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