2 ** This implements the directory to name cache lookup.
3 ** Given a directory scache and a name, the dnlc returns the
4 ** vcache corresponding to the name. The vcache entries that
5 ** exist in the dnlc are not refcounted.
19 osi_rwlock_t cm_dnlcLock;
21 cm_dnlcstats_t dnlcstats; /* dnlc statistics */
22 int cm_useDnlc = 1; /* yes, start using the dnlc */
23 int cm_debugDnlc = 0; /* debug dnlc */
26 /* Hash table invariants:
27 * 1. If nameHash[i] is NULL, list is empty
28 * 2. A single element in a hash bucket has itself as prev and next.
30 struct nc *ncfreelist = (struct nc *)0;
31 static struct nc nameCache[NCSIZE];
32 struct nc* nameHash[NHSIZE];
35 #define dnlcNotify(x,debug){ \
40 hh = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME); \
41 ReportEvent(hh,EVENTLOG_ERROR_TYPE,0,__LINE__, \
42 NULL, 1, 0, ptbuf, NULL); \
43 DeregisterEventSource(hh); \
51 static unsigned int nameptr = 0; /* next bucket to pull something from */
58 ncfreelist = tnc->next;
62 for (j=0; j<NHSIZE+2; j++, nameptr++)
64 if (nameptr >= NHSIZE)
66 if (nameHash[nameptr])
70 tnc = nameHash[nameptr];
73 dnlcNotify("null tnc in GetMeAnEntry",1);
74 osi_Log0(afsd_logp,"null tnc in GetMeAnEntry");
79 { /* only thing in list, don't screw around */
80 nameHash[nameptr] = (struct nc *) 0;
84 tnc = tnc->prev; /* grab oldest one in this bucket */
85 tnc->next->prev = tnc->prev;/* remove it from list */
86 tnc->prev->next = tnc->next;
96 key = tnc->key & (NHSIZE -1);
101 tnc->next = tnc->prev = tnc;
105 tnc->next = nameHash[key];
106 tnc->prev = tnc->next->prev;
107 tnc->next->prev = tnc;
108 tnc->prev->next = tnc;
115 cm_dnlcEnter ( adp, aname, avc )
121 unsigned int key, skey, new=0;
129 osi_Log3(afsd_logp,"cm_dnlcEnter dir %x name %s scache %x",
130 adp, osi_LogSaveString(afsd_logp,aname), avc);
132 dnlcHash( ts, key ); /* leaves ts pointing at the NULL */
133 if (ts - aname >= CM_AFSNCNAMESIZE)
135 skey = key & (NHSIZE -1);
137 lock_ObtainWrite(&cm_dnlcLock);
140 for (tnc = nameHash[skey], safety=0; tnc; tnc = tnc->next, safety++ )
141 if ((tnc->dirp == adp) && (!cm_stricmp(tnc->name, aname)))
142 break; /* preexisting entry */
143 else if ( tnc->next == nameHash[skey]) /* end of list */
148 else if ( safety >NCSIZE)
151 lock_ReleaseWrite(&cm_dnlcLock);
153 dnlcNotify("DNLC cycle",1);
155 osi_Log0(afsd_logp, "DNLC cycle");
162 new = 1; /* entry does not exist, we are creating a new entry*/
163 tnc = GetMeAnEntry();
170 memcpy (tnc->name, aname, ts-aname+1); /* include the NULL */
172 if ( new ) /* insert entry only if it is newly created */
176 lock_ReleaseWrite(&cm_dnlcLock);
183 * if the scache entry is found, return it held
186 cm_dnlcLookup ( adp, sp)
188 cm_lookupSearch_t* sp;
191 unsigned int key, skey;
192 char* aname = sp->searchNamep;
200 osi_Log2(afsd_logp, "cm_dnlcLookup dir %x name %s",
201 adp, osi_LogSaveString(afsd_logp,aname));
203 dnlcHash( ts, key ); /* leaves ts pointing at the NULL */
204 if (ts - aname >= CM_AFSNCNAMESIZE)
207 skey = key & (NHSIZE -1);
209 lock_ObtainRead(&cm_dnlcLock);
210 dnlcstats.lookups++; /* Is a dnlcread lock sufficient? */
212 for ( tvc = (cm_scache_t *) 0, tnc = nameHash[skey], safety=0;
213 tnc; tnc = tnc->next, safety++ )
215 if (tnc->dirp == adp)
217 if ( sp->caseFold ) /* case insensitive */
219 match = cm_stricmp(tnc->name, aname);
220 if ( !match ) /* something matches */
222 /* determine what type of match it is */
223 if ( !strcmp(tnc->name, aname))
225 /* exact match, do nothing */
227 else if ( cm_NoneUpper(tnc->name))
229 else if ( cm_NoneLower(tnc->name))
231 else sp->NCfound = 1;
236 else /* case sensitive */
238 match = strcmp(tnc->name, aname);
239 if ( !match ) /* found a match */
246 if (tnc->next == nameHash[skey])
250 else if (safety >NCSIZE)
253 lock_ReleaseRead(&cm_dnlcLock);
255 dnlcNotify("DNLC cycle",1);
257 osi_Log0(afsd_logp, "DNLC cycle");
264 dnlcstats.misses++; /* Is a dnlcread lock sufficient? */
268 sp->fid.vnode = tvc->fid.vnode;
269 sp->fid.unique = tvc->fid.unique;
271 lock_ReleaseRead(&cm_dnlcLock);
274 lock_ObtainWrite(&cm_scacheLock);
275 tvc->refCount++; /* scache entry held */
276 lock_ReleaseWrite(&cm_scacheLock);
279 if ( cm_debugDnlc && tvc )
280 osi_Log1(afsd_logp, "cm_dnlcLookup found %x", tvc);
287 RemoveEntry (tnc, key)
291 if (!tnc->prev) /* things on freelist always have null prev ptrs */
293 dnlcNotify("Bogus dnlc freelist", 1);
294 osi_Log0(afsd_logp,"Bogus dnlc freelist");
295 return 1; /* error */
298 if (tnc == tnc->next) /* only one in list */
299 nameHash[key] = (struct nc *) 0;
302 if (tnc == nameHash[key])
303 nameHash[key] = tnc->next;
304 tnc->prev->next = tnc->next;
305 tnc->next->prev = tnc->prev;
308 tnc->prev = (struct nc *) 0; /* everything not in hash table has 0 prev */
309 tnc->key = 0; /* just for safety's sake */
310 return 0; /* success */
315 cm_dnlcRemove ( adp, aname)
319 unsigned int key, skey, error=0;
320 int found= 0, safety;
322 struct nc *tnc, *tmp;
328 osi_Log2(afsd_logp, "cm_dnlcRemove dir %x name %s",
329 adp, osi_LogSaveString(afsd_logp,aname));
331 dnlcHash( ts, key ); /* leaves ts pointing at the NULL */
332 if (ts - aname >= CM_AFSNCNAMESIZE)
335 skey = key & (NHSIZE -1);
336 lock_ObtainWrite(&cm_dnlcLock);
339 for (tnc = nameHash[skey], safety=0; tnc; safety++)
341 if ( (tnc->dirp == adp) && (tnc->key == key)
342 && !cm_stricmp(tnc->name,aname) )
344 tnc->dirp = (cm_scache_t *) 0; /* now it won't match anything */
346 error = RemoveEntry(tnc, skey);
350 tnc->next = ncfreelist; /* insert entry into freelist */
352 found = 1; /* found atleast one entry */
354 tnc = tmp; /* continue down the linked list */
356 else if (tnc->next == nameHash[skey]) /* end of list */
360 if ( safety > NCSIZE )
363 lock_ReleaseWrite(&cm_dnlcLock);
365 dnlcNotify("DNLC cycle",1);
367 osi_Log0(afsd_logp, "DNLC cycle");
372 lock_ReleaseWrite(&cm_dnlcLock);
374 if (!found && !error && cm_debugDnlc)
375 osi_Log0(afsd_logp, "cm_dnlcRemove name not found");
381 /* remove anything pertaining to this directory */
393 osi_Log1(afsd_logp, "cm_dnlcPurgedp dir %x", adp);
395 lock_ObtainWrite(&cm_dnlcLock);
398 for (i=0; i<NCSIZE && !err; i++)
400 if (nameCache[i].dirp == adp )
402 nameCache[i].dirp = nameCache[i].vp = (cm_scache_t *) 0;
403 if (nameCache[i].prev && !err)
405 err = RemoveEntry(&nameCache[i], nameCache[i].key & (NHSIZE-1));
406 nameCache[i].next = ncfreelist;
407 ncfreelist = &nameCache[i];
411 lock_ReleaseWrite(&cm_dnlcLock);
416 /* remove anything pertaining to this file */
418 cm_dnlcPurgevp ( avc )
428 osi_Log1(afsd_logp, "cm_dnlcPurgevp scache %x", avc);
430 lock_ObtainWrite(&cm_dnlcLock);
433 for (i=0; i<NCSIZE && !err ; i++)
435 if (nameCache[i].vp == avc)
437 nameCache[i].dirp = nameCache[i].vp = (cm_scache_t *) 0;
438 /* can't simply break; because of hard links -- might be two */
439 /* different entries with same vnode */
440 if (!err && nameCache[i].prev)
442 err=RemoveEntry(&nameCache[i], nameCache[i].key & (NHSIZE-1));
443 nameCache[i].next = ncfreelist;
444 ncfreelist = &nameCache[i];
448 lock_ReleaseWrite(&cm_dnlcLock);
453 /* remove everything */
454 void cm_dnlcPurge(void)
462 osi_Log0(afsd_logp, "cm_dnlcPurge");
464 lock_ObtainWrite(&cm_dnlcLock);
467 ncfreelist = (struct nc *) 0;
468 memset (nameCache, 0, sizeof(struct nc) * NCSIZE);
469 memset (nameHash, 0, sizeof(struct nc *) * NHSIZE);
470 for (i=0; i<NCSIZE; i++)
472 nameCache[i].next = ncfreelist;
473 ncfreelist = &nameCache[i];
475 lock_ReleaseWrite(&cm_dnlcLock);
479 /* remove everything referencing a specific volume */
481 cm_dnlcPurgeVol( fidp )
488 dnlcstats.purgevols++;
500 osi_Log0(afsd_logp,"cm_dnlcInit");
502 lock_InitializeRWLock(&cm_dnlcLock, "cm_dnlcLock");
503 memset (&dnlcstats, 0, sizeof(dnlcstats));
504 lock_ObtainWrite(&cm_dnlcLock);
505 ncfreelist = (struct nc *) 0;
506 memset (nameCache, 0, sizeof(struct nc) * NCSIZE);
507 memset (nameHash, 0, sizeof(struct nc *) * NHSIZE);
508 for (i=0; i<NCSIZE; i++)
510 nameCache[i].next = ncfreelist;
511 ncfreelist = &nameCache[i];
513 lock_ReleaseWrite(&cm_dnlcLock);
517 cm_dnlcShutdown(void)
520 osi_Log0(afsd_logp,"cm_dnlcShutdown");