DEVEL15-windows-server-xdr-free-20090614
[openafs.git] / src / WINNT / afsd / cm_server.c
index 34fe393..a7aea33 100644 (file)
 #include <afs/param.h>
 #include <afs/stds.h>
 
-#ifndef DJGPP
 #include <windows.h>
 #include <winsock2.h>
 #include <nb30.h>
-#else
-#include <sys/socket.h>
-#endif /* !DJGPP */
 #include <stdlib.h>
 #include <malloc.h>
 #include <string.h>
 
 #include "afsd.h"
 #include <WINNT\syscfg.h>
+#include <WINNT/afsreg.h>
 #include <osi.h>
 #include <rx/rx.h>
 
@@ -41,7 +38,9 @@ cm_ForceNewConnectionsAllServers(void)
     lock_ObtainRead(&cm_serverLock);
     for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
         cm_GetServerNoLock(tsp);
+        lock_ReleaseRead(&cm_serverLock);
        cm_ForceNewConnections(tsp);
+        lock_ObtainRead(&cm_serverLock);
         cm_PutServerNoLock(tsp);
     }
     lock_ReleaseRead(&cm_serverLock);
@@ -118,7 +117,7 @@ cm_PingServer(cm_server_t *tsp)
        /* we currently handle 32-bits of capabilities */
        if (caps.Capabilities_len > 0) {
            tsp->capabilities = caps.Capabilities_val[0];
-           free(caps.Capabilities_val);
+           xdr_free(caps.Capabilities_val, caps.Capabilities_len);
            caps.Capabilities_len = 0;
            caps.Capabilities_val = 0;
        } else {
@@ -159,9 +158,11 @@ cm_PingServer(cm_server_t *tsp)
             tsp->flags |= CM_SERVERFLAG_DOWN;
             tsp->downTime = time(NULL);
         }
-       if (code != VRESTARTING)
+       if (code != VRESTARTING) {
+            lock_ReleaseMutex(&tsp->mx);
            cm_ForceNewConnections(tsp);
-
+            lock_ObtainMutex(&tsp->mx);
+        }
        osi_Log3(afsd_logp, "cm_PingServer server %s (%s) is down with caps 0x%x",
                  osi_LogSaveString(afsd_logp, hoststr), 
                  tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
@@ -199,9 +200,7 @@ cm_PingServer(cm_server_t *tsp)
     lock_ReleaseMutex(&tsp->mx);
 }
 
-#define MULTI_CHECKSERVERS 1
-#ifndef MULTI_CHECKSERVERS
-void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
+static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
 {
     /* ping all file servers, up or down, with unauthenticated connection,
      * to find out whether we have all our callbacks from the server still.
@@ -255,8 +254,8 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
     }
     lock_ReleaseRead(&cm_serverLock);
 }       
-#else /* MULTI_CHECKSERVERS */
-void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
+
+static void cm_CheckServersMulti(afs_uint32 flags, cm_cell_t *cellp)
 {
     /* 
      * The goal of this function is to probe simultaneously 
@@ -276,7 +275,7 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
     cm_conn_t **conns = NULL;
     struct rx_connection **rxconns = NULL;
     cm_req_t req;
-    afs_int32 i, j, nconns = 0;
+    afs_int32 i, j, nconns = 0, maxconns;
     afs_int32 *conntimer, *results;
     Capabilities *caps = NULL;
     cm_server_t ** serversp, *tsp;
@@ -288,24 +287,25 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
     char hoststr[16];
 
     cm_InitReq(&req);
+    maxconns = max(cm_numFileServers,cm_numVldbServers);
+    if (maxconns == 0)
+        return;
 
-    j = max(cm_numFileServers,cm_numVldbServers);
-    conns = (cm_conn_t **)malloc(j * sizeof(cm_conn_t *));
-    rxconns = (struct rx_connection **)malloc(j * sizeof(struct rx_connection *));
-    conntimer = (afs_int32 *)malloc(j * sizeof (afs_int32));
-    deltas = (time_t *)malloc(j * sizeof (time_t));
-    results = (afs_int32 *)malloc(j * sizeof (afs_int32));
-    serversp = (cm_server_t **)malloc(j * sizeof(cm_server_t *));
-    caps = (Capabilities *)malloc(j * sizeof(Capabilities));
+    conns = (cm_conn_t **)malloc(maxconns * sizeof(cm_conn_t *));
+    rxconns = (struct rx_connection **)malloc(maxconns * sizeof(struct rx_connection *));
+    conntimer = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
+    deltas = (time_t *)malloc(maxconns * sizeof (time_t));
+    results = (afs_int32 *)malloc(maxconns * sizeof (afs_int32));
+    serversp = (cm_server_t **)malloc(maxconns * sizeof(cm_server_t *));
+    caps = (Capabilities *)malloc(maxconns * sizeof(Capabilities));
 
-    memset(caps, 0, j * sizeof(Capabilities));
+    memset(caps, 0, maxconns * sizeof(Capabilities));
 
     if ((flags & CM_FLAG_CHECKFILESERVERS) || 
         !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
     {
         lock_ObtainRead(&cm_serverLock);
-        nconns = 0;
-        for (nconns=0, tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
+        for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
             if (tsp->type != CM_SERVER_FILE || 
                 tsp->cellp == NULL ||           /* SetPref only */
                 cellp && cellp != tsp->cellp)
@@ -380,7 +380,7 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
                 /* we currently handle 32-bits of capabilities */
                 if (caps[i].Capabilities_len > 0) {
                     tsp->capabilities = caps[i].Capabilities_val[0];
-                    free(caps[i].Capabilities_val);
+                    xdr_free(caps[i].Capabilities_val, caps[i].Capabilities_len);
                     caps[i].Capabilities_len = 0;
                     caps[i].Capabilities_val = 0;
                 } else {
@@ -422,9 +422,11 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
                     tsp->flags |= CM_SERVERFLAG_DOWN;
                     tsp->downTime = time(NULL);
                 }
-                if (code != VRESTARTING)
+                if (code != VRESTARTING) {
+                    lock_ReleaseMutex(&tsp->mx);
                     cm_ForceNewConnections(tsp);
-
+                    lock_ObtainMutex(&tsp->mx);
+                }
                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
                           osi_LogSaveString(afsd_logp, hoststr), 
@@ -551,9 +553,11 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
                     tsp->flags |= CM_SERVERFLAG_DOWN;
                     tsp->downTime = time(NULL);
                 }
