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

Cache object: e292c722657f386aa3e3472a482a9c24


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