afs-checkservers-improve-lock-granularity-20011102
[openafs.git] / src / afs / afs_server.c
index 9d280e1..142fe8d 100644 (file)
@@ -1,13 +1,13 @@
-/* Copyright (C) 1995, 1989, 1998 Transarc Corporation - All rights reserved */
 /*
- * For copyright information, see IPL which you accepted in order to
- * download this software.
- *
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ * 
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
  */
 
 /*
- * afs_server.c
- *
  * Implements:
  * afs_MarkServerUpOrDown
  * afs_ServerDown
  * afs_SetServerPrefs
  * 
  */
-#include "../afs/param.h"      /* Should be always first */
+#include <afsconfig.h>
+#include "../afs/param.h"
+
+RCSID("$Header$");
+
 #include "../afs/stds.h"
 #include "../afs/sysincludes.h"        /* Standard vendor system headers */
 
 #if    defined(AFS_SUN56_ENV)
 #include <inet/led.h>
 #include <inet/common.h>
+#if     defined(AFS_SUN58_ENV)
+# include <netinet/ip6.h>
+# define ipif_local_addr ipif_lcl_addr
+#  ifndef V4_PART_OF_V6
+#  define V4_PART_OF_V6(v6)       v6.s6_addr32[3]
+#  endif
+# endif
 #include <inet/ip.h>
 #endif
 
@@ -275,7 +286,7 @@ static void CheckVLServer(sa, areq)
 
     AFS_STATCNT(CheckVLServer);
     /* Ping dead servers to see if they're back */
-    if (!(aserver->flags & SRVR_ISDOWN) || (aserver->flags & SRVR_ISGONE))
+    if (!((aserver->flags & SRVR_ISDOWN) || (sa->sa_flags & SRVADDR_ISDOWN)) || (aserver->flags & SRVR_ISGONE))
        return;
     if (!aserver->cell)
        return; /* can't do much */
@@ -369,26 +380,22 @@ void afs_CountServers()
     afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges     = 0;
     afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
     afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord   = 0;
