Windows: correct locking in cm_FreeServerList
[openafs.git] / src / WINNT / afsd / cm_server.c
index b83eb4e..0d2ac9e 100644 (file)
@@ -22,6 +22,7 @@
 #include <WINNT/afsreg.h>
 #include <osi.h>
 #include <rx/rx.h>
+#include <math.h>
 
 osi_rwlock_t cm_serverLock;
 osi_rwlock_t cm_syscfgLock;
@@ -46,6 +47,69 @@ cm_ForceNewConnectionsAllServers(void)
     lock_ReleaseRead(&cm_serverLock);
 }
 
+/*
+ * lock_ObtainMutex must be held prior to calling
+ * this function.
+ */
+afs_int32
+cm_RankServer(cm_server_t * tsp)
+{
+    afs_int32 code = 0; /* start with "success" */
+    struct rx_debugPeer tpeer;
+    afs_uint16 port;
+    afs_uint16 newRank;
+
+    switch(tsp->type) {
+       case CM_SERVER_VLDB:
+           port = htons(7003);
+           break;
+       case CM_SERVER_FILE:
+           port = htons(7000);
+           break;
+       default:
+           return -1;
+    }
+
+    code = rx_GetLocalPeers(tsp->addr.sin_addr.s_addr, port, &tpeer);
+
+    /*check if rx_GetLocalPeers succeeded and if there is data for tsp */
+    if(code == 0 && (tpeer.rtt == 0 && tpeer.rtt_dev == 0))
+       code = -1;
+
+    if(code == 0) {
+       if((tsp->flags & CM_SERVERFLAG_PREF_SET))
+           newRank = tsp->adminRank +
+                ((int)(623 * log(tpeer.rtt) / 10) * 10 + 5);
+       else /* rank has not been set by admin, derive rank from rtt */
+           newRank = (int)(7200 * log(tpeer.rtt) / 5000) * 5000 + 5000;
+
+       newRank += (rand() & 0x000f); /* randomize */
+
+        if (abs(newRank - tsp->ipRank) > 0xf) {
+            tsp->ipRank = newRank;
+
+            lock_ReleaseMutex(&tsp->mx);
+            switch (tsp->type) {
+            case CM_SERVER_FILE:
+                /*
+                 * find volumes which might have RO copy
+                 * on server and change the ordering of
+                 * their RO list
+                 */
+                cm_ChangeRankVolume(tsp);
+                break;
+            case CM_SERVER_VLDB:
+                /* set preferences for an existing vlserver */
+                cm_ChangeRankCellVLServer(tsp);
+                break;
+            }
+            lock_ObtainMutex(&tsp->mx);
+        }
+    }
+
+    return code;
+}
+
 void 
 cm_PingServer(cm_server_t *tsp)
 {
@@ -117,7 +181,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];
-           xdr_free(caps.Capabilities_val, caps.Capabilities_len);
+           xdr_free((xdrproc_t) xdr_Capabilities, &caps);
            caps.Capabilities_len = 0;
            caps.Capabilities_val = 0;
        } else {
@@ -200,6 +264,30 @@ cm_PingServer(cm_server_t *tsp)
     lock_ReleaseMutex(&tsp->mx);
 }
 
