237177eb9a8310353b32b1d128d27c058cd4ac41
[openafs.git] / src / WINNT / afsd / cm_dnlc.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11 **      This implements the directory to name cache lookup. 
12 **      Given a directory scache and a name, the dnlc returns the
13 **      vcache corresponding to the name. The vcache entries that 
14 **      exist in the dnlc are not refcounted. 
15 **
16 */
17
18 #include <afs/param.h>
19 #include <afs/stds.h>
20
21 #ifndef DJGPP
22 #include <windows.h>
23 #include <winsock2.h>
24 #endif /* !DJGPP */
25 #include <string.h>
26 #include <stdlib.h>
27 #include <osi.h>
28 #include "afsd.h"
29
30 osi_rwlock_t cm_dnlcLock;
31
32 static cm_dnlcstats_t dnlcstats;        /* dnlc statistics */
33 static int cm_useDnlc = 1;      /* yes, start using the dnlc */
34 static int cm_debugDnlc = 0;    /* debug dnlc */
35
36
37 /* Hash table invariants:
38  *     1.  If nameHash[i] is NULL, list is empty
39  *     2.  A single element in a hash bucket has itself as prev and next.
40  */
41 #ifndef DJGPP
42 #define dnlcNotify(x,debug){                    \
43                         HANDLE  hh;             \
44                         char *ptbuf[1];         \
45                         ptbuf[0] = x;           \
46                         if ( debug ) {          \
47                             hh = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);   \
48                             ReportEvent(hh,EVENTLOG_ERROR_TYPE,0,__LINE__,  \
49                                 NULL, 1, 0, ptbuf, NULL);                   \
50                             DeregisterEventSource(hh);                  \
51                         }                                               \
52                      }  
53 #else
54 #define dnlcNotify(x,debug)
55 #endif /* !DJGPP */
56
57 /* Must be called with cm_dnlcLock write locked */
58 static cm_nc_t * 
59 GetMeAnEntry() 
60 {
61     static unsigned int nameptr = 0; /* next bucket to pull something from */
62     cm_nc_t *tnc;
63     int j;
64   
65     if (cm_data.ncfreelist) 
66     {
67         tnc = cm_data.ncfreelist;
68         cm_data.ncfreelist = tnc->next;
69         return tnc;
70     }
71
72     for (j=0; j<NHSIZE+2; j++, nameptr++) 
73     {
74         if (nameptr >= NHSIZE) 
75             nameptr =0;
76         if (cm_data.nameHash[nameptr])
77             break;
78     }
79
80     tnc = cm_data.nameHash[nameptr];
81     if (!tnc)   
82     {
83         dnlcNotify("null tnc in GetMeAnEntry",1);
84         osi_Log0(afsd_logp,"null tnc in GetMeAnEntry");
85         return 0;
86     }
87
88     if (tnc->prev == tnc) 
89     {                   /* only thing in list, don't screw around */
90         cm_data.nameHash[nameptr] = (cm_nc_t *) 0;
91         return (tnc);
92     }
93
94     tnc = tnc->prev;            /* grab oldest one in this bucket */
95     tnc->next->prev = tnc->prev;/* remove it from list */
96     tnc->prev->next = tnc->next;
97
98     return (tnc);
99 }
100
101 static void 
102 InsertEntry(cm_nc_t *tnc)
103 {
104     unsigned int key; 
105     key = tnc->key & (NHSIZE -1);
106
107     if (!cm_data.nameHash[key]) 
108     {
109         cm_data.nameHash[key] = tnc;
110         tnc->next = tnc->prev = tnc;
111     }
112     else 
113     {
114         tnc->next = cm_data.nameHash[key];
115         tnc->prev = tnc->next->prev;
116         tnc->next->prev = tnc;
117         tnc->prev->next = tnc;
118         cm_data.nameHash[key] = tnc;
119     }
120 }
121
122
123 void 
124 cm_dnlcEnter ( cm_scache_t *adp,
125                char        *aname,
126                cm_scache_t *avc )
127 {
128     cm_nc_t *tnc;
129     unsigned int key, skey, new=0;
130     char *ts = aname;
131     int safety;
132
133     if (!cm_useDnlc)
134         return ;
135   
136     if ( cm_debugDnlc ) 
137         osi_Log3(afsd_logp,"cm_dnlcEnter dir %x name %s scache %x", 
138             adp, osi_LogSaveString(afsd_logp,aname), avc);
139
140     dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
141     if (ts - aname >= CM_AFSNCNAMESIZE) 
142         return ;
143     skey = key & (NHSIZE -1);
144
145     lock_ObtainWrite(&cm_dnlcLock);
146     dnlcstats.enters++;
147   
148     for (tnc = cm_data.nameHash[skey], safety=0; tnc; tnc = tnc->next, safety++ )
149         if ((tnc->dirp == adp) && (!strcmp(tnc->name, aname)))
150             break;                              /* preexisting entry */
151         else if ( tnc->next == cm_data.nameHash[skey])  /* end of list */
152         {
153             tnc = NULL;
154             break;
155         }
156         else if (safety > NCSIZE) 
157         {
158             dnlcstats.cycles++;
159             lock_ReleaseWrite(&cm_dnlcLock);
160
161             dnlcNotify("DNLC cycle",1);
162             if ( cm_debugDnlc )
163                 osi_Log0(afsd_logp, "DNLC cycle");
164             cm_dnlcPurge();
165             return;
166         }
167         
168     if ( !tnc )
169     {
170         new = 1;        /* entry does not exist, we are creating a new entry*/
171         tnc = GetMeAnEntry();
172     }
173     if ( tnc )
174     { 
175         tnc->dirp = adp;
176         tnc->vp = avc;
177         tnc->key = key;
178         memcpy (tnc->name, aname, ts-aname+1); /* include the NULL */
179
180         if ( new )      /* insert entry only if it is newly created */ 
181                 InsertEntry(tnc);
182
183     }
184     lock_ReleaseWrite(&cm_dnlcLock);
185
186     if ( !tnc)
187         cm_dnlcPurge();
188 }
189
190 /*
191 * if the scache entry is found, return it held
192 */
193 cm_scache_t *
194 cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
195 {
196     cm_scache_t * tvc;
197     unsigned int key, skey;
198     char* aname = sp->searchNamep;
199     char *ts = aname;
200     cm_nc_t * tnc, * tnc_begin;
201     int safety, match;
202   
203     if (!cm_useDnlc)
204         return 0;
205     if ( cm_debugDnlc ) 
206         osi_Log2(afsd_logp, "cm_dnlcLookup dir %x name %s", 
207                 adp, osi_LogSaveString(afsd_logp,aname));
208
209     dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
210     if (ts - aname >= CM_AFSNCNAMESIZE) 
211         return 0;
212
213     skey = key & (NHSIZE -1);
214
215     lock_ObtainRead(&cm_dnlcLock);
216     dnlcstats.lookups++;             /* Is a dnlcread lock sufficient? */
217
218     ts = 0;
219     tnc_begin = cm_data.nameHash[skey];
220     for ( tvc = (cm_scache_t *) 0, tnc = tnc_begin, safety=0; 
221           tnc; tnc = tnc->next, safety++ ) 
222     {
223         if (tnc->dirp == adp) 
224         {
225         if( cm_debugDnlc ) 
226             osi_Log1(afsd_logp,"Looking at [%s]",
227                      osi_LogSaveString(afsd_logp,tnc->name));
228
229             if ( sp->caseFold )         /* case insensitive */
230             {
231             match = cm_stricmp(tnc->name, aname);
232             if ( !match )       /* something matches */
233             {
234                 tvc = tnc->vp;
235                 ts = tnc->name;
236
237                 /* determine what type of match it is */
238                 if ( !strcmp(tnc->name, aname))
239                 {       
240                     /* exact match. */
241                     sp->ExactFound = 1;
242
243                     if( cm_debugDnlc )
244                         osi_Log1(afsd_logp,"DNLC found exact match [%s]",
245                                  osi_LogSaveString(afsd_logp,tnc->name));
246                     break;
247                 }
248                 else if ( cm_NoneUpper(tnc->name))
249                     sp->LCfound = 1;
250                 else if ( cm_NoneLower(tnc->name))
251                     sp->UCfound = 1;
252                 else    
253                     sp->NCfound = 1;
254                 /* Don't break here. We might find an exact match yet */
255             }
256             }
257             else                        /* case sensitive */
258             {
259             match = strcmp(tnc->name, aname);
260             if ( !match ) /* found a match */
261             {
262                 sp->ExactFound = 1;
263                 tvc = tnc->vp; 
264                 ts = tnc->name;
265                 break;
266             }
267             }
268         }
269         if (tnc->next == cm_data.nameHash[skey]) 
270     {                   /* end of list */
271             break;
272         }
273         else if (tnc->next == tnc_begin || safety > NCSIZE) 
274         {
275             dnlcstats.cycles++;
276             lock_ReleaseRead(&cm_dnlcLock);
277
278             dnlcNotify("DNLC cycle",1); 
279             if ( cm_debugDnlc ) 
280                 osi_Log0(afsd_logp, "DNLC cycle"); 
281             cm_dnlcPurge();
282             return(0);
283         }
284     }
285
286     if(cm_debugDnlc && ts) {
287         osi_Log3(afsd_logp, "DNLC matched [%s] for [%s] with vnode[%ld]",
288                  osi_LogSaveString(afsd_logp,ts),
289                  osi_LogSaveString(afsd_logp,aname),
290                  (long) tvc->fid.vnode);
291     }
292
293     if (!tvc) 
294         dnlcstats.misses++;     /* Is a dnlcread lock sufficient? */
295     else 
296     {
297         sp->found = 1;
298         sp->fid.vnode  = tvc->fid.vnode; 
299         sp->fid.unique = tvc->fid.unique;       
300     }
301     lock_ReleaseRead(&cm_dnlcLock);
302
303     if (tvc)
304         cm_HoldSCache(tvc);
305
306     if ( cm_debugDnlc && tvc ) 
307         osi_Log1(afsd_logp, "cm_dnlcLookup found %x", tvc);
308     
309     return tvc;
310 }
311
312
313 static int
314 RemoveEntry (cm_nc_t *tnc, unsigned int key)
315 {
316     if (!tnc->prev) /* things on freelist always have null prev ptrs */
317     {
318         dnlcNotify("Bogus dnlc freelist", 1);
319         osi_Log0(afsd_logp,"Bogus dnlc freelist");
320         return 1;   /* error */
321     }
322
323     if (tnc == tnc->next)  /* only one in list */
324         cm_data.nameHash[key] = (cm_nc_t *) 0;
325     else 
326     {
327         if (tnc == cm_data.nameHash[key])
328             cm_data.nameHash[key]  = tnc->next;
329         tnc->prev->next = tnc->next;
330         tnc->next->prev = tnc->prev;
331     }
332
333     memset(tnc, 0, sizeof(cm_nc_t));
334     tnc->magic = CM_DNLC_MAGIC;
335     return 0;     /* success */
336 }
337
338
339 void 
340 cm_dnlcRemove (cm_scache_t *adp, char *aname)
341 {
342     unsigned int key, skey, error=0;
343     int found= 0, safety;
344     char *ts = aname;
345     cm_nc_t *tnc, *tmp;
346   
347     if (!cm_useDnlc)
348         return ;
349
350     if ( cm_debugDnlc )
351         osi_Log2(afsd_logp, "cm_dnlcRemove dir %x name %s", 
352                 adp, osi_LogSaveString(afsd_logp,aname));
353
354     dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
355     if (ts - aname >= CM_AFSNCNAMESIZE) 
356         return ;
357
358     skey = key & (NHSIZE -1);
359     lock_ObtainWrite(&cm_dnlcLock);
360     dnlcstats.removes++;
361
362     for (tnc = cm_data.nameHash[skey], safety=0; tnc; safety++) 
363     {
364         if ( (tnc->dirp == adp) && (tnc->key == key) 
365                         && !strcmp(tnc->name,aname) )
366         {
367             tmp = tnc->next;
368             error = RemoveEntry(tnc, skey);
369             if ( error )
370                 break;
371
372             tnc->next = cm_data.ncfreelist; /* insert entry into freelist */
373             cm_data.ncfreelist = tnc;
374             found = 1;          /* found at least one entry */
375
376             tnc = tmp;          /* continue down the linked list */
377         }
378         else if (tnc->next == cm_data.nameHash[skey]) /* end of list */
379             break;
380         else
381             tnc = tnc->next;
382         if ( safety > NCSIZE )
383         {
384             dnlcstats.cycles++;
385             lock_ReleaseWrite(&cm_dnlcLock);
386
387             dnlcNotify("DNLC cycle",1); 
388             if ( cm_debugDnlc ) 
389                 osi_Log0(afsd_logp, "DNLC cycle"); 
390             cm_dnlcPurge();
391             return;
392         }
393     }
394     lock_ReleaseWrite(&cm_dnlcLock);
395
396     if (!found && !error && cm_debugDnlc)
397         osi_Log0(afsd_logp, "cm_dnlcRemove name not found");
398
399     if ( error )
400         cm_dnlcPurge();
401 }
402
403 /* remove anything pertaining to this directory */
404 void 
405 cm_dnlcPurgedp (cm_scache_t *adp)
406 {
407     int i;
408     int err=0;
409
410     if (!cm_useDnlc)
411         return ;
412
413     if ( cm_debugDnlc )
414         osi_Log1(afsd_logp, "cm_dnlcPurgedp dir %x", adp);
415
416     lock_ObtainWrite(&cm_dnlcLock);
417     dnlcstats.purgeds++;
418
419     for (i=0; i<NCSIZE && !err; i++) 
420     {
421         if (cm_data.nameCache[i].dirp == adp ) 
422         {
423             if (cm_data.nameCache[i].prev) {
424                 err = RemoveEntry(&cm_data.nameCache[i], cm_data.nameCache[i].key & (NHSIZE-1));
425                 if (!err)
426                 {
427                     cm_data.nameCache[i].next = cm_data.ncfreelist;
428                     cm_data.ncfreelist = &cm_data.nameCache[i];
429                 }
430             } else {
431                 cm_data.nameCache[i].dirp = cm_data.nameCache[i].vp = (cm_scache_t *) 0;
432             }
433         }
434     }
435     lock_ReleaseWrite(&cm_dnlcLock);
436     if ( err )
437         cm_dnlcPurge();
438 }
439
440 /* remove anything pertaining to this file */
441 void 
442 cm_dnlcPurgevp (cm_scache_t *avc)
443 {
444     int i;
445     int err=0;
446
447     if (!cm_useDnlc)
448         return ;
449
450     if ( cm_debugDnlc )
451         osi_Log1(afsd_logp, "cm_dnlcPurgevp scache %x", avc);
452
453     lock_ObtainWrite(&cm_dnlcLock);
454     dnlcstats.purgevs++;
455
456     for (i=0; i<NCSIZE && !err ; i++) 
457     {
458         if (cm_data.nameCache[i].vp == avc) 
459         {
460             if (cm_data.nameCache[i].prev) {
461                 err = RemoveEntry(&cm_data.nameCache[i], cm_data.nameCache[i].key & (NHSIZE-1));
462                 if (!err)
463                 {
464                     cm_data.nameCache[i].next = cm_data.ncfreelist;
465                     cm_data.ncfreelist = &cm_data.nameCache[i];
466                 }
467             } else {
468                 cm_data.nameCache[i].dirp = cm_data.nameCache[i].vp = (cm_scache_t *) 0;
469             }
470         }
471     }
472     lock_ReleaseWrite(&cm_dnlcLock);
473     if ( err )
474         cm_dnlcPurge();
475 }
476
477 /* remove everything */
478 void cm_dnlcPurge(void)
479 {
480     int i;
481
482     if (!cm_useDnlc)
483         return ;
484
485     if ( cm_debugDnlc )
486         osi_Log0(afsd_logp, "cm_dnlcPurge");
487
488     lock_ObtainWrite(&cm_dnlcLock);
489     dnlcstats.purges++;
490     
491     cm_data.ncfreelist = (cm_nc_t *) 0;
492     memset (cm_data.nameCache, 0, sizeof(cm_nc_t) * NCSIZE);
493     memset (cm_data.nameHash, 0, sizeof(cm_nc_t *) * NHSIZE);
494     for (i=0; i<NCSIZE; i++)
495     {
496         cm_data.nameCache[i].magic = CM_DNLC_MAGIC;
497         cm_data.nameCache[i].next = cm_data.ncfreelist;
498         cm_data.ncfreelist = &cm_data.nameCache[i];
499     }
500     lock_ReleaseWrite(&cm_dnlcLock);
501    
502 }
503
504 /* remove everything referencing a specific volume */
505 /* is this function ever called? */
506 void
507 cm_dnlcPurgeVol(AFSFid *fidp)
508 {
509
510     if (!cm_useDnlc)
511         return ;
512
513     dnlcstats.purgevols++;
514     cm_dnlcPurge();
515 }
516
517 long
518 cm_dnlcValidate(void)
519 {
520     int i, purged = 0;
521     cm_nc_t * ncp;
522
523   retry:
524     // are all nameCache entries marked with the magic bit?
525     for (i=0; i<NCSIZE; i++)
526     {
527         if (cm_data.nameCache[i].magic != CM_DNLC_MAGIC) {
528             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].magic != CM_DNLC_MAGIC", i);
529             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].magic != CM_DNLC_MAGIC\n", i);
530             goto purge;
531         }
532         if (cm_data.nameCache[i].next &&
533             cm_data.nameCache[i].next->magic != CM_DNLC_MAGIC) {
534             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].next->magic != CM_DNLC_MAGIC", i);
535             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].next->magic != CM_DNLC_MAGIC\n", i);
536             goto purge;
537         }
538         if (cm_data.nameCache[i].prev &&
539             cm_data.nameCache[i].prev->magic != CM_DNLC_MAGIC) {
540             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].prev->magic != CM_DNLC_MAGIC", i);
541             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].prev->magic != CM_DNLC_MAGIC\n", i);
542             goto purge;
543         }
544         if (cm_data.nameCache[i].dirp &&
545             cm_data.nameCache[i].dirp->magic != CM_SCACHE_MAGIC) {
546             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].dirp->magic != CM_SCACHE_MAGIC", i);
547             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].dirp->magic != CM_SCACHE_MAGIC\n", i);
548             goto purge;
549         }
550         if (cm_data.nameCache[i].vp &&
551             cm_data.nameCache[i].vp->magic != CM_SCACHE_MAGIC) {
552             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].vp->magic != CM_SCACHE_MAGIC", i);
553             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].vp->magic != CM_SCACHE_MAGIC\n", i);
554             goto purge;
555         }
556     }
557
558     // are the contents of the hash table intact?
559     for (i=0; i<NHSIZE;i++) {
560         for (ncp = cm_data.nameHash[i]; ncp ; 
561              ncp = ncp->next != cm_data.nameHash[i] ? ncp->next : NULL) {
562             if (ncp->magic != CM_DNLC_MAGIC) {
563                 afsi_log("cm_dnlcValidate failure: ncp->magic != CM_DNLC_MAGIC");
564                 fprintf(stderr, "cm_dnlcValidate failure: ncp->magic != CM_DNLC_MAGIC\n");
565                 goto purge;
566             }
567             if (ncp->prev && ncp->prev->magic != CM_DNLC_MAGIC) {
568                 afsi_log("cm_dnlcValidate failure: ncp->prev->magic != CM_DNLC_MAGIC");
569                 fprintf(stderr, "cm_dnlcValidate failure: ncp->prev->magic != CM_DNLC_MAGIC\n");
570                 goto purge;
571             }
572             if (ncp->dirp && ncp->dirp->magic != CM_SCACHE_MAGIC) {
573                 afsi_log("cm_dnlcValidate failure: ncp->dirp->magic != CM_DNLC_MAGIC");
574                 fprintf(stderr, "cm_dnlcValidate failure: ncp->dirp->magic != CM_DNLC_MAGIC\n");
575                 goto purge;
576             }
577             if (ncp->vp && ncp->vp->magic != CM_SCACHE_MAGIC) {
578                 afsi_log("cm_dnlcValidate failure: ncp->vp->magic != CM_DNLC_MAGIC");
579                 fprintf(stderr, "cm_dnlcValidate failure: ncp->vp->magic != CM_DNLC_MAGIC\n");
580                 goto purge;
581             }
582         }
583     }
584
585     // is the freelist stable?
586     if ( cm_data.ncfreelist ) {
587         for (ncp = cm_data.ncfreelist, i = 0; ncp && i < NCSIZE; 
588              ncp = ncp->next != cm_data.ncfreelist ? ncp->next : NULL, i++) {
589             if (ncp->magic != CM_DNLC_MAGIC) {
590                 afsi_log("cm_dnlcValidate failure: ncp->magic != CM_DNLC_MAGIC");
591                 fprintf(stderr, "cm_dnlcValidate failure: ncp->magic != CM_DNLC_MAGIC\n");
592                 goto purge;
593             }
594             if (ncp->prev) {
595                 afsi_log("cm_dnlcValidate failure: ncp->prev != NULL");
596                 fprintf(stderr, "cm_dnlcValidate failure: ncp->prev != NULL\n");
597                 goto purge;
598             }
599             if (ncp->key) {
600                 afsi_log("cm_dnlcValidate failure: ncp->key != 0");
601                 fprintf(stderr, "cm_dnlcValidate failure: ncp->key != 0\n");
602                 goto purge;
603             }
604             if (ncp->dirp) {
605                 afsi_log("cm_dnlcValidate failure: ncp->dirp != NULL");
606                 fprintf(stderr, "cm_dnlcValidate failure: ncp->dirp != NULL\n");
607                goto purge;
608             }
609             if (ncp->vp) {
610                 afsi_log("cm_dnlcValidate failure: ncp->vp != NULL");
611                 fprintf(stderr, "cm_dnlcValidate failure: ncp->vp != NULL\n");
612                 goto purge;
613             }
614         }
615
616         if ( i == NCSIZE && ncp ) {
617             afsi_log("cm_dnlcValidate failure: dnlc freeList corrupted");
618             fprintf(stderr, "cm_dnlcValidate failure: dnlc freeList corrupted\n");
619             goto purge;
620         }
621     }
622     return 0;
623
624   purge:
625     if ( purged )
626         return -1;
627
628     afsi_log("cm_dnlcValidate information: purging");
629     fprintf(stderr, "cm_dnlcValidate information: purging\n");
630     cm_data.ncfreelist = (cm_nc_t *) 0;
631     memset (cm_data.nameCache, 0, sizeof(cm_nc_t) * NCSIZE);
632     memset (cm_data.nameHash, 0, sizeof(cm_nc_t *) * NHSIZE);
633     for (i=0; i<NCSIZE; i++)
634     {
635         cm_data.nameCache[i].magic = CM_DNLC_MAGIC;
636         cm_data.nameCache[i].next = cm_data.ncfreelist;
637         cm_data.ncfreelist = &cm_data.nameCache[i];
638     }
639     purged = 1;
640     goto retry;
641 }
642
643 void 
644 cm_dnlcInit(int newFile)
645 {
646     int i;
647
648     if (!cm_useDnlc)
649         return ;
650
651     if ( cm_debugDnlc )
652         osi_Log0(afsd_logp,"cm_dnlcInit");
653
654     memset (&dnlcstats, 0, sizeof(dnlcstats));
655
656     lock_InitializeRWLock(&cm_dnlcLock, "cm_dnlcLock");
657     if ( newFile ) {
658         lock_ObtainWrite(&cm_dnlcLock);
659         cm_data.ncfreelist = (cm_nc_t *) 0;
660         cm_data.nameCache = cm_data.dnlcBaseAddress;
661         memset (cm_data.nameCache, 0, sizeof(cm_nc_t) * NCSIZE);
662         cm_data.nameHash = (cm_nc_t **) (cm_data.nameCache + NCSIZE);
663         memset (cm_data.nameHash, 0, sizeof(cm_nc_t *) * NHSIZE);
664     
665         for (i=0; i<NCSIZE; i++)
666         {
667             cm_data.nameCache[i].magic = CM_DNLC_MAGIC;
668             cm_data.nameCache[i].next = cm_data.ncfreelist;
669             cm_data.ncfreelist = &cm_data.nameCache[i];
670         }
671         lock_ReleaseWrite(&cm_dnlcLock);
672     }
673 }
674
675 long 
676 cm_dnlcShutdown(void)
677 {
678     if ( cm_debugDnlc )
679         osi_Log0(afsd_logp,"cm_dnlcShutdown");
680
681     return 0;
682 }