-                if (code != VRESTARTING)
+                if (code != VRESTARTING) {
+                    lock_ReleaseMutex(&tsp->mx);
                     cm_ForceNewConnections(tsp);
-
+                    lock_ObtainMutex(&tsp->mx);
+                }
                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
                           osi_LogSaveString(afsd_logp, hoststr), 
@@ -600,8 +604,7 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
         !(flags & (CM_FLAG_CHECKFILESERVERS|CM_FLAG_CHECKVLDBSERVERS)))
     {
         lock_ObtainRead(&cm_serverLock);
-        nconns = 0;
-        for (nconns=0, tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
+        for (nconns=0, tsp = cm_allServersp; tsp && nconns < maxconns; tsp = tsp->allNextp) {
             if (tsp->type != CM_SERVER_VLDB ||
                 tsp->cellp == NULL ||           /* SetPref only */
                 cellp && cellp != tsp->cellp)
@@ -652,7 +655,7 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
             } multi_End;
         }
 
-        /* Process results of servers that support RXAFS_GetCapabilities */
+        /* Process results of servers that support VL_ProbeServer */
         for (i=0; i<nconns; i++) {
             if (conntimer[i])
                 rx_SetConnDeadTime(rxconns[i], ConnDeadtimeout);
@@ -676,68 +679,22 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
                           osi_LogSaveString(afsd_logp, hoststr), 
                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
                           tsp->capabilities);
-
-                /* Now update the volume status if necessary */
-                if (wasDown) {
-                    cm_server_vols_t * tsrvp;
-                    cm_volume_t * volp;
-                    int i;
-
-                    for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
-                        for (i=0; i<NUM_SERVER_VOLS; i++) {
-                            if (tsrvp->ids[i] != 0) {
-                                cm_InitReq(&req);
-
-                                lock_ReleaseMutex(&tsp->mx);
-                                code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
-                                                         &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
-                                lock_ObtainMutex(&tsp->mx);
-                                if (code == 0) {
-                                    cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
-                                    cm_PutVolume(volp);
-                                }
-                            }
-                        }
-                    }
-                }
             } else {
                 /* mark server as down */
                 if (!(tsp->flags & CM_SERVERFLAG_DOWN)) {
                     tsp->flags |= CM_SERVERFLAG_DOWN;
                     tsp->downTime = time(NULL);
                 }
-                if (code != VRESTARTING)
+                if (code != VRESTARTING) {
+                    lock_ReleaseMutex(&tsp->mx);
                     cm_ForceNewConnections(tsp);
-
+                    lock_ObtainMutex(&tsp->mx);
+                }
                 afs_inet_ntoa_r(tsp->addr.sin_addr.S_un.S_addr, hoststr);
                 osi_Log3(afsd_logp, "cm_MultiPingServer server %s (%s) is down with caps 0x%x",
                           osi_LogSaveString(afsd_logp, hoststr), 
                           tsp->type == CM_SERVER_VLDB ? "vldb" : "file",
                           tsp->capabilities);
-
-                /* Now update the volume status if necessary */
-                if (!wasDown) {
-                    cm_server_vols_t * tsrvp;
-                    cm_volume_t * volp;
-                    int i;
-
-                    for (tsrvp = tsp->vols; tsrvp; tsrvp = tsrvp->nextp) {
-                        for (i=0; i<NUM_SERVER_VOLS; i++) {
-                            if (tsrvp->ids[i] != 0) {
-                                cm_InitReq(&req);
-
-                                lock_ReleaseMutex(&tsp->mx);
-                                code = cm_FindVolumeByID(tsp->cellp, tsrvp->ids[i], cm_rootUserp,
-                                                         &req, CM_GETVOL_FLAG_NO_LRU_UPDATE, &volp);
-                                lock_ObtainMutex(&tsp->mx);
-                                if (code == 0) {
-                                    cm_UpdateVolumeStatus(volp, tsrvp->ids[i]);
-                                    cm_PutVolume(volp);
-                                }
-                            }
-                        }
-                    }
-                }
             }
 
             if (tsp->waitCount == 0)