-    bzero((char *) afs_stats_cmperf.fs_UpDown[0].downIncidents,
-          AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
+    memset((char *) afs_stats_cmperf.fs_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
 
     afs_stats_cmperf.fs_UpDown[1].sumOfRecordAges     = 0;
     afs_stats_cmperf.fs_UpDown[1].ageOfYoungestRecord = 0;
     afs_stats_cmperf.fs_UpDown[1].ageOfOldestRecord   = 0;
-    bzero((char *) afs_stats_cmperf.fs_UpDown[1].downIncidents,
-          AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
+    memset((char *) afs_stats_cmperf.fs_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
 
     afs_stats_cmperf.vl_UpDown[0].sumOfRecordAges     = 0;
     afs_stats_cmperf.vl_UpDown[0].ageOfYoungestRecord = 0;
     afs_stats_cmperf.vl_UpDown[0].ageOfOldestRecord   = 0;
-    bzero((char *) afs_stats_cmperf.vl_UpDown[0].downIncidents,
-          AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
+    memset((char *) afs_stats_cmperf.vl_UpDown[0].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
 
     afs_stats_cmperf.vl_UpDown[1].sumOfRecordAges     = 0;
     afs_stats_cmperf.vl_UpDown[1].ageOfYoungestRecord = 0;
     afs_stats_cmperf.vl_UpDown[1].ageOfOldestRecord   = 0;
-    bzero((char *) afs_stats_cmperf.vl_UpDown[1].downIncidents,
-          AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
+    memset((char *) afs_stats_cmperf.vl_UpDown[1].downIncidents, 0, AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
 
     /*
      * Compute the current time, used to figure out server record ages.
@@ -497,13 +504,15 @@ void afs_CheckServers(adown, acellp)
     struct server *ts;
     struct srvAddr *sa;
     struct conn *tc;
-    afs_int32 i;
+    afs_int32 i, j;
     afs_int32 code;
     afs_int32 start, end, delta;
     osi_timeval_t tv;
     int setTimer;
     struct unixuser *tu;
     char tbuffer[CVBS];
+    int srvAddrCount;
+    struct srvAddr **addrs;
     XSTATS_DECLS;
 
     AFS_STATCNT(afs_CheckServers);
@@ -511,128 +520,152 @@ void afs_CheckServers(adown, acellp)
     ObtainReadLock(&afs_xserver);  /* Necessary? */
     ObtainReadLock(&afs_xsrvAddr);     
 
+    srvAddrCount = 0;
     for (i=0;i<NSERVERS;i++) {
-       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) { 
-         ts = sa->server;
-         if (!ts)
-            continue;
-         /* See if a cell to check was specified.  If it is spec'd and not
-          * this server's cell, just skip the server.
-          */
-         if (acellp && acellp != ts->cell)
-              continue;
-
-         if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN)) 
-             || (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
-              continue;
-         /* check vlserver with special code */
-         if (sa->sa_portal == AFS_VLPORT) {
-            CheckVLServer(sa, &treq);
-            continue;
-         }
+       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) { 
+           srvAddrCount++;
+       }
+    }
+
+    addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
+    j = 0;
+    for (i=0;i<NSERVERS;i++) {
+       for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) { 
+           if (j >= srvAddrCount) break;
+           addrs[j++] = sa;
+       }
+    }
 
-         if (!ts->cell) /* not really an active server, anyway, it must */
-            continue;   /* have just been added by setsprefs */ 
-         
-         /* get a connection, even if host is down; bumps conn ref count */
-         tu = afs_GetUser(treq.uid, ts->cell, SHARED_LOCK);
-         tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cell, tu,
-                           1/*force*/, 1/*create*/, SHARED_LOCK);
-         afs_PutUser(tu, SHARED_LOCK);
-         if (!tc)
-              continue;
-
-         if ((sa->sa_flags & SRVADDR_ISDOWN) || HaveCallBacksFrom(ts) ||
-             (tc->srvr->server == afs_setTimeHost)) {
-            if (sa->sa_flags & SRVADDR_ISDOWN) {
+    ReleaseReadLock(&afs_xsrvAddr);    
+    ReleaseReadLock(&afs_xserver);
+
+    for (i=0; i<j; i++) {
+       sa = addrs[i];
+       ts = sa->server;
+       if (!ts)
+           continue;
+
+       /* See if a cell to check was specified.  If it is spec'd and not
+        * this server's cell, just skip the server.
+        */
+       if (acellp && acellp != ts->cell)
+           continue;
+
+       if ((!adown && (sa->sa_flags & SRVADDR_ISDOWN)) ||
+           (adown && !(sa->sa_flags & SRVADDR_ISDOWN)))
+           continue;
+
+       /* check vlserver with special code */
+       if (sa->sa_portal == AFS_VLPORT) {
+           CheckVLServer(sa, &treq);
+           continue;
+       }
+
+       if (!ts->cell) /* not really an active server, anyway, it must */
+           continue;  /* have just been added by setsprefs */ 
+
+       /* get a connection, even if host is down; bumps conn ref count */
+       tu = afs_GetUser(treq.uid, ts->cell, SHARED_LOCK);
+       tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cell, tu,
+                         1/*force*/, 1/*create*/, SHARED_LOCK);
+       afs_PutUser(tu, SHARED_LOCK);
+       if (!tc) continue;
+
+       if ((sa->sa_flags & SRVADDR_ISDOWN) || HaveCallBacksFrom(ts) ||
+           (tc->srvr->server == afs_setTimeHost)) {
+           if (sa->sa_flags & SRVADDR_ISDOWN) {
                rx_SetConnDeadTime(tc->id, 3);
                setTimer = 1;
-            } else
-                 setTimer = 0;
-            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETTIME);
-            start = osi_Time();        /* time the gettimeofday call */
+           } else {
+               setTimer = 0;
+           }
+
+           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_GETTIME);
+           start = osi_Time();         /* time the gettimeofday call */
 #ifdef RX_ENABLE_LOCKS
-            AFS_GUNLOCK();
+           AFS_GUNLOCK();
 #endif /* RX_ENABLE_LOCKS */
-            code = RXAFS_GetTime(tc->id, &tv.tv_sec, &tv.tv_usec);
+           code = RXAFS_GetTime(tc->id, &tv.tv_sec, &tv.tv_usec);
 #ifdef RX_ENABLE_LOCKS
-            AFS_GLOCK();
+           AFS_GLOCK();
 #endif /* RX_ENABLE_LOCKS */
-            end = osi_Time();
-            XSTATS_END_TIME;
-            /*
-             * If we're supposed to set the time, and the call worked
-             * quickly (same second response) and this is the host we
-             * use for the time and the time is really different, then
-             * really set the time
-             */
-            if (code == 0 && start == end && afs_setTime != 0 &&
-                (tc->srvr->server == afs_setTimeHost ||
-                 /*
-                  * Sync only to a server in the local cell: cell(id)==1
-                  * or CPrimary.
-                  */
-                 (afs_setTimeHost == (struct server *)0 &&
-                  (ts->cell->cell == 1 || (ts->cell->states&CPrimary))))) {
-               char msgbuf[90];        /* strlen("afs: setting clock...") + slop */
+           end = osi_Time();
+           XSTATS_END_TIME;
+           /*
+            * If we're supposed to set the time, and the call worked
+            * quickly (same second response) and this is the host we
+            * use for the time and the time is really different, then
+            * really set the time
+            */
+           if (code == 0 && start == end && afs_setTime != 0 &&
+               (tc->srvr->server == afs_setTimeHost ||
+               /*
+                * Sync only to a server in the local cell: cell(id)==1
+                * or CPrimary.
+                */
+               (afs_setTimeHost == (struct server *)0 &&
+                (ts->cell->cell == 1 || (ts->cell->states&CPrimary))))) {
+
+               char msgbuf[90];  /* strlen("afs: setting clock...") + slop */
                /* set the time */
                delta = end - tv.tv_sec;   /* how many secs fast we are */
                /* see if clock has changed enough to make it worthwhile */
                if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
-                  if (delta > AFS_MAXCHANGEBACK) {
-                     /* setting clock too far back, just do it a little */
-                     tv.tv_sec = end - AFS_MAXCHANGEBACK;
-                  }
-                  afs_osi_SetTime(&tv);
-                  if (delta > 0) {
-                     strcpy(msgbuf, "afs: setting clock back ");
-                     if (delta > AFS_MAXCHANGEBACK) {
-                        afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], AFS_MAXCHANGEBACK));
-                        afs_strcat(msgbuf, " seconds (of ");
-                        afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta - AFS_MAXCHANGEBACK));
-                        afs_strcat(msgbuf, ", via ");
-                        print_internet_address(msgbuf, sa, "); clock is still fast.", 0);
-                     } else {
-                        afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta));
-                        afs_strcat(msgbuf, " seconds (via ");
-                        print_internet_address(msgbuf, sa, ").", 0);
-                     }
-                  }
-                  else {
-                     strcpy(msgbuf, "afs: setting clock ahead ");
-                     afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], -delta));
-                     afs_strcat(msgbuf, " seconds (via ");
-                     print_internet_address(msgbuf, sa, ").", 0);
-                  }
+                   if (delta > AFS_MAXCHANGEBACK) {
+                       /* setting clock too far back, just do it a little */
+                       tv.tv_sec = end - AFS_MAXCHANGEBACK;
+                   }
+                   afs_osi_SetTime(&tv);
+                   if (delta > 0) {
+                       strcpy(msgbuf, "afs: setting clock back ");
+                       if (delta > AFS_MAXCHANGEBACK) {
+                           afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], AFS_MAXCHANGEBACK));
+                           afs_strcat(msgbuf, " seconds (of ");
+                           afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta - AFS_MAXCHANGEBACK));
+                           afs_strcat(msgbuf, ", via ");
+                           print_internet_address(msgbuf, sa, "); clock is still fast.", 0);
+                       } else {
+                           afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], delta));
+                           afs_strcat(msgbuf, " seconds (via ");
+                           print_internet_address(msgbuf, sa, ").", 0);
+                       }
+                   } else {
+                       strcpy(msgbuf, "afs: setting clock ahead ");
+                       afs_strcat(msgbuf, afs_cv2string(&tbuffer[CVBS], -delta));
+                       afs_strcat(msgbuf, " seconds (via ");
+                       print_internet_address(msgbuf, sa, ").", 0);
+                   }
                }
                afs_setTimeHost = tc->srvr->server;
