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