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