-            }
-            if (setTimer)
-                 rx_SetConnDeadTime(tc->id, 50);
-            if (code >= 0 && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
+           }
+           if (setTimer)
+               rx_SetConnDeadTime(tc->id, 50);
+           if (code >= 0 && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
                /* server back up */
                print_internet_address("afs: file server ", sa, " is back up", 2);
-               /* 
-                * XXX We should hold a server write lock here XXX
-                */
+
+               ObtainWriteLock(&afs_xserver, 244);
+               ObtainWriteLock(&afs_xsrvAddr, 245);    
                afs_MarkServerUpOrDown(sa, 0);
+               ReleaseWriteLock(&afs_xsrvAddr);
+               ReleaseWriteLock(&afs_xserver);
+
                if (afs_waitForeverCount) {
-                  afs_osi_Wakeup(&afs_waitForever);
+                   afs_osi_Wakeup(&afs_waitForever);
                }
-            }
-            else
-                 if (code < 0) {
-                    /* server crashed */
-                    afs_ServerDown(sa);
-                    ForceNewConnections(sa);  /* multi homed clients */
-                 }
-         }
+           } else {
+               if (code < 0) {
+                   /* server crashed */
+                   afs_ServerDown(sa);
+                   ForceNewConnections(sa);  /* multi homed clients */
+               }
+           }
+       }
 
