windows-dnlc-20080226
[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_ReleaseRead(&cm_dnlcLock);
161             lock_ObtainWrite(&cm_dnlcLock);
162             writeLocked = 1;
163             goto retry;
164         }
165         new = 1;        /* entry does not exist, we are creating a new entry*/
166         tnc = GetMeAnEntry();
167     }
168     if ( tnc )
169     { 
170         tnc->dirp = adp;
171         tnc->vp = avc;
172         tnc->key = key;
173         memcpy (tnc->name, aname, ts-aname+1); /* include the NULL */
174
175         if ( new )      /* insert entry only if it is newly created */ 
176                 InsertEntry(tnc);
177
178     }
179     if (writeLocked)
180         lock_ReleaseWrite(&cm_dnlcLock);
181     else
182         lock_ReleaseRead(&cm_dnlcLock);
183
184     if ( !tnc)
185         cm_dnlcPurge();
186 }
187
188 /*
189 * if the scache entry is found, return it held
190 */
191 cm_scache_t *
192 cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
193 {
194     cm_scache_t * tvc;
195     unsigned int key, skey;
196     char* aname = sp->searchNamep;
197     char *ts = aname;
198     cm_nc_t * tnc, * tnc_begin;
199     int safety, match;
200   
201     if (!cm_useDnlc)
202         return NULL;
203
204     if ( cm_debugDnlc ) 
205         osi_Log2(afsd_logp, "cm_dnlcLookup dir %x name %s", 
206                 adp, osi_LogSaveString(afsd_logp,aname));
207
208     dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
209
210     if (ts - aname >= CM_AFSNCNAMESIZE) {
211         InterlockedIncrement(&dnlcstats.lookups);
212         InterlockedIncrement(&dnlcstats.misses);
213         return NULL;
214     }
215
216     skey = key & (NHSIZE -1);
217
218     lock_ObtainRead(&cm_dnlcLock);
219     InterlockedIncrement(&dnlcstats.lookups);
220
221     ts = 0;
222     tnc_begin = cm_data.nameHash[skey];
223     for ( tvc = (cm_scache_t *) NULL, tnc = tnc_begin, safety=0; 
224           tnc; tnc = tnc->next, safety++ ) 
225     {
226         if (tnc->dirp == adp) 
227         {
228         if( cm_debugDnlc ) 
229             osi_Log1(afsd_logp,"Looking at [%s]",
230                      osi_LogSaveString(afsd_logp,tnc->name));
231
232             if ( sp->caseFold )         /* case insensitive */
233             {
234             match = cm_stricmp(tnc->name, aname);
235             if ( !match )       /* something matches */
236             {
237                 tvc = tnc->vp;
238                 ts = tnc->name;
239
240                 /* determine what type of match it is */
241                 if ( !strcmp(tnc->name, aname))
242                 {       
243                     /* exact match. */
244                     sp->ExactFound = 1;
245
246                     if( cm_debugDnlc )
247                         osi_Log1(afsd_logp,"DNLC found exact match [%s]",
248                                  osi_LogSaveString(afsd_logp,tnc->name));
249                     break;
250                 }
251                 else if ( cm_NoneUpper(tnc->name))
252                     sp->LCfound = 1;
253                 else if ( cm_NoneLower(tnc->name))
254                     sp->UCfound = 1;
255                 else    
256                     sp->NCfound = 1;
257                 /* Don't break here. We might find an exact match yet */
258             }
259             }
260             else                        /* case sensitive */
261             {
262             match = strcmp(tnc->name, aname);
263             if ( !match ) /* found a match */
264             {
265                 sp->ExactFound = 1;
266                 tvc = tnc->vp; 
267                 ts = tnc->name;
268                 break;
269             }
270             }
271         }
272         if (tnc->next == cm_data.nameHash[skey]) 
273     {                   /* end of list */
274             break;
275         }
276         else if (tnc->next == tnc_begin || safety > NCSIZE) 
277         {
278             InterlockedIncrement(&dnlcstats.cycles);
279             lock_ReleaseRead(&cm_dnlcLock);
280
281             if ( cm_debugDnlc ) 
282                 osi_Log0(afsd_logp, "DNLC cycle"); 
283             cm_dnlcPurge();
284             return(NULL);
285         }
286     }
287
288     if(cm_debugDnlc && ts) {
289         osi_Log3(afsd_logp, "DNLC matched [%s] for [%s] with vnode[%ld]",
290                  osi_LogSaveString(afsd_logp,ts),
291                  osi_LogSaveString(afsd_logp,aname),
292                  (long) tvc->fid.vnode);
293     }
294
295     if (!tvc) 
296         InterlockedIncrement(&dnlcstats.misses);
297     else 
298     {
299         sp->found = 1;
300         sp->fid.vnode  = tvc->fid.vnode; 
301         sp->fid.unique = tvc->fid.unique;       
302     }
303     lock_ReleaseRead(&cm_dnlcLock);
304
305     if (tvc)
306         cm_HoldSCache(tvc);
307
308     if ( cm_debugDnlc && tvc ) 
309         osi_Log1(afsd_logp, "cm_dnlcLookup found %x", tvc);
310     
311     return tvc;
312 }
313
314
315 static int
316 RemoveEntry (cm_nc_t *tnc, unsigned int key)
317 {
318     if (!tnc->prev) /* things on freelist always have null prev ptrs */
319     {
320         osi_Log0(afsd_logp,"Bogus dnlc freelist");
321         return 1;   /* error */
322     }
323
324     if (tnc == tnc->next)  /* only one in list */
325         cm_data.nameHash[key] = (cm_nc_t *) 0;
326     else 
327     {
328         if (tnc == cm_data.nameHash[key])
329             cm_data.nameHash[key]  = tnc->next;
330         tnc->prev->next = tnc->next;
331         tnc->next->prev = tnc->prev;
332     }
333
334     memset(tnc, 0, sizeof(cm_nc_t));
335     tnc->magic = CM_DNLC_MAGIC;
336     return 0;     /* success */
337 }
338
339
340 void 
341 cm_dnlcRemove (cm_scache_t *adp, char *aname)
342 {
343     unsigned int key, skey, error=0;
344     int found= 0, safety;
345     char *ts = aname;
346     cm_nc_t *tnc, *tmp;
347   
348     if (!cm_useDnlc)
349         return ;
350
351     if ( cm_debugDnlc )
352         osi_Log2(afsd_logp, "cm_dnlcRemove dir %x name %s", 
353                 adp, osi_LogSaveString(afsd_logp,aname));
354
355     dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
356     if (ts - aname >= CM_AFSNCNAMESIZE) 
357         return ;
358
359     skey = key & (NHSIZE -1);
360     lock_ObtainWrite(&cm_dnlcLock);
361     InterlockedIncrement(&dnlcstats.removes);
362
363     for (tnc = cm_data.nameHash[skey], safety=0; tnc; safety++) 
364     {
365         if ( (tnc->dirp == adp) && (tnc->key == key) 
366                         && !strcmp(tnc->name,aname) )
367         {
368             tmp = tnc->next;
369             error = RemoveEntry(tnc, skey);
370             if ( error )
371                 break;
372
373             tnc->next = cm_data.ncfreelist; /* insert entry into freelist */
374             cm_data.ncfreelist = tnc;
375             found = 1;          /* found at least one entry */
376
377             tnc = tmp;          /* continue down the linked list */
378         }
379         else if (tnc->next == cm_data.nameHash[skey]) /* end of list */
380             break;
381         else
382             tnc = tnc->next;
383         if ( safety > NCSIZE )
384         {
385             InterlockedIncrement(&dnlcstats.cycles);
386             lock_ReleaseWrite(&cm_dnlcLock);
387
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     InterlockedIncrement(&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     InterlockedIncrement(&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     InterlockedIncrement(&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     InterlockedIncrement(&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     HKEY parmKey;
648     DWORD dummyLen;
649     DWORD dwValue;
650     DWORD code;
651
652     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
653                          0, KEY_QUERY_VALUE, &parmKey);
654     if (code == ERROR_SUCCESS) {
655         dummyLen = sizeof(DWORD);
656         code = RegQueryValueEx(parmKey, "UseDNLC", NULL, NULL,
657                                 (BYTE *) &dwValue, &dummyLen);
658         if (code == ERROR_SUCCESS)
659             cm_useDnlc = dwValue ? 1 : 0;
660         afsi_log("CM UseDNLC = %d", cm_useDnlc);
661
662         dummyLen = sizeof(DWORD);
663         code = RegQueryValueEx(parmKey, "DebugDNLC", NULL, NULL,
664                                 (BYTE *) &dwValue, &dummyLen);
665         if (code == ERROR_SUCCESS)
666             cm_debugDnlc = dwValue ? 1 : 0;
667         afsi_log("CM DebugDNLC = %d", cm_debugDnlc);
668         RegCloseKey (parmKey);
669     }
670
671     if (!cm_useDnlc)
672         return ;
673
674     if ( cm_debugDnlc )
675         osi_Log0(afsd_logp,"cm_dnlcInit");
676
677     memset (&dnlcstats, 0, sizeof(dnlcstats));
678
679     lock_InitializeRWLock(&cm_dnlcLock, "cm_dnlcLock");
680     if ( newFile ) {
681         lock_ObtainWrite(&cm_dnlcLock);
682         cm_data.ncfreelist = (cm_nc_t *) 0;
683         cm_data.nameCache = cm_data.dnlcBaseAddress;
684         memset (cm_data.nameCache, 0, sizeof(cm_nc_t) * NCSIZE);
685         cm_data.nameHash = (cm_nc_t **) (cm_data.nameCache + NCSIZE);
686         memset (cm_data.nameHash, 0, sizeof(cm_nc_t *) * NHSIZE);
687     
688         for (i=0; i<NCSIZE; i++)
689         {
690             cm_data.nameCache[i].magic = CM_DNLC_MAGIC;
691             cm_data.nameCache[i].next = cm_data.ncfreelist;
692             cm_data.ncfreelist = &cm_data.nameCache[i];
693         }
694         lock_ReleaseWrite(&cm_dnlcLock);
695     }
696 }
697
698 long 
699 cm_dnlcShutdown(void)
700 {
701     if ( cm_debugDnlc )
702         osi_Log0(afsd_logp,"cm_dnlcShutdown");
703
704     return 0;
705 }