"Fossies" - the Fresh Open Source Software Archive

Member "linux-coda-6.9/linux2.0/namecache.c" (1 Dec 2009, 26015 Bytes) of package /linux/misc/old/linux-coda-6.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1990 Carnegie-Mellon University
    4  * Copyright (c) 1989 Carnegie-Mellon University
    5  * All rights reserved.  The CMU software License Agreement specifies
    6  * the terms and conditions for use and redistribution.
    7  */
    8 
    9 /*
   10  * This code was written for the Coda file system at Carnegie Mellon University.
   11  * Contributers include David Steere, James Kistler, and M. Satyanarayanan.
   12  * Modifications for Linux: Peter J. Braam
   13  */
   14 
   15 /*
   16  * HISTORY
   17  * coda_namecache.c,v
   18  * Revision 1.3  1996/11/08 18:06:09  bnoble
   19  * Minor changes in vnode operation signature, VOP_UPDATE signature, and
   20  * some newly defined bits in the include files.
   21  *
   22  * Revision 1.2  1996/01/02 16:56:50  bnoble
   23  * Added support for Coda MiniCache and raw inode calls (final commit)
   24  *
   25  * Revision 1.1.2.1  1995/12/20 01:57:15  bnoble
   26  * Added CFS-specific files
   27  *
   28  * Revision 3.1.1.1  1995/03/04  19:07:57  bnoble
   29  * Branch for NetBSD port revisions
   30  *
   31  * Revision 3.1  1995/03/04  19:07:56  bnoble
   32  * Bump to major revision 3 to prepare for NetBSD port
   33  *
   34  * Revision 2.3  1994/10/14  09:57:54  dcs
   35  * Made changes 'cause sun4s have braindead compilers
   36  *
   37  * Revision 2.2  94/08/28  19:37:35  luqi
   38  * Add a new CODA_REPLACE call to allow venus to replace a ViceFid in the
   39  * mini-cache. 
   40  * 
   41  * In "linux/coda.h":
   42  * Add CODA_REPLACE decl.
   43  * 
   44  * In "coda_namecache.c":
   45  * Add routine cfsnc_replace.
   46  * 
   47  * In "coda_subr.c":
   48  * Add case-statement to process CODA_REPLACE.
   49  * 
   50  * In "cfsnc.h":
   51  * Add decl for CFSNC_REPLACE.
   52  * 
   53  * 
   54  * Revision 2.1  94/07/21  16:25:15  satya
   55  * Conversion to C++ 3.0; start of Coda Release 2.0
   56  *
   57  * Revision 1.2  92/10/27  17:58:21  lily
   58  * merge kernel/latest and alpha/src/cfs
   59  * 
   60  * Revision 2.3  92/09/30  14:16:20  mja
   61  *  call coda_flush instead of calling inode_uncache_try directly 
   62  *  (from dcs). Also...
   63  * 
   64  *  Substituted rvb's history blurb so that we agree with Mach 2.5 sources.
   65  *  [91/02/09            jjk]
   66  * 
   67  *  Added contributors blurb.
   68  *  [90/12/13            jjk]
   69  * 
   70  * Revision 2.2  90/07/05  11:26:30  mrt
   71  *  Created for the Coda File System.
   72  *  [90/05/23            dcs]
   73  * 
   74  * Revision 1.3  90/05/31  17:01:24  dcs
   75  * Prepare for merge with facilities kernel.
   76  * 
   77  * 
   78  */
   79 
   80 /*
   81  * This module contains the routines to implement the CFS name cache. The
   82  * purpose of this cache is to reduce the cost of translating pathnames 
   83  * into Vice FIDs. Each entry in the cache contains the name of the file,
   84  * the vnode (FID) of the parent directory, and the cred structure of the
   85  * user accessing the file.
   86  *
   87  * The first time a file is accessed, it is looked up by the local Venus
   88  * which first insures that the user has access to the file. In addition
   89  * we are guaranteed that Venus will invalidate any name cache entries in
   90  * case the user no longer should be able to access the file. For these
   91  * reasons we do not need to keep access list information as well as a
   92  * cred structure for each entry.
   93  *
   94  * The table can be accessed through the routines cnc_init(), cnc_enter(),
   95  * cnc_lookup(), cnc_rmfidcred(), cnc_rmfid(), cnc_rmcred(), and cnc_purge().
   96  * There are several other routines which aid in the implementation of the
   97  * hash table.
   98  */
   99 
  100 #include <linux/types.h>
  101 #include <linux/kernel.h>
  102 #include <linux/sched.h>
  103 #include <linux/fs.h>
  104 #include <linux/stat.h>
  105 #include <linux/errno.h>
  106 #include <linux/locks.h>
  107 #include <asm/segment.h>
  108 #include <linux/string.h>
  109 
  110 #include "linux/coda.h"
  111 #include "coda_linux.h"
  112 #include "cnode.h"
  113 #include "namecache.h"
  114 
  115 
  116 static struct cfscache * cfsnc_find(struct cnode *dcp, const char * name, int namelen, int hash);
  117 static void cfsnc_remove(struct cfscache *cncp);
  118 static inline int  nchash(const char *, int, struct cnode *);
  119 static inline int ncmatch(struct cfscache *, const char *, int, 
  120                           struct cnode *);
  121 static inline void hashins(struct cfscache *a, struct cfscache *pred);
  122 static inline void hashrem(struct cfscache *a);
  123 static inline void hashnull(struct cfscache *);
  124 static inline void lrurem(struct cfscache *a);
  125 static inline void lruins(struct cfscache *a, struct cfscache *pred);
  126 static void cfsnc_gather_stats(void);
  127 
  128 
  129 /* externals */
  130 extern int coda_fideq(ViceFid *fid1, ViceFid *fid2);
  131 extern int coda_debug;
  132 extern int coda_print_entry;
  133 extern struct super_block *coda_super_block;
  134 
  135 
  136 
  137 /* 
  138  * Declaration of the name cache data structure.
  139  */
  140 
  141 int     cfsnc_use = 1;           /* Indicate use of CFS Name Cache */
  142 int cfsnc_size = CFSNC_CACHESIZE;    /* size of the cache */
  143 int cfsnc_hashsize = CFSNC_HASHSIZE; /* size of the primary hash */
  144 int     cfsnc_flushme = 0;
  145 int     cfsnc_procsize = 0;
  146 static  int cfsnc_force = 0;
  147 
  148 struct cfshash {
  149     struct cfscache *hash_next, *hash_prev;
  150     int              length;
  151 };
  152 
  153 struct cfslruhead {
  154         struct cfscache *dummy1, *dummy2;
  155         struct cfscache *lru_next, *lru_prev;
  156 };
  157 
  158 struct  cfscache *cfsncheap;    /* pointer to the cache entries */
  159 struct  cfshash  *cfsnchash;    /* hash table of cfscache pointers */
  160 struct  cfslruhead  cfsnc_lru;  /* head of lru chain; prev = lru */
  161 
  162 struct cfsnc_statistics cfsnc_stat; /* Keep various stats */
  163 
  164 #define TOTAL_CACHE_SIZE    (sizeof(struct cfscache) * cfsnc_size)
  165 #define TOTAL_HASH_SIZE     (sizeof(struct cfshash)  * cfsnc_hashsize)
  166 int cfsnc_initialized = 0;      /* Initially the cache has not been initialized */
  167 
  168 /* 
  169  * for testing purposes
  170  */
  171 int cfsnc_debug = 1;
  172 
  173 
  174 /*
  175  * Auxillary routines -- shouldn't be entry points
  176  */
  177 
  178 
  179 /*
  180  * Hash function for the primary hash.
  181  * First try -- (first + last letters + length + (int)cp) mod size
  182  * 2nd try -- same, except dir fid.vnode instead of cp
  183  */
  184 static inline int  
  185 nchash(const char *name, int namelen, struct cnode *cp)
  186 {
  187     return ((name[0] + name[namelen-1] + 
  188              namelen + (int)(CTOI(cp)->i_ino)) & (cfsnc_hashsize-1));   
  189 }
  190 
  191 /* matching function */
  192 static inline int ncmatch(struct cfscache *cp, const char *name, int namelen,
  193                           struct cnode *dcp)
  194 {
  195     if ( !dcp || !cp || !cp->dcp ) {
  196         printk("**ncmath NULL: dcp %p, cp %p, cp->dcp %p\n", 
  197            dcp, cp, cp->dcp);
  198         return 0;
  199     }
  200     return  ((namelen == cp->namelen) && 
  201          (dcp == cp->dcp) && 
  202          (memcmp(cp->name,name,namelen) == 0));
  203 }
  204 
  205 /* insert  a  behind  pred */
  206 static inline void hashins(struct cfscache *a, struct cfscache *pred)
  207 {
  208     a->hash_next = pred->hash_next;
  209     pred->hash_next->hash_prev= a;
  210     pred->hash_next = a;
  211     a->hash_prev = pred;
  212 }
  213 
  214 static inline void hashrem(struct cfscache *a) 
  215 {
  216     a->hash_prev->hash_next = a->hash_next;
  217     a->hash_next->hash_prev = a->hash_prev;
  218 }
  219 
  220 static inline void hashnull(struct cfscache *elem) {
  221     elem->hash_next = elem;
  222     elem->hash_prev = elem;
  223 }
  224 
  225 static inline void lrurem(struct cfscache *a) 
  226 {
  227     a->lru_prev->lru_next = a->lru_next;
  228     a->lru_next->lru_prev = a->lru_prev;
  229 }
  230 
  231 static inline void lruins(struct cfscache *a, struct cfscache *pred)
  232 {
  233     pred->lru_next->lru_prev= a;
  234     a->lru_next = pred->lru_next;
  235     
  236     a->lru_prev = pred;
  237     pred->lru_next = a;
  238 }
  239 
  240 static struct cfscache *
  241 cfsnc_find(struct cnode *dcp, const char * name, int namelen, int hash)
  242 {
  243     /* 
  244      * hash to find the appropriate bucket, look through the chain
  245      * for the right entry 
  246      */
  247     register struct cfscache *cncp;
  248     int count = 1;
  249     char pname[CODA_MAXNAMLEN];
  250 
  251     memcpy(pname, name, namelen);
  252     pname[namelen] = '\0';
  253 
  254     CDEBUG(D_CACHE, "dcp 0x%x, name %s, len %d, hash %d\n",
  255                (int)dcp, pname, namelen, hash);
  256 
  257     for (cncp  = cfsnchash[hash].hash_next; 
  258          cncp != (struct cfscache *)&cfsnchash[hash];
  259          cncp  = cncp->hash_next, count++) 
  260     {
  261 
  262         if (ncmatch(cncp, name, namelen, dcp))
  263         { 
  264         cfsnc_stat.Search_len += count;
  265         CDEBUG(D_CACHE, "dcp 0x%x,found.\n", (int) dcp);
  266         if ( namelen == 2 && name[0]=='.' && name[1]=='.' ) {
  267 CDEBUG(D_CACHE, "HIT: name %s, ino %ld, pino %ld\n", pname, CTOI(dcp)->i_ino,
  268        CTOI(cncp->cp)->i_ino);
  269         }
  270         return(cncp);
  271             
  272         }
  273     }
  274     CDEBUG(D_CACHE, "dcp 0x%x,not found.\n", (int) dcp);
  275     return((struct cfscache *)0);
  276 }
  277 
  278 static void
  279 cfsnc_remove(struct cfscache *cncp)
  280 {
  281     /* 
  282      * remove an entry -- VN_RELE(cncp->dcp, cp), crfree(cred),
  283      * remove it from it's hash chain, and
  284      * place it at the head of the lru list.
  285      */
  286     CDEBUG(D_CACHE, "remove %s from parent %lx.%lx.%lx\n",
  287            cncp->name, (cncp->dcp)->c_fid.Volume,
  288            (cncp->dcp)->c_fid.Vnode, (cncp->dcp)->c_fid.Unique);
  289 
  290     hashrem(cncp);
  291     hashnull(cncp);     /* have it be a null chain */
  292 
  293     VN_RELE(CTOI(cncp->dcp));
  294     VN_RELE(CTOI(cncp->cp)); 
  295     /* crfree(cncp->cred);  */
  296 
  297     memset(DATA_PART(cncp), 0 ,DATA_SIZE);
  298     cncp->cp = NULL;
  299     cncp->dcp = NULL;
  300 
  301     /* Put the null entry just after the least-recently-used entry */
  302     lrurem(cncp);
  303     lruins(cncp, cfsnc_lru.lru_prev);
  304 }
  305 
  306 
  307 /*
  308  * Entry points for the CFS Name Cache
  309  */
  310 
  311 /*  
  312  * Initialize the cache, the LRU structure and the Hash structure(s)
  313  */
  314 void
  315 cfsnc_init(void)
  316 {
  317     register int i;
  318 
  319     /* zero the statistics structure */
  320     cfsnc_procsize =  10000 * cfsnc_hashsize + cfsnc_size;
  321     memset(&cfsnc_stat, 0, (sizeof(struct cfsnc_statistics)));
  322     
  323     CODA_ALLOC(cfsncheap, struct cfscache *, TOTAL_CACHE_SIZE);
  324     CODA_ALLOC(cfsnchash, struct cfshash *, TOTAL_HASH_SIZE);
  325     
  326     cfsnc_lru.lru_next = cfsnc_lru.lru_prev = (struct cfscache *)&cfsnc_lru; 
  327     
  328     /* initialize the heap */
  329     for (i=0; i < cfsnc_size; i++) {    
  330     lruins(&cfsncheap[i], (struct cfscache *) &cfsnc_lru);
  331     hashnull(&cfsncheap[i]);
  332     cfsncheap[i].cp = cfsncheap[i].dcp = (struct cnode *)0;
  333     }
  334     
  335     for (i=0; i < cfsnc_hashsize; i++) {    /* initialize the hashtable */
  336     hashnull((struct cfscache *)&cfsnchash[i]);
  337     cfsnchash[i].length=0;  /* bucket length */
  338     }
  339     
  340     cfsnc_initialized = 1;
  341     CDEBUG(D_CACHE, "cfsnc_initialized is now 1.\n");
  342 }
  343 
  344 /*
  345  * Enter a new (dir cnode, name) pair into the cache, updating the
  346  * LRU and Hash as needed.
  347  */
  348 
  349 void
  350 cfsnc_enter(struct cnode *dcp, register const char *name, int namelen, struct cnode *cp)
  351 {
  352     register struct cfscache *cncp;
  353     register int hash;
  354     
  355     if (cfsnc_use == 0)         /* Cache is off */
  356     return;
  357     
  358     CDEBUG(D_CACHE, "dcp 0x%x cp 0x%x name %s, ind 0x%x \n",
  359        (int)dcp, (int)cp, name, (int)cp->c_vnode); 
  360     
  361     if (namelen > CFSNC_NAMELEN) {
  362         CDEBUG(D_CACHE, "long name enter %s\n",name);
  363         cfsnc_stat.long_name_enters++;  /* record stats */
  364     return;
  365     }
  366     
  367     hash = nchash(name, namelen, dcp);
  368     CDEBUG(D_CACHE, "Calling find with name %s, dcp %d, hash %d\n",
  369            name, (int) dcp, (int) hash);
  370 
  371     cncp = cfsnc_find(dcp, name, namelen, hash);
  372     if (cncp != (struct cfscache *) 0) {    
  373     printk("cfsnc_enter: Duplicate cache entry; tell Peter.\n");
  374     cfsnc_stat.dbl_enters++;        /* duplicate entry */
  375     return;
  376     }
  377     
  378     cfsnc_stat.enters++;        /* record the enters statistic */
  379     
  380     /* Grab the lru element in the lru chain */
  381     cncp = cfsnc_lru.lru_prev;
  382     
  383     lrurem(cncp);   /* remove it from the lists */
  384     
  385     /* if cncp is on hash list remove it */
  386     if ( CFSNC_VALID(cncp) ) {
  387     /* We have to decrement the appropriate hash bucket length
  388        here, so we have to find the hash bucket */
  389     cfsnchash[nchash(cncp->name, cncp->namelen, cncp->dcp)].length--;
  390     cfsnc_stat.lru_rm++;    /* zapped a valid entry */
  391     hashrem(cncp);
  392     VN_RELE(CTOI(cncp->dcp));
  393     VN_RELE(CTOI(cncp->cp));
  394     /* crfree(cncp->cred); */
  395     }
  396     /*
  397      * Put a hold on the current vnodes and fill in the cache entry.
  398      */
  399     VN_HOLD(CTOI(cp));
  400     VN_HOLD(CTOI(dcp));
  401     /* XXXX crhold(cred); */
  402     cncp->dcp = dcp;
  403     cncp->cp = cp;
  404     cncp->namelen = namelen;
  405     /* cncp->cred = cred; */
  406     
  407     memcpy(cncp->name, name, (unsigned)namelen);
  408     
  409     /* Insert into the lru and hash chains. */
  410     
  411     lruins(cncp, (struct cfscache *) &cfsnc_lru);
  412     hashins(cncp, (struct cfscache *)&cfsnchash[hash]);
  413     cfsnchash[hash].length++;                      /* Used for tuning */
  414     CDEBUG(D_CACHE, "Entering:\n");
  415     coda_print_ce(cncp);
  416 }
  417 
  418 /*
  419  * Find the (dir cnode, name) pair in the cache, if it's cred
  420  * matches the input, return it, otherwise return 0
  421  */
  422 
  423 struct cnode *
  424 cfsnc_lookup(struct cnode *dcp, register const char *name, int namelen)
  425 {
  426     register int hash;
  427     register struct cfscache *cncp;
  428         /* this should go into a callback funcntion for /proc/sys
  429            don't know how at the moment? */  
  430     if (cfsnc_flushme == 1) {
  431         cfsnc_flush();
  432         cfsnc_flushme = 0;
  433     }
  434     
  435     if (cfsnc_procsize != 10000*cfsnc_hashsize + cfsnc_size ) {
  436         int hsh = cfsnc_procsize/10000;
  437         int siz = cfsnc_procsize%10000;
  438         int rc;
  439         
  440         if ( (hsh > 1) && (siz > 2) ) {
  441             rc = cfsnc_resize(hsh, siz);
  442             if ( !rc ) {
  443                 printk("Coda:cache size (hash,size) (%d,%d)\n",
  444                     hsh, siz);
  445             } else {
  446                 printk("Coda: cache resize failed\n");
  447             }
  448         }
  449     }
  450 
  451     if (cfsnc_use == 0)         /* Cache is off */
  452         return((struct cnode *) 0);
  453 
  454     if (namelen > CFSNC_NAMELEN) {
  455             CDEBUG(D_CACHE,"long name lookup %s\n",name);
  456         cfsnc_stat.long_name_lookups++;     /* record stats */
  457         return((struct cnode *) 0);
  458     }
  459 
  460     /* Use the hash function to locate the starting point,
  461        then the search routine to go down the list looking for
  462        the correct cred.
  463      */
  464 
  465     hash = nchash(name, namelen, dcp);
  466     CDEBUG(D_CACHE, "Calling find with name %s, dcp %d, hash %d\n",
  467            name, (int) dcp, (int) hash);
  468     cncp = cfsnc_find(dcp, name, namelen, hash);
  469     if (cncp == (struct cfscache *) 0) {
  470         cfsnc_stat.misses++;            /* record miss */
  471         return((struct cnode *) 0);
  472     }
  473 
  474     cfsnc_stat.hits++;
  475 
  476     /* put this entry at the mru end of the LRU */
  477     lrurem(cncp);
  478     lruins(cncp, (struct cfscache *) &cfsnc_lru);
  479 
  480     /* move it to the front of the hash chain */
  481     /* don't need to change the hash bucket length */
  482     hashrem(cncp);
  483     hashins(cncp, (struct cfscache *) &cfsnchash[hash]);
  484 
  485     CDEBUG(D_CACHE, "lookup: dcp 0x%x, name %s,  cp 0x%x\n",
  486            (int) dcp, name,  (int) cncp->cp);
  487 
  488     return(cncp->cp);
  489 }
  490 
  491 /*
  492  * Remove all entries with a parent which has the input fid.
  493  */
  494 
  495 void
  496 cfsnc_zapParentfid(ViceFid *fid)
  497 {
  498     /* To get to a specific fid, we might either have another hashing
  499        function or do a sequential search through the cache for the
  500        appropriate entries. The later may be acceptable since I don't
  501        think callbacks or whatever Case 1 covers are frequent occurences.
  502      */
  503     register struct cfscache *cncp, *ncncp;
  504     register int i;
  505 
  506     if (cfsnc_use == 0)         /* Cache is off */
  507         return;
  508 
  509     CDEBUG(D_CACHE, " fid 0x%lx, 0x%lx, 0x%lx \n",
  510            fid->Volume, fid->Vnode, fid->Unique);
  511 
  512     cfsnc_stat.zapPfids++;
  513 
  514     for (i = 0; i < cfsnc_hashsize; i++) {
  515 
  516         /*
  517          * Need to save the hash_next pointer in case we remove the
  518          * entry. remove causes hash_next to point to itself.
  519          */
  520 
  521         for (cncp = cfsnchash[i].hash_next; 
  522              cncp != (struct cfscache *) &cfsnchash[i];
  523              cncp = ncncp) {
  524             ncncp = cncp->hash_next;
  525             if ( coda_fideq(&cncp->dcp->c_fid, fid) ) {
  526                     cfsnchash[i].length--;   /* Used for tuning */
  527                 cfsnc_remove(cncp); 
  528                 }
  529              }
  530     }
  531 }
  532 
  533 /*
  534  * Remove all entries which have the same fid as the input
  535  */
  536 void
  537 cfsnc_zapfid(ViceFid *fid)
  538 {
  539     /* See comment for zapParentfid. This routine will be used
  540        if attributes are being cached. 
  541      */
  542     register struct cfscache *cncp, *ncncp;
  543     register int i;
  544 
  545     if (cfsnc_use == 0)         /* Cache is off */
  546         return;
  547 
  548     CDEBUG(D_CACHE, "Zapfid: fid 0x%lx, 0x%lx, 0x%lx \n",
  549            fid->Volume, fid->Vnode, fid->Unique);
  550 
  551     cfsnc_stat.zapFids++;
  552 
  553     for (i = 0; i < cfsnc_hashsize; i++) {
  554         for (cncp = cfsnchash[i].hash_next; 
  555              cncp != (struct cfscache *) &cfsnchash[i];
  556              cncp = ncncp) {
  557             ncncp = cncp->hash_next;
  558             if (coda_fideq(&(cncp->cp->c_fid), fid)) {
  559                     CDEBUG(D_CACHE, "Found cncp: name %s\n", cncp->name);
  560                     cfsnchash[i].length--;   /* Used for tuning */
  561                 cfsnc_remove(cncp); 
  562                 }
  563              }
  564     }
  565 }
  566 
  567 
  568 /*
  569  * Remove all entries which have the (dir vnode, name) pair
  570  */
  571 void
  572 cfsnc_zapfile(struct cnode *dcp, register const char *name, int length)
  573 {
  574     /* use the hash function to locate the file, then zap all
  575        entries of it regardless of the cred.
  576      */
  577     register struct cfscache *cncp;
  578     int hash;
  579 
  580     if (cfsnc_use == 0)         /* Cache is off */
  581         return;
  582 
  583     CDEBUG(D_CACHE,"Zapfile: dcp 0x%x name %s \n",
  584            (int) dcp, name);
  585 
  586     if (length > CFSNC_NAMELEN) {
  587         cfsnc_stat.long_remove++;       /* record stats */
  588         return;
  589     }
  590 
  591     cfsnc_stat.zapFile++;
  592 
  593     hash = nchash(name, length,  dcp);
  594     /* remove entries: remember they might exist for more than a 
  595        single cred */
  596     while ( (cncp = cfsnc_find(dcp, name, length, hash)) != NULL ) {
  597       cfsnchash[hash].length--;       
  598       cfsnc_remove(cncp);
  599     }
  600 }
  601 
  602 /* 
  603  * Remove all the entries for a particular user. Used when tokens expire.
  604  * A user is determined by his/her effective user id (id_uid).
  605  */
  606 
  607 void
  608 cfsnc_purge_user(struct coda_cred *cred)
  609 {
  610     /* I think the best approach is to go through the entire cache
  611        via HASH or whatever and zap all entries which match the
  612        input cred. Or just flush the whole cache.
  613        It might be best to go through on basis of LRU since cache
  614        will almost always be full and LRU is more straightforward.
  615      */
  616 
  617     register struct cfscache *cncp;
  618     int hash;
  619 
  620     if (cfsnc_use == 0)         /* Cache is off */
  621         return;
  622 
  623     CDEBUG(D_CACHE,"ZapDude: uid %ld\n",cred->cr_uid);
  624     cfsnc_stat.zapUsers++;
  625 
  626     for (cncp = cfsnc_lru.lru_next;
  627          cncp != (struct cfscache *) &cfsnc_lru;
  628          cncp = cncp->lru_next) {
  629 
  630         if ((CFSNC_VALID(cncp)) &&
  631            ((cncp->cred)->cr_uid == cred->cr_uid)) {
  632                 /* Seems really ugly, but we have to decrement the appropriate
  633                hash bucket length here, so we have to find the hash bucket
  634                */
  635                 hash = nchash(cncp->name, cncp->namelen, cncp->dcp);
  636             cfsnchash[hash].length--;     /* For performance tuning */
  637 
  638             cfsnc_remove(cncp); 
  639         }
  640     }
  641 }
  642 
  643 /*
  644  * Flush the entire name cache. In response to a flush of the Venus cache.
  645  */
  646 
  647 void
  648 cfsnc_flush(void)
  649 {
  650     /* One option is to deallocate the current name cache and
  651        call init to start again. Or just deallocate, then rebuild.
  652        Or again, we could just go through the array and zero the 
  653        appropriate fields. 
  654      */
  655     
  656     /* 
  657      * Go through the whole lru chain and kill everything as we go.
  658      * I don't use remove since that would rebuild the lru chain
  659      * as it went and that seemed unneccesary.
  660      */
  661     register struct cfscache *cncp;
  662     int i;
  663 
  664     if ((cfsnc_use == 0 || cfsnc_initialized == 0) && (cfsnc_force == 0) )
  665         return;
  666 
  667     cfsnc_stat.Flushes++;
  668 
  669     for (cncp = cfsnc_lru.lru_next;
  670          cncp != (struct cfscache *) &cfsnc_lru;
  671          cncp = cncp->lru_next) {
  672         if ( CFSNC_VALID(cncp) ) {
  673             hashrem(cncp);  /* only zero valid nodes */
  674             hashnull(cncp);
  675             VN_RELE(CTOI(cncp->dcp));  
  676             VN_RELE(CTOI(cncp->cp));  
  677             /* crfree(cncp->cred);  */
  678             memset(DATA_PART(cncp), 0, DATA_SIZE);
  679         }
  680     }
  681 
  682     for (i = 0; i < cfsnc_hashsize; i++)
  683       cfsnchash[i].length = 0;
  684 }
  685 
  686 /*
  687  * This routine replaces a ViceFid in the name cache with another.
  688  * It is added to allow Venus during reintegration to replace 
  689  * locally allocated temp fids while disconnected with global fids 
  690  * even when the reference count on those fids are not zero.
  691  */
  692 void
  693 cfsnc_replace(ViceFid *f1, ViceFid *f2)
  694 {
  695         /* 
  696      * Replace f1 with f2 throughout the name cache
  697      */
  698     int hash;
  699     register struct cfscache *cncp;
  700 
  701     CDEBUG(D_CACHE, 
  702     "cfsnc_replace fid_1 = (%lx.%lx.%lx) and fid_2 = (%lx.%lx.%lx)\n",
  703            f1->Volume, f1->Vnode, f1->Unique, 
  704            f2->Volume, f2->Vnode, f2->Unique);
  705 
  706     for (hash = 0; hash < cfsnc_hashsize; hash++) {
  707         for (cncp = cfsnchash[hash].hash_next; 
  708              cncp != (struct cfscache *) &cfsnchash[hash];
  709              cncp = cncp->hash_next) {
  710                 if (!memcmp(&cncp->cp->c_fid, f1, sizeof(ViceFid))) {
  711                 memcpy(&cncp->cp->c_fid, f2, sizeof(ViceFid));
  712                 continue;   /* no need to check cncp->dcp now */
  713             }
  714                 if (!memcmp(&cncp->dcp->c_fid, f1, sizeof(ViceFid)))
  715                 memcpy(&cncp->dcp->c_fid, f2, sizeof(ViceFid));
  716              }
  717     }
  718 }
  719 
  720 /*
  721  * Debugging routines
  722  */
  723 
  724 /* 
  725  * This routine should print out all the hash chains to the console.
  726  */
  727 
  728 void
  729 print_cfsnc(void)
  730 {
  731     int hash;
  732     register struct cfscache *cncp;
  733 
  734     for (hash = 0; hash < cfsnc_hashsize; hash++) {
  735         printk("\nhash %d\n",hash);
  736 
  737         for (cncp = cfsnchash[hash].hash_next; 
  738              cncp != (struct cfscache *)&cfsnchash[hash];
  739              cncp = cncp->hash_next) {
  740             printk("cp 0x%x dcp 0x%x cred 0x%x name %s ino %d count %d dev %d\n",
  741                   (int)cncp->cp, (int)cncp->dcp,
  742                   (int)cncp->cred, cncp->name, CTOI(cncp->cp)->i_count, CTOI(cncp->cp)->i_count, CTOI(cncp->cp)->i_dev);
  743              }
  744     }
  745 }
  746 
  747 int
  748 cfsnc_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
  749 {
  750         int hash;
  751         int len=0;
  752         off_t pos=0;
  753         off_t begin;
  754     struct cfscache *cncp;
  755         char tmpbuf[80];
  756 
  757         if (offset < 80) 
  758               len += sprintf(buffer, "%-79s\n",
  759       "hash  len   volume    vnode   unique             name        ino       pino ct");
  760     if ( !cfsnc_initialized ) {
  761         *start = buffer;
  762         return len;
  763     }
  764         pos = 80;
  765     for (hash = 0; hash < cfsnc_hashsize; hash++) {
  766         for (cncp = cfsnchash[hash].hash_next; 
  767              cncp != (struct cfscache *)&cfsnchash[hash];
  768              cncp = cncp->hash_next) {
  769             pos += 80;
  770             if (pos < offset)
  771                                 continue;
  772             sprintf(tmpbuf, "%4d  %3d %8x %8x %8x %16s %10d %10d %2d", 
  773                 hash, cfsnchash[hash].length, (int) cncp->cp->c_fid.Volume, 
  774                 (int) cncp->cp->c_fid.Vnode, (int) cncp->cp->c_fid.Unique , cncp->name, 
  775                 CTOI(cncp->cp)->i_ino, 
  776                 CTOI(cncp->dcp)->i_ino, 
  777                 CTOI(cncp->cp)->i_count);
  778                         len += sprintf(buffer+len, "%-79s\n", tmpbuf);
  779                         if(len >= length)
  780                                 break;
  781                     }
  782                 if(len>= length)
  783                         break;
  784         }
  785         begin = len - (pos - offset);
  786         *start = buffer + begin;
  787         len -= begin;
  788         if(len>length)
  789                 len = length;
  790         return len;
  791 } 
  792 
  793 int
  794 cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy)
  795 {
  796         int len=0;
  797         off_t begin;
  798     
  799     cfsnc_gather_stats();
  800 
  801     /* this works as long as we are below 1024 characters! */    
  802     len += sprintf(buffer,"Coda minicache statistics\n\n");
  803     len += sprintf(buffer+len, "cfsnc_hits : %d\n", cfsnc_stat.hits);
  804     len += sprintf(buffer+len, "cfsnc_misses : %d\n", cfsnc_stat.misses);
  805     len += sprintf(buffer+len, "cfsnc_enters : %d\n", cfsnc_stat.enters);
  806     len += sprintf(buffer+len, "cfsnc_dbl_enters : %d\n", cfsnc_stat.dbl_enters);
  807     len += sprintf(buffer+len, "cfsnc_long_name_enters : %d\n", cfsnc_stat.long_name_enters);
  808     len += sprintf(buffer+len, "cfsnc_long_name_lookups : %d\n", cfsnc_stat.long_name_lookups);
  809     len += sprintf(buffer+len, "cfsnc_long_remove : %d\n", cfsnc_stat.long_remove);
  810     len += sprintf(buffer+len, "cfsnc_lru_rm : %d\n", cfsnc_stat.lru_rm);
  811     len += sprintf(buffer+len, "cfsnc_zapPfids : %d\n", cfsnc_stat.zapPfids);
  812     len += sprintf(buffer+len, "cfsnc_zapFids : %d\n", cfsnc_stat.zapFids);
  813     len += sprintf(buffer+len, "cfsnc_zapFile : %d\n", cfsnc_stat.zapFile);
  814     len += sprintf(buffer+len, "cfsnc_zapUsers : %d\n", cfsnc_stat.zapUsers);
  815     len += sprintf(buffer+len, "cfsnc_Flushes : %d\n", cfsnc_stat.Flushes);
  816     len += sprintf(buffer+len, "cfsnc_SumLen : %d\n", cfsnc_stat.Sum_bucket_len);
  817     len += sprintf(buffer+len, "cfsnc_Sum2Len : %d\n", cfsnc_stat.Sum2_bucket_len);
  818     len += sprintf(buffer+len,  "cfsnc_# 0 len : %d\n", cfsnc_stat.Num_zero_len);
  819     len += sprintf(buffer+len,  "cfsnc_MaxLen : %d\n", cfsnc_stat.Max_bucket_len);
  820     len += sprintf(buffer+len,  "cfsnc_SearchLen : %d\n", cfsnc_stat.Search_len);
  821         begin =  offset;
  822         *start = buffer + begin;
  823         len -= begin;
  824 
  825         if(len>length)
  826                 len = length;
  827     if (len< 0)
  828         len = 0;
  829         return len;
  830 } 
  831 
  832 
  833 
  834 void
  835 coda_print_ce(struct cfscache *ce) 
  836 {
  837 CDEBUG(D_CACHE, "cp 0x%x, dcp 0x%x, name %s, inod 0x%x, ino %d, count %d, dev %d\n",
  838         (int)ce->cp, (int)ce->dcp, ce->name, (int)CTOI(ce->cp),(int)CTOI(ce->cp)->i_ino,  CTOI(ce->cp)->i_count, CTOI(ce->cp)->i_dev);
  839 }
  840 
  841 static void
  842 cfsnc_gather_stats(void)
  843 {
  844     int i, max = 0, sum = 0, temp, zeros = 0, ave, n;
  845 
  846     for (i = 0; i < cfsnc_hashsize; i++) {
  847       if (cfsnchash[i].length) {
  848         sum += cfsnchash[i].length;
  849       } else {
  850         zeros++;
  851       }
  852 
  853       if (cfsnchash[i].length > max)
  854         max = cfsnchash[i].length;
  855     }
  856 
  857 /*
  858  * When computing the Arithmetic mean, only count slots which 
  859  * are not empty in the distribution.
  860  */
  861         cfsnc_stat.Sum_bucket_len = sum;
  862         cfsnc_stat.Num_zero_len = zeros;
  863         cfsnc_stat.Max_bucket_len = max;
  864 
  865     if ((n = cfsnc_hashsize - zeros) > 0) 
  866       ave = sum / n;
  867     else
  868       ave = 0;
  869 
  870     sum = 0;
  871     for (i = 0; i < cfsnc_hashsize; i++) {
  872       if (cfsnchash[i].length) {
  873         temp = cfsnchash[i].length - ave;
  874         sum += temp * temp;
  875       }
  876     }
  877         cfsnc_stat.Sum2_bucket_len = sum;
  878 }
  879 
  880 /*
  881  * The purpose of this routine is to allow the hash and cache sizes to be
  882  * changed dynamically. This should only be used in controlled environments,
  883  * it makes no effort to lock other users from accessing the cache while it
  884  * is in an improper state (except by turning the cache off).
  885  */
  886 int
  887 cfsnc_resize(int hashsize, int heapsize)
  888 {
  889     if ((hashsize % 2) || (heapsize % 2)) { /* Illegal hash or cache sizes */
  890     return(EINVAL);
  891     }                 
  892     
  893     cfsnc_use = 0;                       /* Turn the cache off */
  894     cfsnc_force = 1;                     /* otherwise we can't flush */
  895     
  896     cfsnc_flush();                       /* free any cnodes in the cache */
  897     cfsnc_force = 0;
  898     
  899     /* WARNING: free must happen *before* size is reset */
  900     CODA_FREE(cfsncheap,TOTAL_CACHE_SIZE);
  901     CODA_FREE(cfsnchash,TOTAL_HASH_SIZE);
  902     
  903     cfsnc_hashsize = hashsize;
  904     cfsnc_size = heapsize;
  905     
  906     cfsnc_init();                        /* Set up a cache with the new size */
  907     
  908     cfsnc_use = 1;                       /* Turn the cache back on */
  909     return(0);
  910 }
  911 
  912 
  913