@@ -756,17 +713,39 @@ void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
     free(conntimer);
     free(deltas);
     free(results);
+    free(serversp);
     free(caps);
 }
-#endif /* MULTI_CHECKSERVERS */
+
+void cm_CheckServers(afs_uint32 flags, cm_cell_t *cellp)
+{
+    DWORD code;
+    HKEY parmKey;
+    DWORD dummyLen;
+    DWORD multi = 1;
+
+    code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
+                         0, KEY_QUERY_VALUE, &parmKey);
+    if (code == ERROR_SUCCESS) {
+        dummyLen = sizeof(multi);
+        code = RegQueryValueEx(parmKey, "MultiCheckServers", NULL, NULL,
+                                (BYTE *) &multi, &dummyLen);
+        RegCloseKey (parmKey);
+    }
+
+    if (multi)
+        cm_CheckServersMulti(flags, cellp);
+    else
+        cm_CheckServersSingular(flags, cellp);
+}
 
 void cm_InitServer(void)
 {
     static osi_once_t once;
         
     if (osi_Once(&once)) {
-        lock_InitializeRWLock(&cm_serverLock, "cm_serverLock");
-        lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock");
+        lock_InitializeRWLock(&cm_serverLock, "cm_serverLock", LOCK_HIERARCHY_SERVER_GLOBAL);
+        lock_InitializeRWLock(&cm_syscfgLock, "cm_syscfgLock", LOCK_HIERARCHY_SYSCFG_GLOBAL);
         osi_EndOnce(&once);
     }
 }
@@ -891,13 +870,14 @@ void cm_SetServerPrefs(cm_server_t * serverp)
            else serverp->ipRank = min(serverp->ipRank,CM_IPRANK_MED);
            /* same net */
        }       
-       /* random between 0..15*/
-       serverp->ipRank += min(serverp->ipRank, rand() % 0x000f);
     } /* and of for loop */
+
+    /* random between 0..15*/
+    serverp->ipRank += (rand() % 0x000f);
     lock_ReleaseRead(&cm_syscfgLock);
 }
 
-cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp, afs_uint32 flags) {
+cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cellp, afsUUID *uuidp, afs_uint32 flags) {
     cm_server_t *tsp;
 
     osi_assertx(socketp->sin_family == AF_INET, "unexpected socket family");
@@ -907,8 +887,12 @@ cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cell
         memset(tsp, 0, sizeof(*tsp));
         tsp->type = type;
         tsp->cellp = cellp;
+        if (uuidp && !afs_uuid_is_nil(uuidp)) {
+            tsp->uuid = *uuidp;
+            tsp->flags |= CM_SERVERFLAG_UUID;
+        }
         tsp->refCount = 1;
-        lock_InitializeMutex(&tsp->mx, "cm_server_t mutex");
+        lock_InitializeMutex(&tsp->mx, "cm_server_t mutex", LOCK_HIERARCHY_SERVER);
         tsp->addr = *socketp;
 
         cm_SetServerPrefs(tsp); 
@@ -929,7 +913,7 @@ cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cell
         lock_ReleaseWrite(&cm_serverLock);     /* release server lock */
 
         if ( !(flags & CM_FLAG_NOPROBE) ) {
-            tsp->flags = CM_SERVERFLAG_DOWN;   /* assume down; ping will mark up if available */
+            tsp->flags |= CM_SERVERFLAG_DOWN;  /* assume down; ping will mark up if available */
             cm_PingServer(tsp);                        /* Obtain Capabilities and check up/down state */
         }
     }
