windows-dnlc-20080226
[openafs.git] / src / WINNT / afsd / cm_dnlc.c
index eced524..b0e7338 100644 (file)
 #include <afs/param.h>
 #include <afs/stds.h>
 
-#ifndef DJGPP
 #include <windows.h>
 #include <winsock2.h>
-#endif /* !DJGPP */
 #include <string.h>
 #include <stdlib.h>
 #include <osi.h>
 #include "afsd.h"
+#include <WINNT/afsreg.h>
 
 osi_rwlock_t cm_dnlcLock;
 
@@ -38,22 +37,8 @@ static int cm_debugDnlc = 0; /* debug dnlc */
  *     1.  If nameHash[i] is NULL, list is empty
  *     2.  A single element in a hash bucket has itself as prev and next.
  */
-#ifndef DJGPP
-#define dnlcNotify(x,debug){                    \
-                        HANDLE  hh;             \
-                        char *ptbuf[1];         \
-                        ptbuf[0] = x;           \
-                       if ( debug ) {          \
-                            hh = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);   \
-                            ReportEvent(hh,EVENTLOG_ERROR_TYPE,0,__LINE__,  \
-                               NULL, 1, 0, ptbuf, NULL);                   \
-                            DeregisterEventSource(hh);                 \
-                       }                                               \
-                     }  
-#else
-#define dnlcNotify(x,debug)
-#endif /* !DJGPP */
 
+/* Must be called with cm_dnlcLock write locked */
 static cm_nc_t * 
 GetMeAnEntry() 
 {
@@ -79,7 +64,6 @@ GetMeAnEntry()
     tnc = cm_data.nameHash[nameptr];
     if (!tnc)   
     {
-       dnlcNotify("null tnc in GetMeAnEntry",1);
        osi_Log0(afsd_logp,"null tnc in GetMeAnEntry");
        return 0;
     }
@@ -98,8 +82,7 @@ GetMeAnEntry()
 }
 
 static void 