+void
+cm_RankUpServers()
+{
+    cm_server_t * tsp;
+
+    lock_ObtainRead(&cm_serverLock);
+    for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
+       cm_GetServerNoLock(tsp);
+       lock_ReleaseRead(&cm_serverLock);
+
+       lock_ObtainMutex(&tsp->mx);
+
+        /* if the server is not down, rank the server */
+        if(!(tsp->flags & CM_SERVERFLAG_DOWN))
+          cm_RankServer(tsp);
+
+       lock_ReleaseMutex(&tsp->mx);
+
+       lock_ObtainRead(&cm_serverLock);
+       cm_PutServerNoLock(tsp);
+    }
+    lock_ReleaseRead(&cm_serverLock);
+}
+
 static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
 {
     /* ping all file servers, up or down, with unauthenticated connection,
@@ -210,6 +298,7 @@ static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
     int doPing;
     int isDown;
     int isFS;
+    int isVLDB;
 
     lock_ObtainRead(&cm_serverLock);
     for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
@@ -222,6 +311,7 @@ static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
         doPing = 0;
         isDown = tsp->flags & CM_SERVERFLAG_DOWN;
         isFS   = tsp->type == CM_SERVER_FILE;
+        isVLDB = tsp->type == CM_SERVER_VLDB;
 
         /* only do the ping if the cell matches the requested cell, or we're
          * matching all cells (cellp == NULL), and if we've requested to ping
@@ -231,7 +321,7 @@ static void cm_CheckServersSingular(afs_uint32 flags, cm_cell_t *cellp)
              ((isDown && (flags & CM_FLAG_CHECKDOWNSERVERS)) ||
                (!isDown && (flags & CM_FLAG_CHECKUPSERVERS))) &&
              ((!(flags & CM_FLAG_CHECKVLDBSERVERS) || 
-               !isFS && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
+               isVLDB && (flags & CM_FLAG_CHECKVLDBSERVERS)) &&
               (!(flags & CM_FLAG_CHECKFILESERVERS) || 
                  isFS && (flags & CM_FLAG_CHECKFILESERVERS)))) {
             doPing = 1;
@@ -380,7 +470,7 @@ static void cm_CheckServersMulti(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];
-                    xdr_free(caps[i].Capabilities_val, caps[i].Capabilities_len);
+                    xdr_free((xdrproc_t) xdr_Capabilities, &caps[i]);
                     caps[i].Capabilities_len = 0;
                     caps[i].Capabilities_val = 0;
                 } else {
@@ -837,7 +927,7 @@ void cm_SetServerPrefs(cm_server_t * serverp)
     }
 
     serverAddr = ntohl(serverp->addr.sin_addr.s_addr);
-    serverp->ipRank  = CM_IPRANK_LOW;  /* default setings */
+    serverp->ipRank  = CM_IPRANK_LOW;  /* default settings */
 
     for ( i=0; i < cm_noIPAddr; i++)
     {
@@ -921,14 +1011,15 @@ cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cell
 }
 
 cm_server_t *
-cm_FindServerByIP(afs_uint32 ipaddr, int type)
+cm_FindServerByIP(afs_uint32 ipaddr, unsigned short port, int type)
 {
     cm_server_t *tsp;
 
     lock_ObtainRead(&cm_serverLock);
     for (tsp = cm_allServersp; tsp; tsp = tsp->allNextp) {
         if (tsp->type == type &&
-            tsp->addr.sin_addr.S_un.S_addr == ipaddr)
+            tsp->addr.sin_addr.S_un.S_addr == ipaddr &&
+            (tsp->addr.sin_port == port || tsp->addr.sin_port == 0))
             break;
     }
 
@@ -1292,11 +1383,11 @@ 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);
 
+    if (*list == NULL)
+        goto done;
+
     while (*current)
     {
         nextp = &(*current)->next;
@@ -1318,6 +1409,8 @@ void cm_FreeServerList(cm_serverRef_t** list, afs_uint32 flags)
         }
     }
   
+  done:
+
     lock_ReleaseWrite(&cm_serverLock);
 }
 
@@ -1336,7 +1429,8 @@ int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
     if (lock)
         lock_ObtainRead(&cm_serverLock);
   
-    sprintf(output, "%s - dumping servers - cm_numFileServers=%d, cm_numVldbServers=%d\r\n", 
+    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);
   
@@ -1361,9 +1455,12 @@ int cm_DumpServers(FILE *outputFile, char *cookie, int lock)
         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, 
+        sprintf(output,
+                 "%s - tsp=0x%p cell=%s addr=%-15s port=%u 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,
+                 ntohs(tsp->addr.sin_port), 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);