@@ -947,6 +931,11 @@ cm_FindServerByIP(afs_uint32 ipaddr, int type)
             tsp->addr.sin_addr.S_un.S_addr == ipaddr)
             break;
     }
+
+    /* bump ref count if we found the server */
+    if (tsp) 
+        cm_GetServerNoLock(tsp);
+
     lock_ReleaseRead(&cm_serverLock);
 
     return tsp;
@@ -1055,6 +1044,8 @@ LONG_PTR cm_ChecksumServerList(cm_serverRef_t *serversp)
 
     lock_ObtainRead(&cm_serverLock);
     for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
+        if (tsrp->status == srv_deleted)
+            continue;
         if (first)
             first = 0;
         else
@@ -1194,16 +1185,32 @@ void cm_RandomizeServer(cm_serverRef_t** list)
 void cm_FreeServer(cm_server_t* serverp)
 {
     cm_server_vols_t * tsrvp, *nextp;
+    int delserver = 0;
 
     cm_PutServerNoLock(serverp);
     if (serverp->refCount == 0)
     {
-        /* we need to check to ensure that all of the connections
+        /* 
+         * we need to check to ensure that all of the connections
          * for this server have a 0 refCount; otherwise, they will
          * not be garbage collected 
+         *
+         * must drop the cm_serverLock because cm_GCConnections
+         * obtains the cm_connLock and that comes first in the 
+         * lock hierarchy.  
          */
+        lock_ReleaseWrite(&cm_serverLock);
         cm_GCConnections(serverp);  /* connsp */
+        lock_ObtainWrite(&cm_serverLock);
+    }
+
 
+    /* 
+     * Once we have the cm_serverLock locked check to make
+     * sure the refCount is still zero before removing the 
+     * server entirely.
+     */
+    if (serverp->refCount == 0) {
        if (!(serverp->flags & CM_SERVERFLAG_PREF_SET)) {
             switch (serverp->type) {
             case CM_SERVER_VLDB:
@@ -1239,6 +1246,7 @@ void cm_FreeServer(cm_server_t* serverp)
     }
 }
 
+/* Called with cm_serverLock write locked */
 void cm_RemoveVolumeFromServer(cm_server_t * serverp, afs_uint32 volID)
 {
     cm_server_vols_t * tsrvp;
@@ -1263,6 +1271,9 @@ void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
     cm_serverRef_t  **nextp = 0;
     cm_serverRef_t  * next = 0;
 
+       if (*list == NULL)
+               return;
+
     lock_ObtainWrite(&cm_serverLock);
 
     while (*current)
@@ -1288,3 +1299,62 @@ void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
   
     lock_ReleaseWrite(&cm_serverLock);
 }
+
+/* dump all servers to a file. 
+ * cookie is used to identify this batch for easy parsing, 
+ * and it a string provided by a caller 
+ */
+int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
+{
+    int zilch;
+    cm_server_t *tsp;
+    char output[1024];
+    char uuidstr[128];
+    char hoststr[16];
+
+    if (lock)
+        lock_ObtainRead(&cm_serverLock);
+  
+    sprintf(output, "%s - dumping servers - cm_numFileServers=%d, cm_numVldbServers=%d\r\n", 
+            cookie, cm_numFileServers, cm_numVldbServers);
+    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+  
+    for (tsp = cm_allServersp; tsp; tsp=tsp->allNextp)
+    {
+        char * type;
+        char * down;
+
+        switch (tsp->type) {
+        case CM_SERVER_VLDB:
+            type = "vldb";
+            break;
+        case CM_SERVER_FILE:
+            type = "file";
+            break;
+        default:
+            type = "unknown";
+        }
+
+        afsUUID_to_string(&tsp->uuid, uuidstr, sizeof(uuidstr));
+        afs_inet_ntoa_r(tsp->addr.sin_addr.s_addr, hoststr);
+        down = ctime(&tsp->downTime);
+        down[strlen(down)-1] = '\0';
+
+        sprintf(output, "%s - tsp=0x%p cell=%s addr=%-15s uuid=%s type=%s caps=0x%x flags=0x%x waitCount=%u rank=%u downTime=\"%s\" refCount=%u\r\n",
+                 cookie, tsp, tsp->cellp ? tsp->cellp->name : "", hoststr, uuidstr, type, 
+                 tsp->capabilities, tsp->flags, tsp->waitCount, tsp->ipRank, 
+                 (tsp->flags & CM_SERVERFLAG_DOWN) ?  down : "up",
+                 tsp->refCount);
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+    }
+    sprintf(output, "%s - Done dumping servers.\r\n", cookie);
+    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+  
+    if (lock)
+       lock_ReleaseRead(&cm_serverLock);
+
+    return (0);     
+}
+
+
+