-         afs_PutConn(tc, SHARED_LOCK); /* done with it now */
-       }   /* for each server loop */
-    }      /* for each server hash bucket loop */
-    ReleaseReadLock(&afs_xsrvAddr);    
-    ReleaseReadLock(&afs_xserver);
+       afs_PutConn(tc, SHARED_LOCK);   /* done with it now */
+    } /* Outer loop over addrs */
+
+    afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
 
 } /*afs_CheckServers*/
 
@@ -650,7 +683,7 @@ struct server *afs_FindServer (afs_int32 aserver, ushort aport,
        i = afs_uuid_hash(uuidp) % NSERVERS;
        for (ts = afs_servers[i]; ts; ts = ts->next) {
            if ( (ts->flags & SRVR_MULTIHOMED) &&
-                (bcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp)) == 0) &&
+                (memcmp((char *)uuidp, (char *)&ts->sr_uuid, sizeof(*uuidp)) == 0) &&
                 (!ts->addr || (ts->addr->sa_portal == aport)) )
                return ts;
        }
@@ -695,7 +728,7 @@ NB:  Has to be unsigned, since shifts on signed quantities may preserve
    clients.  This is probably OK, but I don't want to see too much of it.
 */
 
-#define        ranstage(x)     (x)= (afs_uint32) (3141592621*((afs_uint32)x)+1)
+#define        ranstage(x)     (x)= (afs_uint32) (3141592621U*((afs_uint32)x)+1)
 extern afs_int32 rxi_getaddr();
 
 unsigned int afs_random()