-InsertEntry(tnc)
-    cm_nc_t *tnc;
+InsertEntry(cm_nc_t *tnc)
 {
     unsigned int key; 
     key = tnc->key & (NHSIZE -1);
@@ -129,10 +112,14 @@ cm_dnlcEnter ( cm_scache_t *adp,
     unsigned int key, skey, new=0;
     char *ts = aname;
     int safety;
+    int writeLocked = 0;
 
     if (!cm_useDnlc)
        return ;
-  
+
+    if (!strcmp(aname,".") || !strcmp(aname,".."))
+       return ;
+
     if ( cm_debugDnlc ) 
        osi_Log3(afsd_logp,"cm_dnlcEnter dir %x name %s scache %x", 
            adp, osi_LogSaveString(afsd_logp,aname), avc);
@@ -142,9 +129,9 @@ cm_dnlcEnter ( cm_scache_t *adp,
        return ;
     skey = key & (NHSIZE -1);
 
-    lock_ObtainWrite(&cm_dnlcLock);
-    dnlcstats.enters++;
-  
+    InterlockedIncrement(&dnlcstats.enters);
+    lock_ObtainRead(&cm_dnlcLock);
+  retry:
     for (tnc = cm_data.nameHash[skey], safety=0; tnc; tnc = tnc->next, safety++ )
        if ((tnc->dirp == adp) && (!strcmp(tnc->name, aname)))
            break;                              /* preexisting entry */
@@ -155,10 +142,12 @@ cm_dnlcEnter ( cm_scache_t *adp,
        }
        else if (safety > NCSIZE) 
        {
-           dnlcstats.cycles++;
-           lock_ReleaseWrite(&cm_dnlcLock);
+           InterlockedIncrement(&dnlcstats.cycles);
+            if (writeLocked)
+                lock_ReleaseWrite(&cm_dnlcLock);
+            else
+                lock_ReleaseRead(&cm_dnlcLock);
 
-           dnlcNotify("DNLC cycle",1);
            if ( cm_debugDnlc )
                 osi_Log0(afsd_logp, "DNLC cycle");
            cm_dnlcPurge();
@@ -167,6 +156,12 @@ cm_dnlcEnter ( cm_scache_t *adp,
        
     if ( !tnc )
     {
+        if ( !writeLocked ) {
+            lock_ReleaseRead(&cm_dnlcLock);
+            lock_ObtainWrite(&cm_dnlcLock);
+            writeLocked = 1;
+            goto retry;
+        }
        new = 1;        /* entry does not exist, we are creating a new entry*/
        tnc = GetMeAnEntry();
     }
@@ -181,7 +176,10 @@ cm_dnlcEnter ( cm_scache_t *adp,
                InsertEntry(tnc);
 
     }
-    lock_ReleaseWrite(&cm_dnlcLock);
+    if (writeLocked)
+        lock_ReleaseWrite(&cm_dnlcLock);
+    else
+        lock_ReleaseRead(&cm_dnlcLock);
 
     if ( !tnc)
        cm_dnlcPurge();
@@ -201,23 +199,28 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
     int safety, match;
   
     if (!cm_useDnlc)
-       return 0;
+       return NULL;
+
     if ( cm_debugDnlc ) 
        osi_Log2(afsd_logp, "cm_dnlcLookup dir %x name %s", 
                adp, osi_LogSaveString(afsd_logp,aname));
 
     dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
-    if (ts - aname >= CM_AFSNCNAMESIZE) 
-       return 0;
+
+    if (ts - aname >= CM_AFSNCNAMESIZE) {
+        InterlockedIncrement(&dnlcstats.lookups);
+        InterlockedIncrement(&dnlcstats.misses);
+       return NULL;
+    }
 
     skey = key & (NHSIZE -1);
 
     lock_ObtainRead(&cm_dnlcLock);
-    dnlcstats.lookups++;            /* Is a dnlcread lock sufficient? */
+    InterlockedIncrement(&dnlcstats.lookups);
 
     ts = 0;
     tnc_begin = cm_data.nameHash[skey];
-    for ( tvc = (cm_scache_t *) 0, tnc = tnc_begin, safety=0; 
+    for ( tvc = (cm_scache_t *) NULL, tnc = tnc_begin, safety=0; 
           tnc; tnc = tnc->next, safety++ ) 
     {
        if (tnc->dirp == adp) 
@@ -272,14 +275,13 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
        }
        else if (tnc->next == tnc_begin || safety > NCSIZE) 
        {
-           dnlcstats.cycles++;
+           InterlockedIncrement(&dnlcstats.cycles);
            lock_ReleaseRead(&cm_dnlcLock);
 
-           dnlcNotify("DNLC cycle",1); 
            if ( cm_debugDnlc ) 
                osi_Log0(afsd_logp, "DNLC cycle"); 
            cm_dnlcPurge();
-           return(0);
+           return(NULL);
        }
     }
 
@@ -291,7 +293,7 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
     }
 
     if (!tvc) 
-        dnlcstats.misses++;    /* Is a dnlcread lock sufficient? */
+        InterlockedIncrement(&dnlcstats.misses);
     else 
     {
         sp->found = 1;
@@ -311,13 +313,10 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
 
 
 static int
-RemoveEntry (tnc, key)
-    cm_nc_t    *tnc;
-    unsigned int key;
+RemoveEntry (cm_nc_t *tnc, unsigned int key)
 {
     if (!tnc->prev) /* things on freelist always have null prev ptrs */
     {
-       dnlcNotify("Bogus dnlc freelist", 1);
        osi_Log0(afsd_logp,"Bogus dnlc freelist");
        return 1;   /* error */
     }
@@ -332,16 +331,14 @@ RemoveEntry (tnc, key)
        tnc->next->prev = tnc->prev;
     }
 
-    tnc->prev = (cm_nc_t *) 0; /* everything not in hash table has 0 prev */
-    tnc->key = 0; /* just for safety's sake */
+    memset(tnc, 0, sizeof(cm_nc_t));
+    tnc->magic = CM_DNLC_MAGIC;
     return 0;    /* success */
 }
 
 
 void 
-cm_dnlcRemove ( adp, aname)
-    cm_scache_t *adp;
-    char          *aname;
+cm_dnlcRemove (cm_scache_t *adp, char *aname)
 {
     unsigned int key, skey, error=0;
     int found= 0, safety;
@@ -361,14 +358,13 @@ cm_dnlcRemove ( adp, aname)
 
     skey = key & (NHSIZE -1);
     lock_ObtainWrite(&cm_dnlcLock);
-    dnlcstats.removes++;
+    InterlockedIncrement(&dnlcstats.removes);
 
     for (tnc = cm_data.nameHash[skey], safety=0; tnc; safety++) 
     {
        if ( (tnc->dirp == adp) && (tnc->key == key) 
                        && !strcmp(tnc->name,aname) )
        {
-           tnc->dirp = (cm_scache_t *) 0; /* now it won't match anything */
            tmp = tnc->next;
            error = RemoveEntry(tnc, skey);
            if ( error )
@@ -376,7 +372,7 @@ cm_dnlcRemove ( adp, aname)
 
            tnc->next = cm_data.ncfreelist; /* insert entry into freelist */
            cm_data.ncfreelist = tnc;
-           found = 1;          /* found atleast one entry */
+           found = 1;          /* found at least one entry */
 
            tnc = tmp;          /* continue down the linked list */
        }
@@ -386,10 +382,9 @@ cm_dnlcRemove ( adp, aname)
            tnc = tnc->next;
        if ( safety > NCSIZE )
        {
-           dnlcstats.cycles++;
+           InterlockedIncrement(&dnlcstats.cycles);
            lock_ReleaseWrite(&cm_dnlcLock);
 
-           dnlcNotify("DNLC cycle",1); 
            if ( cm_debugDnlc ) 
                osi_Log0(afsd_logp, "DNLC cycle"); 
            cm_dnlcPurge();
@@ -407,8 +402,7 @@ cm_dnlcRemove ( adp, aname)
 
 /* remove anything pertaining to this directory */
 void 
-cm_dnlcPurgedp (adp)
-  cm_scache_t *adp;
+cm_dnlcPurgedp (cm_scache_t *adp)
 {
     int i;
     int err=0;
@@ -420,19 +414,22 @@ cm_dnlcPurgedp (adp)
        osi_Log1(afsd_logp, "cm_dnlcPurgedp dir %x", adp);
 
     lock_ObtainWrite(&cm_dnlcLock);
-    dnlcstats.purgeds++;
+    InterlockedIncrement(&dnlcstats.purgeds);
 
     for (i=0; i<NCSIZE && !err; i++) 
     {
        if (cm_data.nameCache[i].dirp == adp ) 
        {
-           cm_data.nameCache[i].dirp = cm_data.nameCache[i].vp = (cm_scache_t *) 0;
-           if (cm_data.nameCache[i].prev && !err) 
-           {
-               err = RemoveEntry(&cm_data.nameCache[i], cm_data.nameCache[i].key & (NHSIZE-1));
-               cm_data.nameCache[i].next = cm_data.ncfreelist;
-               cm_data.ncfreelist = &cm_data.nameCache[i];
-           }
+           if (cm_data.nameCache[i].prev) {
+                err = RemoveEntry(&cm_data.nameCache[i], cm_data.nameCache[i].key & (NHSIZE-1));
+                if (!err)
+                {
+                    cm_data.nameCache[i].next = cm_data.ncfreelist;
+                    cm_data.ncfreelist = &cm_data.nameCache[i];
+                }
+           } else {
+                cm_data.nameCache[i].dirp = cm_data.nameCache[i].vp = (cm_scache_t *) 0;
+            }
        }
     }
     lock_ReleaseWrite(&cm_dnlcLock);
@@ -442,8 +439,7 @@ cm_dnlcPurgedp (adp)
 
 /* remove anything pertaining to this file */
 void 
-cm_dnlcPurgevp ( avc )
-  cm_scache_t *avc;
+cm_dnlcPurgevp (cm_scache_t *avc)
 {
     int i;
     int err=0;
@@ -455,21 +451,22 @@ cm_dnlcPurgevp ( avc )
        osi_Log1(afsd_logp, "cm_dnlcPurgevp scache %x", avc);
 
     lock_ObtainWrite(&cm_dnlcLock);
-    dnlcstats.purgevs++;
+    InterlockedIncrement(&dnlcstats.purgevs);
 
     for (i=0; i<NCSIZE && !err ; i++) 
     {
        if (cm_data.nameCache[i].vp == avc) 
        {
-           cm_data.nameCache[i].dirp = cm_data.nameCache[i].vp = (cm_scache_t *) 0;
-           /* can't simply break; because of hard links -- might be two */
-           /* different entries with same vnode */ 
-           if (!err && cm_data.nameCache[i].prev) 
-           {
-               err=RemoveEntry(&cm_data.nameCache[i], cm_data.nameCache[i].key & (NHSIZE-1));
-               cm_data.nameCache[i].next = cm_data.ncfreelist;
-               cm_data.ncfreelist = &cm_data.nameCache[i];
-           }
+           if (cm_data.nameCache[i].prev) {
+                err = RemoveEntry(&cm_data.nameCache[i], cm_data.nameCache[i].key & (NHSIZE-1));
+                if (!err)
+                {
+                    cm_data.nameCache[i].next = cm_data.ncfreelist;
+                    cm_data.ncfreelist = &cm_data.nameCache[i];
+                }
+           } else {
+                cm_data.nameCache[i].dirp = cm_data.nameCache[i].vp = (cm_scache_t *) 0;
+            }
        }
     }
     lock_ReleaseWrite(&cm_dnlcLock);
@@ -489,70 +486,72 @@ void cm_dnlcPurge(void)
        osi_Log0(afsd_logp, "cm_dnlcPurge");
 
     lock_ObtainWrite(&cm_dnlcLock);
-    dnlcstats.purges++;
+    InterlockedIncrement(&dnlcstats.purges);
     
     cm_data.ncfreelist = (cm_nc_t *) 0;
     memset (cm_data.nameCache, 0, sizeof(cm_nc_t) * NCSIZE);
     memset (cm_data.nameHash, 0, sizeof(cm_nc_t *) * NHSIZE);
-    for (i=0; i<NCSIZE; i++) 
+    for (i=0; i<NCSIZE; i++)
     {
-       cm_data.nameCache[i].next = cm_data.ncfreelist;
-       cm_data.ncfreelist = &cm_data.nameCache[i];
+        cm_data.nameCache[i].magic = CM_DNLC_MAGIC;
+        cm_data.nameCache[i].next = cm_data.ncfreelist;
+        cm_data.ncfreelist = &cm_data.nameCache[i];
     }
     lock_ReleaseWrite(&cm_dnlcLock);
    
 }
 
 /* remove everything referencing a specific volume */
+/* is this function ever called? */
 void
-cm_dnlcPurgeVol( fidp )
-  AFSFid *fidp;
+cm_dnlcPurgeVol(AFSFid *fidp)
 {
 
     if (!cm_useDnlc)
         return ;
 
-    dnlcstats.purgevols++;
+    InterlockedIncrement(&dnlcstats.purgevols);
     cm_dnlcPurge();
 }
 
 long
 cm_dnlcValidate(void)
 {
-    int i;
+    int i, purged = 0;
     cm_nc_t * ncp;
-    
+
+  retry:
     // are all nameCache entries marked with the magic bit?
     for (i=0; i<NCSIZE; i++)
     {
         if (cm_data.nameCache[i].magic != CM_DNLC_MAGIC) {
             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].magic != CM_DNLC_MAGIC", i);
             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].magic != CM_DNLC_MAGIC\n", i);
-            return -1;
+            goto purge;
         }
         if (cm_data.nameCache[i].next &&
             cm_data.nameCache[i].next->magic != CM_DNLC_MAGIC) {
             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].next->magic != CM_DNLC_MAGIC", i);
             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].next->magic != CM_DNLC_MAGIC\n", i);
-            return -2;
+            goto purge;
         }
         if (cm_data.nameCache[i].prev &&
             cm_data.nameCache[i].prev->magic != CM_DNLC_MAGIC) {
             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].prev->magic != CM_DNLC_MAGIC", i);
             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].prev->magic != CM_DNLC_MAGIC\n", i);
-            return -3;
+            goto purge;
         }
         if (cm_data.nameCache[i].dirp &&
             cm_data.nameCache[i].dirp->magic != CM_SCACHE_MAGIC) {
             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].dirp->magic != CM_SCACHE_MAGIC", i);
             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].dirp->magic != CM_SCACHE_MAGIC\n", i);
-            return -4;
+            goto purge;
         }
         if (cm_data.nameCache[i].vp &&
             cm_data.nameCache[i].vp->magic != CM_SCACHE_MAGIC) {
             afsi_log("cm_dnlcValidate failure: cm_data.nameCache[%d].vp->magic != CM_SCACHE_MAGIC", i);
             fprintf(stderr, "cm_dnlcValidate failure: cm_data.nameCache[%d].vp->magic != CM_SCACHE_MAGIC\n", i);
-            return -5;
+            goto purge;
         }
     }
 
@@ -563,60 +562,111 @@ cm_dnlcValidate(void)
             if (ncp->magic != CM_DNLC_MAGIC) {
                 afsi_log("cm_dnlcValidate failure: ncp->magic != CM_DNLC_MAGIC");
                 fprintf(stderr, "cm_dnlcValidate failure: ncp->magic != CM_DNLC_MAGIC\n");
-                return -6;
+                goto purge;
             }
             if (ncp->prev && ncp->prev->magic != CM_DNLC_MAGIC) {
                 afsi_log("cm_dnlcValidate failure: ncp->prev->magic != CM_DNLC_MAGIC");
                 fprintf(stderr, "cm_dnlcValidate failure: ncp->prev->magic != CM_DNLC_MAGIC\n");
-                return -7;
+                goto purge;
             }
             if (ncp->dirp && ncp->dirp->magic != CM_SCACHE_MAGIC) {
                 afsi_log("cm_dnlcValidate failure: ncp->dirp->magic != CM_DNLC_MAGIC");
                 fprintf(stderr, "cm_dnlcValidate failure: ncp->dirp->magic != CM_DNLC_MAGIC\n");
-                return -8;
+                goto purge;
             }
             if (ncp->vp && ncp->vp->magic != CM_SCACHE_MAGIC) {
                 afsi_log("cm_dnlcValidate failure: ncp->vp->magic != CM_DNLC_MAGIC");
                 fprintf(stderr, "cm_dnlcValidate failure: ncp->vp->magic != CM_DNLC_MAGIC\n");
-                return -9;
+                goto purge;
             }
         }
     }
 
     // is the freelist stable?
     if ( cm_data.ncfreelist ) {
-        for (ncp = cm_data.ncfreelist; ncp; 
-             ncp = ncp->next != cm_data.ncfreelist ? ncp->next : NULL) {
+        for (ncp = cm_data.ncfreelist, i = 0; ncp && i < NCSIZE; 
+             ncp = ncp->next != cm_data.ncfreelist ? ncp->next : NULL, i++) {
             if (ncp->magic != CM_DNLC_MAGIC) {
                 afsi_log("cm_dnlcValidate failure: ncp->magic != CM_DNLC_MAGIC");
                 fprintf(stderr, "cm_dnlcValidate failure: ncp->magic != CM_DNLC_MAGIC\n");
-                return -10;
+                goto purge;
             }
-            if (ncp->prev && ncp->prev->magic != CM_DNLC_MAGIC) {
-                afsi_log("cm_dnlcValidate failure: ncp->prev->magic != CM_DNLC_MAGIC");
-                fprintf(stderr, "cm_dnlcValidate failure: ncp->prev->magic != CM_DNLC_MAGIC\n");
-                return -11;
+            if (ncp->prev) {
+                afsi_log("cm_dnlcValidate failure: ncp->prev != NULL");
+                fprintf(stderr, "cm_dnlcValidate failure: ncp->prev != NULL\n");
+                goto purge;
             }
-            if (ncp->dirp && ncp->dirp->magic != CM_SCACHE_MAGIC) {
-                afsi_log("cm_dnlcValidate failure: ncp->dirp->magic != CM_DNLC_MAGIC");
-                fprintf(stderr, "cm_dnlcValidate failure: ncp->dirp->magic != CM_DNLC_MAGIC\n");
-               return -12;
+            if (ncp->key) {
+                afsi_log("cm_dnlcValidate failure: ncp->key != 0");
+                fprintf(stderr, "cm_dnlcValidate failure: ncp->key != 0\n");
+                goto purge;
             }
-            if (ncp->vp && ncp->vp->magic != CM_SCACHE_MAGIC) {
-                afsi_log("cm_dnlcValidate failure: ncp->vp->magic != CM_DNLC_MAGIC");
-                fprintf(stderr, "cm_dnlcValidate failure: ncp->vp->magic != CM_DNLC_MAGIC\n");
-                return -13;
+            if (ncp->dirp) {
+                afsi_log("cm_dnlcValidate failure: ncp->dirp != NULL");
+                fprintf(stderr, "cm_dnlcValidate failure: ncp->dirp != NULL\n");
+               goto purge;
+            }
+            if (ncp->vp) {
+                afsi_log("cm_dnlcValidate failure: ncp->vp != NULL");
+                fprintf(stderr, "cm_dnlcValidate failure: ncp->vp != NULL\n");
+                goto purge;
             }
         }
-    }
 
+        if ( i == NCSIZE && ncp ) {
+            afsi_log("cm_dnlcValidate failure: dnlc freeList corrupted");
+            fprintf(stderr, "cm_dnlcValidate failure: dnlc freeList corrupted\n");
+            goto purge;
+        }
+    }
     return 0;
+
+  purge:
+    if ( purged )
+        return -1;
+
+    afsi_log("cm_dnlcValidate information: purging");
+    fprintf(stderr, "cm_dnlcValidate information: purging\n");
+    cm_data.ncfreelist = (cm_nc_t *) 0;
+    memset (cm_data.nameCache, 0, sizeof(cm_nc_t) * NCSIZE);
+    memset (cm_data.nameHash, 0, sizeof(cm_nc_t *) * NHSIZE);
+    for (i=0; i<NCSIZE; i++)
+    {
+        cm_data.nameCache[i].magic = CM_DNLC_MAGIC;
+        cm_data.nameCache[i].next = cm_data.ncfreelist;
+        cm_data.ncfreelist = &cm_data.nameCache[i];
+    }
+    purged = 1;
+    goto retry;
 }
 
 void 
 cm_dnlcInit(int newFile)
 {
     int i;
+    HKEY parmKey;
+    DWORD dummyLen;
+    DWORD dwValue;
+    DWORD code;
+
+    code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
+                         0, KEY_QUERY_VALUE, &parmKey);
+    if (code == ERROR_SUCCESS) {
+        dummyLen = sizeof(DWORD);
+        code = RegQueryValueEx(parmKey, "UseDNLC", NULL, NULL,
+                                (BYTE *) &dwValue, &dummyLen);
+        if (code == ERROR_SUCCESS)
+            cm_useDnlc = dwValue ? 1 : 0;
+        afsi_log("CM UseDNLC = %d", cm_useDnlc);
+
+        dummyLen = sizeof(DWORD);
+        code = RegQueryValueEx(parmKey, "DebugDNLC", NULL, NULL,
+                                (BYTE *) &dwValue, &dummyLen);
+        if (code == ERROR_SUCCESS)
+            cm_debugDnlc = dwValue ? 1 : 0;
+        afsi_log("CM DebugDNLC = %d", cm_debugDnlc);
+        RegCloseKey (parmKey);
+    }
 
     if (!cm_useDnlc)
         return ;