@@ -794,10 +827,13 @@ void afs_SortServers(struct server *aservers[], int count)
     for (i=0; i<count; i++) {
        if (!aservers[i]) break;
        for (low=i,j=i+1; j<=count; j++) {
-         if (!aservers[j]) break;
-         if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
-            low = j;
-         }
+          if ((!aservers[j]) || (!aservers[j]->addr)) 
+              break;
+          if ((!aservers[low]) || (!aservers[low]->addr))
+              break;
+          if (aservers[j]->addr->sa_iprank < aservers[low]->addr->sa_iprank) {
+              low = j;
+          }
        }
        if (low != i) {
          ts = aservers[i]; 
@@ -961,8 +997,8 @@ typedef struct ill_s {                      /**/
 #endif
 
 #ifdef AFS_USERSPACE_IP_ADDR
-#ifndef min
-#define min(A,B) ((A)<(B)) ? (A) : (B)
+#ifndef afs_min
+#define afs_min(A,B) ((A)<(B)) ? (A) : (B)
 #endif
 /*
  * The IP addresses and ranks are determined by afsd (in user space) and
@@ -993,12 +1029,12 @@ afsi_SetServerIPRank(sa, addr, subnetmask)
    if ( (serverAddr & netMask ) == myNet ) {
       if ( (serverAddr & subnetmask ) == mySubnet) {
         if ( serverAddr == myAddr ) {    /* same machine */
-          sa->sa_iprank = min(sa->sa_iprank, TOPR);
+          sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
         } else {                           /* same subnet */
-           sa->sa_iprank = min(sa->sa_iprank, HI);
+           sa->sa_iprank = afs_min(sa->sa_iprank, HI);
         }
       } else {                               /* same net */
-        sa->sa_iprank = min(sa->sa_iprank, MED);
+        sa->sa_iprank = afs_min(sa->sa_iprank, MED);
       }
    }
 }
@@ -1077,6 +1113,10 @@ static afs_SetServerPrefs(sa)
 
     if (sa) sa->sa_iprank= 0;
     for (ill = (struct ill_s *)*addr /*ill_g_headp*/; ill; ill = ill->ill_next ) {
+#ifdef AFS_SUN58_ENV
+       /* Make sure this is an IPv4 ILL */
+       if (ill->ill_isv6) continue;
+#endif
        for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next ) {
            subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
            subnetmask = ipif->ipif_net_mask;
@@ -1195,6 +1235,13 @@ static afs_SetServerPrefs(sa)
 #ifdef AFS_SGI62_ENV
     (void) hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
                     (caddr_t)sa, NULL);
+#elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
+    {
+        struct in_ifaddr *ifa;
+        TAILQ_FOREACH(ifa , &in_ifaddrhead, ia_link) {
+            afsi_SetServerIPRank(sa, ifa);
+        }
+    }
 #else
     {
        extern struct in_ifaddr *in_ifaddr;
@@ -1364,7 +1411,7 @@ struct server *afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers,
        newts = (struct server *) afs_osi_Alloc(sizeof(struct server));
        if (!newts) panic("malloc of server struct");
        afs_totalServers++;
-       bzero((char *)newts, sizeof(struct server));
+       memset((char *)newts, 0, sizeof(struct server));
 
        /* Add the server struct to the afs_servers[] hash chain */
        srvhash = (uuidp ? (afs_uuid_hash(uuidp)%NSERVERS) : SHash(aserverp[0]));
@@ -1405,7 +1452,7 @@ struct server *afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers,
          newsa = (struct srvAddr *) afs_osi_Alloc(sizeof(struct srvAddr));
          if (!newsa) panic("malloc of srvAddr struct");
          afs_totalSrvAddrs++;
-         bzero((char *)newsa, sizeof(struct srvAddr));
+         memset((char *)newsa, 0, sizeof(struct srvAddr));
 
          /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
          newsa->next_bkt = afs_srvAddrs[iphash];
@@ -1453,7 +1500,7 @@ struct server *afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers,
          if (!orphts) {
             orphts = (struct server *) afs_osi_Alloc(sizeof(struct server));
             if (!orphts) panic("malloc of lo server struct");
-            bzero((char *)orphts, sizeof(struct server));
+            memset((char *)orphts, 0, sizeof(struct server));
             afs_totalServers++;
 
             /* Add the orphaned server to the afs_servers[] hash chain.