properly mark servers down for rx errors except OPCODE
[openafs.git] / src / afs / afs_server.c
index 8b594a1..49dc24e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * 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
  * afsi_SetServerIPRank
  * afs_GetServer
  * afs_ActivateServer
- * 
+ *
  *
  * Local:
  * HaveCallBacksFrom
  * CheckVLServer
  * afs_SortOneServer
  * afs_SetServerPrefs
- * 
+ *
  */
 #include <afsconfig.h>
 #include "afs/param.h"
 
-RCSID
-    ("$Header$");
 
 #include "afs/stds.h"
 #include "afs/sysincludes.h"   /* Standard vendor system headers */
@@ -47,10 +45,10 @@ RCSID
 #ifdef AFS_SGI62_ENV
 #include "h/hashing.h"
 #endif
-#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN60_ENV)
+#if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV)
 #include <netinet/in_var.h>
 #endif /* AFS_HPUX110_ENV */
-#ifdef AFS_DARWIN60_ENV
+#ifdef AFS_DARWIN_ENV
 #include <net/if_var.h>
 #endif
 #endif /* !defined(UKERNEL) */
@@ -132,8 +130,8 @@ GetUpDownStats(struct server *srv)
 void
 afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
 {
-    register struct server *a_serverP = sa->server;
-    register struct srvAddr *sap;
+    struct server *a_serverP = sa->server;
+    struct srvAddr *sap;
     osi_timeval_t currTime, *currTimeP;        /*Current time */
     afs_int32 downTime;                /*Computed downtime, in seconds */
     struct afs_stats_SrvUpDownInfo *upDownP;   /*Ptr to up/down info record */
@@ -155,7 +153,7 @@ afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
                return;
            }
        }
-       /* 
+       /*
         * All ips are down we treat the whole server down
         */
        a_serverP->flags |= SRVR_ISDOWN;
@@ -239,14 +237,14 @@ afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
 }                              /*MarkServerUpOrDown */
 
 
-void
+afs_int32
 afs_ServerDown(struct srvAddr *sa)
 {
-    register struct server *aserver = sa->server;
+    struct server *aserver = sa->server;
 
     AFS_STATCNT(ServerDown);
     if (aserver->flags & SRVR_ISDOWN || sa->sa_flags & SRVADDR_ISDOWN)
-       return;
+       return 0;
     afs_MarkServerUpOrDown(sa, SRVR_ISDOWN);
     if (sa->sa_portal == aserver->cell->vlport)
        print_internet_address
@@ -254,7 +252,7 @@ afs_ServerDown(struct srvAddr *sa)
     else
        print_internet_address("afs: Lost contact with file server ", sa, "",
                               1);
-
+    return 1;
 }                              /*ServerDown */
 
 
@@ -262,9 +260,9 @@ afs_ServerDown(struct srvAddr *sa)
 int
 afs_HaveCallBacksFrom(struct server *aserver)
 {
-    register afs_int32 now;
-    register int i;
-    register struct vcache *tvc;
+    afs_int32 now;
+    int i;
+    struct vcache *tvc;
 
     AFS_STATCNT(HaveCallBacksFrom);
     now = osi_Time();          /* for checking for expired callbacks */
@@ -275,7 +273,7 @@ afs_HaveCallBacksFrom(struct server *aserver)
             * from the required host
             */
            if (aserver == tvc->callback && tvc->cbExpires >= now
-               && ((tvc->states & CRO) == 0))
+               && ((tvc->f.states & CRO) == 0))
                return 1;
        }
     }
@@ -285,11 +283,11 @@ afs_HaveCallBacksFrom(struct server *aserver)
 
 
 static void
-CheckVLServer(register struct srvAddr *sa, struct vrequest *areq)
+CheckVLServer(struct srvAddr *sa, struct vrequest *areq)
 {
-    register struct server *aserver = sa->server;
-    register struct conn *tc;
-    register afs_int32 code;
+    struct server *aserver = sa->server;
+    struct afs_conn *tc;
+    afs_int32 code;
 
     AFS_STATCNT(CheckVLServer);
     /* Ping dead servers to see if they're back */
@@ -315,7 +313,7 @@ CheckVLServer(register struct srvAddr *sa, struct vrequest *areq)
      * with old vlsevers), then we treat this server as running again
      */
     if (code == 0 || (code <= -450 && code >= -470)) {
-       if (tc->srvr == sa) {
+       if (tc->parent->srvr == sa) {
            afs_MarkServerUpOrDown(sa, 0);
            print_internet_address("afs: volume location server ", sa,
                                   " is back up", 2);
@@ -383,25 +381,25 @@ afs_CountServers(void)
     afs_stats_cmperf.fs_UpDown[0].sumOfRecordAges = 0;
     afs_stats_cmperf.fs_UpDown[0].ageOfYoungestRecord = 0;
     afs_stats_cmperf.fs_UpDown[0].ageOfOldestRecord = 0;
-    memset((char *)afs_stats_cmperf.fs_UpDown[0].downIncidents, 0,
+    memset(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;
-    memset((char *)afs_stats_cmperf.fs_UpDown[1].downIncidents, 0,
+    memset(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;
-    memset((char *)afs_stats_cmperf.vl_UpDown[0].downIncidents, 0,
+    memset(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;
-    memset((char *)afs_stats_cmperf.vl_UpDown[1].downIncidents, 0,
+    memset(afs_stats_cmperf.vl_UpDown[1].downIncidents, 0,
           AFS_STATS_NUM_DOWNTIME_INCIDENTS_BUCKETS * sizeof(afs_int32));
 
     /*
@@ -424,7 +422,7 @@ afs_CountServers(void)
 
            /*
             * Any further tallying for this record will only be done if it has
-            * been activated. 
+            * been activated.
             */
            if ((currSrvP->flags & AFS_SERVER_FLAG_ACTIVATED)
                && currSrvP->addr && currSrvP->cell) {
@@ -488,6 +486,43 @@ afs_CountServers(void)
 }                              /*afs_CountServers */
 
 
+void
+ForceAllNewConnections(void)
+{
+    int srvAddrCount;
+    struct srvAddr **addrs;
+    struct srvAddr *sa;
+    afs_int32 i, j;
+
+    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) {
+           srvAddrCount++;
+       }
+    }
+
+    addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
+    osi_Assert(addrs != NULL);
+    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;
+       }
+    }
+
+    ReleaseReadLock(&afs_xsrvAddr);
+    ReleaseReadLock(&afs_xserver);
+    for (i = 0; i < j; i++) {
+        sa = addrs[i];
+       ForceNewConnections(sa);
+    }
+}
+
 /* check down servers (if adown), or running servers (if !adown) */
 void
 afs_CheckServers(int adown, struct cell *acellp)
@@ -495,24 +530,31 @@ afs_CheckServers(int adown, struct cell *acellp)
     struct vrequest treq;
     struct server *ts;
     struct srvAddr *sa;
-    struct conn *tc;
+    struct afs_conn *tc;
     afs_int32 i, j;
     afs_int32 code;
     afs_int32 start, end = 0, delta;
-    afs_int32 m_error;
     osi_timeval_t tv;
     struct unixuser *tu;
     char tbuffer[CVBS];
     int srvAddrCount;
     struct srvAddr **addrs;
-    struct conn **conns;
+    struct afs_conn **conns;
     int nconns;
-    struct rx_connection **rxconns;      
-    afs_int32 *conntimer, *deltas;
+    struct rx_connection **rxconns;
+    afs_int32 *conntimer, *deltas, *results;
+    Capabilities *caps = NULL;
 
     AFS_STATCNT(afs_CheckServers);
 
-    conns = (struct conn **)0;
+    /*
+     * No sense in doing the server checks if we are running in disconnected
+     * mode
+     */
+    if (AFS_IS_DISCONNECTED)
+        return;
+
+    conns = (struct afs_conn **)0;
     rxconns = (struct rx_connection **) 0;
     conntimer = 0;
     nconns = 0;
@@ -530,6 +572,7 @@ afs_CheckServers(int adown, struct cell *acellp)
     }
 
     addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
+    osi_Assert(addrs != NULL);
     j = 0;
     for (i = 0; i < NSERVERS; i++) {
        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
@@ -542,10 +585,20 @@ afs_CheckServers(int adown, struct cell *acellp)
     ReleaseReadLock(&afs_xsrvAddr);
     ReleaseReadLock(&afs_xserver);
 
-    conns = (struct conn **)afs_osi_Alloc(j * sizeof(struct conn *));
-    rxconns = (struct rx_connection **)afs_osi_Alloc(j * sizeof(struct rx_connection *));
-    conntimer = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
-    deltas = (afs_int32 *)afs_osi_Alloc(j * sizeof (afs_int32));
+    conns = afs_osi_Alloc(j * sizeof(struct afs_conn *));
+    osi_Assert(conns != NULL);
+    rxconns = afs_osi_Alloc(j * sizeof(struct rx_connection *));
+    osi_Assert(rxconns != NULL);
+    conntimer = afs_osi_Alloc(j * sizeof (afs_int32));
+    osi_Assert(conntimer != NULL);
+    deltas = afs_osi_Alloc(j * sizeof (afs_int32));
+    osi_Assert(deltas != NULL);
+    results = afs_osi_Alloc(j * sizeof (afs_int32));
+    osi_Assert(results != NULL);
+
+    caps = afs_osi_Alloc(j * sizeof (Capabilities));
+    osi_Assert(caps != NULL);
+    memset(caps, 0, j * sizeof(Capabilities));
 
     for (i = 0; i < j; i++) {
        deltas[i] = 0;
@@ -582,8 +635,8 @@ afs_CheckServers(int adown, struct cell *acellp)
            continue;
 
        if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(sa->server)
-           || (tc->srvr->server == afs_setTimeHost)) {
-           conns[nconns]=tc; 
+           || (tc->parent->srvr->server == afs_setTimeHost)) {
+           conns[nconns]=tc;
            rxconns[nconns]=tc->id;
            if (sa->sa_flags & SRVADDR_ISDOWN) {
                rx_SetConnDeadTime(tc->id, 3);
@@ -595,48 +648,96 @@ afs_CheckServers(int adown, struct cell *acellp)
        }
     } /* Outer loop over addrs */
 
-    start = osi_Time();         /* time the gettimeofday call */
-    AFS_GUNLOCK(); 
+    AFS_GUNLOCK();
     multi_Rx(rxconns,nconns)
       {
-       tv.tv_sec = tv.tv_usec = 0;
-       multi_RXAFS_GetTime(&tv.tv_sec, &tv.tv_usec);
-       tc = conns[multi_i];
-       sa = tc->srvr;
-       if (conntimer[multi_i] == 0)
-         rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
-       end = osi_Time();
-       m_error=multi_error;
-       if ((start == end) && !multi_error)
-         deltas[multi_i] = end - tv.tv_sec;
-       
+       multi_RXAFS_GetCapabilities(&caps[multi_i]);
+       results[multi_i] = multi_error;
       } multi_End;
-    AFS_GLOCK(); 
-    
-    for(i=0;i<nconns;i++){
-      tc = conns[i];
-      sa = tc->srvr;
-      
-      if (( m_error >= 0 ) && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->srvr == sa)) {
-       /* server back up */
-       print_internet_address("afs: file server ", sa, " is back up", 2);
-       
-       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_GLOCK();
+
+    for ( i = 0 ; i < nconns ; i++ ) {
+       ts = addrs[i]->server;
+       if ( !ts )
+           continue;
+       ts->capabilities = 0;
+       ts->flags |= SCAPS_KNOWN;
+       if ( results[i] == RXGEN_OPCODE ) {
+           /* Mark server as up - it responded */
+           results[i] = 0;
+           continue;
        }
-      } else {
-       if (m_error < 0) {
-         /* server crashed */
-         afs_ServerDown(sa);
-         ForceNewConnections(sa);  /* multi homed clients */
+       if ( results[i] >= 0 )
+           /* we currently handle 32-bits of capabilities */
+           if (caps[i].Capabilities_len > 0) {
+               ts->capabilities = caps[i].Capabilities_val[0];
+               xdr_free((xdrproc_t)xdr_Capabilities, &caps[i]);
+               caps[i].Capabilities_val = NULL;
+               caps[i].Capabilities_len = 0;
+           }
+    }
+
+    if ( afs_setTime != 0 ) {
+       start = osi_Time();         /* time the gettimeofday call */
+       AFS_GUNLOCK();
+       if ( afs_setTimeHost == NULL ) {
+           multi_Rx(rxconns,nconns)
+             {
+                 tv.tv_sec = tv.tv_usec = 0;
+                 multi_RXAFS_GetTime(
+                     (afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
+                 tc = conns[multi_i];
+                 sa = tc->parent->srvr;
+                 if (conntimer[multi_i] == 1)
+                     rx_SetConnDeadTime(tc->id, afs_rx_deadtime);
+                 end = osi_Time();
+                 results[multi_i]=multi_error;
+                 if ((start == end) && !multi_error)
+                     deltas[multi_i] = end - tv.tv_sec;
+             } multi_End;
+           }
+       else {                  /* find and query setTimeHost only */
+           for ( i = 0 ; i < j ; i++ ) {
+               if ( conns[i] == NULL || conns[i]->parent->srvr == NULL )
+                   continue;
+               if ( conns[i]->parent->srvr->server == afs_setTimeHost ) {
+                   tv.tv_sec = tv.tv_usec = 0;
+                   results[i] = RXAFS_GetTime(rxconns[i],
+                               (afs_uint32 *)&tv.tv_sec, (afs_uint32 *)&tv.tv_usec);
+                   end = osi_Time();
+                   if ((start == end) && !results[i])
+                       deltas[i] = end - tv.tv_sec;
+                   break;
+               }
+           }
+       }
+       AFS_GLOCK();
+    }
+
+    for(i=0;i<nconns;i++){
+       tc = conns[i];
+       sa = tc->parent->srvr;
+
+       if (( results[i] >= 0 ) && (sa->sa_flags & SRVADDR_ISDOWN) && (tc->parent->srvr == sa)) {
+           /* server back up */
+           print_internet_address("afs: file server ", sa, " is back up", 2);
+
+           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);
+           }
+       } else {
+           if ((results[i] < 0) && (results[i] != RXGEN_OPCODE)) {
+               /* server crashed */
+               afs_ServerDown(sa);
+               ForceNewConnections(sa);  /* multi homed clients */
+           }
        }
-      }
     }
 
     /*
@@ -649,17 +750,17 @@ afs_CheckServers(int adown, struct cell *acellp)
        for (i=0; i<nconns; i++) {
            delta = deltas[i];
            tc = conns[i];
-           sa = tc->srvr;
-           
-           if ((tc->srvr->server == afs_setTimeHost ||
+           sa = tc->parent->srvr;
+
+           if ((tc->parent->srvr->server == afs_setTimeHost ||
                 /* Sync only to a server in the local cell */
                 (afs_setTimeHost == (struct server *)0 &&
                  afs_IsPrimaryCell(sa->server->cell)))) {
                /* set the time */
                char msgbuf[90];  /* strlen("afs: setting clock...") + slop */
                delta = end - tv.tv_sec;   /* how many secs fast we are */
-               
-               afs_setTimeHost = tc->srvr->server;
+
+               afs_setTimeHost = tc->parent->srvr->server;
                /* see if clock has changed enough to make it worthwhile */
                if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
                    end = osi_Time();
@@ -673,33 +774,33 @@ afs_CheckServers(int adown, struct cell *acellp)
                    if (delta > 0) {
                        strcpy(msgbuf, "afs: setting clock back ");
                        if (delta > AFS_MAXCHANGEBACK) {
-                           afs_strcat(msgbuf, 
-                                      afs_cv2string(&tbuffer[CVBS], 
+                           afs_strcat(msgbuf,
+                                      afs_cv2string(&tbuffer[CVBS],
                                                     AFS_MAXCHANGEBACK));
                            afs_strcat(msgbuf, " seconds (of ");
-                           afs_strcat(msgbuf, 
-                                      afs_cv2string(&tbuffer[CVBS], 
-                                                    delta - 
+                           afs_strcat(msgbuf,
+                                      afs_cv2string(&tbuffer[CVBS],
+                                                    delta -
                                                     AFS_MAXCHANGEBACK));
                            afs_strcat(msgbuf, ", via ");
-                           print_internet_address(msgbuf, sa, 
+                           print_internet_address(msgbuf, sa,
                                                   "); clock is still fast.",
                                                   0);
                        } else {
-                           afs_strcat(msgbuf, 
+                           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_strcat(msgbuf,
                                   afs_cv2string(&tbuffer[CVBS], -delta));
                        afs_strcat(msgbuf, " seconds (via ");
                        print_internet_address(msgbuf, sa, ").", 0);
                    }
                     /* We're only going to set it once; why bother looping? */
-                   break; 
+                   break;
                }
            }
        }
@@ -707,13 +808,15 @@ afs_CheckServers(int adown, struct cell *acellp)
     for (i = 0; i < nconns; i++) {
        afs_PutConn(conns[i], SHARED_LOCK);     /* done with it now */
     }
-    
+
     afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
-    afs_osi_Free(conns, j * sizeof(struct conn *));
+    afs_osi_Free(conns, j * sizeof(struct afs_conn *));
     afs_osi_Free(rxconns, j * sizeof(struct rx_connection *));
     afs_osi_Free(conntimer, j * sizeof(afs_int32));
     afs_osi_Free(deltas, j * sizeof(afs_int32));
-    
+    afs_osi_Free(results, j * sizeof(afs_int32));
+    afs_osi_Free(caps, j * sizeof(Capabilities));
+
 } /*afs_CheckServers*/
 
 
@@ -760,19 +863,19 @@ afs_FindServer(afs_int32 aserver, afs_uint16 aport, afsUUID * uuidp,
 
 /* Rules:
    X = (aX + c) % m
-   m is a power of two 
+   m is a power of two
    a % 8 is 5
    a is 0.73m  should be 0.01m .. 0.99m
    c is more or less immaterial.  1 or a is suggested.
-  
+
 NB:  LOW ORDER BITS are not very random.  To get small random numbers,
-     treat result as <1, with implied binary point, and multiply by 
+     treat result as <1, with implied binary point, and multiply by
      desired modulus.
 NB:  Has to be unsigned, since shifts on signed quantities may preserve
      the sign bit.
 */
-/* added rxi_getaddr() to try to get as much initial randomness as 
-   possible, since at least one customer reboots ALL their clients 
+/* added rxi_getaddr() to try to get as much initial randomness as
+   possible, since at least one customer reboots ALL their clients
    simultaneously -- so osi_Time is bound to be the same on some of the
    clients.  This is probably OK, but I don't want to see too much of it.
 */
@@ -783,7 +886,7 @@ unsigned int
 afs_random(void)
 {
     static afs_int32 state = 0;
-    register int i;
+    int i;
 
     AFS_STATCNT(afs_random);
     if (!state) {
@@ -808,7 +911,7 @@ afs_random(void)
 /* returns int 0..14 using the high bits of a pseudo-random number instead of
    the low bits, as the low bits are "less random" than the high ones...
    slight roundoff error exists, an excercise for the reader.
-   need to multiply by something with lots of ones in it, so multiply by 
+   need to multiply by something with lots of ones in it, so multiply by
    8 or 16 is right out.
  */
 int
@@ -897,7 +1000,7 @@ afs_SortServers(struct server *aservers[], int count)
 }                              /*afs_SortServers */
 
 /* afs_SetServerPrefs is rather system-dependent.  It pokes around in kernel
-   data structures to determine what the local IP addresses and subnet masks 
+   data structures to determine what the local IP addresses and subnet masks
    are in order to choose which server(s) are on the local subnet.
 
    As I see it, there are several cases:
@@ -909,19 +1012,19 @@ afs_SortServers(struct server *aservers[], int count)
    4. The server is on a different logical subnet or net than this host, but
    this host is a 'metric 0 gateway' to it.  Ie, two address-spaces share
    one physical medium.
-   5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the 
+   5. This host has a direct (point-to-point, ie, PPP or SLIP) link to the
    server.
    6. This host and the server are disjoint.
 
    That is a rough order of preference.  If a point-to-point link has a high
-   metric, I'm assuming that it is a very slow link, and putting it at the 
-   bottom of the list (at least until RX works better over slow links).  If 
-   its metric is 1, I'm assuming that it's relatively fast (T1) and putting 
+   metric, I'm assuming that it is a very slow link, and putting it at the
+   bottom of the list (at least until RX works better over slow links).  If
+   its metric is 1, I'm assuming that it's relatively fast (T1) and putting
    it ahead of #6.
    It's not easy to check for case #4, so I'm ignoring it for the time being.
 
    BSD "if" code keeps track of some rough network statistics (cf 'netstat -i')
-   That could be used to prefer certain servers fairly easily.  Maybe some 
+   That could be used to prefer certain servers fairly easily.  Maybe some
    other time...
 
    NOTE: this code is very system-dependent, and very dependent on the TCP/IP
@@ -1050,8 +1153,8 @@ typedef struct ill_s {
 /*
  * The IP addresses and ranks are determined by afsd (in user space) and
  * passed into the kernel at startup time through the AFSOP_ADVISEADDR
- * system call. These are stored in the data structure 
- * called 'afs_cb_interface'. 
+ * system call. These are stored in the data structure
+ * called 'afs_cb_interface'.
  *
  * struct srvAddr *sa;         remote server
  * afs_int32 addr;                one of my local addr in net order
@@ -1092,9 +1195,10 @@ afsi_SetServerIPRank(struct srvAddr *sa, afs_int32 addr,
            sa->sa_iprank = afs_min(sa->sa_iprank, MED);
        }
     }
+    return;
 }
 #else /* AFS_USERSPACE_IP_ADDR */
-#if (! defined(AFS_SUN5_ENV)) && !defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
+#if (! defined(AFS_SUN5_ENV)) && (! defined(AFS_DARWIN_ENV)) && (! defined(AFS_OBSD47_ENV)) && defined(USEIFADDR)
 void
 afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
 {
@@ -1131,31 +1235,44 @@ afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
 #endif /* IFF_POINTTOPOINT */
 }
 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR) */
-#if defined(AFS_DARWIN60_ENV) && defined(USEIFADDR)
+#if (defined(AFS_DARWIN_ENV) || defined(AFS_OBSD47_ENV)) && defined(USEIFADDR)
 #ifndef afs_min
 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
 #endif
 void
-afsi_SetServerIPRank(sa, ifa)
-     struct srvAddr *sa;
-     struct ifaddr *ifa;
+afsi_SetServerIPRank(struct srvAddr *sa, rx_ifaddr_t ifa)
 {
+    struct sockaddr sout;
     struct sockaddr_in *sin;
     int t;
 
     afs_uint32 subnetmask, myAddr, myNet, myDstaddr, mySubnet, netMask;
     afs_uint32 serverAddr;
 
-    if (ifa->ifa_addr->sa_family != AF_INET)
+    if (rx_ifaddr_address_family(ifa) != AF_INET)
        return;
-    sin = (struct sockaddr_in *)ifa->ifa_addr;
-    myAddr = ntohl(sin->sin_addr.s_addr);      /* one of my IP addr in host order */
+    t = rx_ifaddr_address(ifa, &sout, sizeof(sout));
+    if (t != 0) {
+       sin = (struct sockaddr_in *)&sout;
+       myAddr = ntohl(sin->sin_addr.s_addr);   /* one of my IP addr in host order */
+    } else {
+       myAddr = 0;
+    }
     serverAddr = ntohl(sa->sa_ip);     /* server's IP addr in host order */
-    sin = (struct sockaddr_in *)ifa->ifa_netmask;
-    subnetmask = ntohl(sin->sin_addr.s_addr);  /* subnet mask in host order */
-    sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
-    if (sin)
-       myDstaddr = sin->sin_addr.s_addr;
+    t = rx_ifaddr_netmask(ifa, &sout, sizeof(sout));
+    if (t != 0) {
+       sin = (struct sockaddr_in *)&sout;
+       subnetmask = ntohl(sin->sin_addr.s_addr);       /* subnet mask in host order */
+    } else {
+       subnetmask = 0;
+    }
+    t = rx_ifaddr_dstaddress(ifa, &sout, sizeof(sout));
+    if (t != 0) {
+       sin = (struct sockaddr_in *)&sout;
+       myDstaddr = ntohl(sin->sin_addr.s_addr);
+    } else {
+       myDstaddr = 0;
+    }
 
     if (IN_CLASSA(myAddr))
        netMask = IN_CLASSA_NET;
@@ -1174,20 +1291,20 @@ afsi_SetServerIPRank(sa, ifa)
            if (serverAddr == myAddr) { /* same machine */
                sa->sa_iprank = afs_min(sa->sa_iprank, TOPR);
            } else {            /* same subnet */
-               sa->sa_iprank = afs_min(sa->sa_iprank, HI + ifa->ifa_metric);
+               sa->sa_iprank = afs_min(sa->sa_iprank, HI + rx_ifnet_metric(rx_ifaddr_ifnet(ifa)));
            }
        } else {                /* same net */
-           sa->sa_iprank = afs_min(sa->sa_iprank, MED + ifa->ifa_metric);
+           sa->sa_iprank = afs_min(sa->sa_iprank, MED + rx_ifnet_metric(rx_ifaddr_ifnet(ifa)));
        }
     }
 #ifdef  IFF_POINTTOPOINT
     /* check for case #4 -- point-to-point link */
-    if ((ifa->ia_ifp->if_flags & IFF_POINTOPOINT)
+    if ((rx_ifnet_flags(rx_ifaddr_ifnet(ifa)) & IFF_POINTOPOINT)
        && (myDstaddr == serverAddr)) {
-       if (ifa->ia_ifp->if_metric >= (MAXDEFRANK - MED) / PPWEIGHT)
+       if (rx_ifnet_metric(rx_ifaddr_ifnet(ifa)) >= (MAXDEFRANK - MED) / PPWEIGHT)
            t = MAXDEFRANK;
        else
-           t = MED + (PPWEIGHT << ifa->->ifa_metric);
+           t = MED + (PPWEIGHT << rx_ifnet_metric(rx_ifaddr_ifnet(ifa)));
        if (sa->sa_iprank > t)
            sa->sa_iprank = t;
        }
@@ -1198,14 +1315,16 @@ afsi_SetServerIPRank(sa, ifa)
 
 #ifdef AFS_SGI62_ENV
 static int
-
-  afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
-                    caddr_t arg2) {
+afsi_enum_set_rank(struct hashbucket *h, caddr_t mkey, caddr_t arg1,
+                  caddr_t arg2)
+{
     afsi_SetServerIPRank((struct srvAddr *)arg1, (struct in_ifaddr *)h);
     return 0;                  /* Never match, so we enumerate everyone */
 }
 #endif                         /* AFS_SGI62_ENV */
-static int afs_SetServerPrefs(struct srvAddr *sa) {
+static int
+afs_SetServerPrefs(struct srvAddr *sa)
+{
 #if     defined(AFS_USERSPACE_IP_ADDR)
     int i;
 
@@ -1217,23 +1336,74 @@ static int afs_SetServerPrefs(struct srvAddr *sa) {
 #else                          /* AFS_USERSPACE_IP_ADDR */
 #if    defined(AFS_SUN5_ENV)
 #ifdef AFS_SUN510_ENV
-    ill_walk_context_t ctx;
+    int i = 0;
 #else
     extern struct ill_s *ill_g_headp;
     long *addr = (long *)ill_g_headp;
-#endif
     ill_t *ill;
     ipif_t *ipif;
+#endif
     int subnet, subnetmask, net, netmask;
 
     if (sa)
          sa->sa_iprank = 0;
 #ifdef AFS_SUN510_ENV
-    for (ill = ILL_START_WALK_ALL(&ctx) ; ill ; ill = ill_next(&ctx, ill)) {
+    rw_enter(&afsifinfo_lock, RW_READER);
+
+    for (i = 0; (afsifinfo[i].ipaddr != NULL) && (i < ADDRSPERSITE); i++) {
+
+       if (IN_CLASSA(afsifinfo[i].ipaddr)) {
+           netmask = IN_CLASSA_NET;
+       } else if (IN_CLASSB(afsifinfo[i].ipaddr)) {
+           netmask = IN_CLASSB_NET;
+       } else if (IN_CLASSC(afsifinfo[i].ipaddr)) {
+           netmask = IN_CLASSC_NET;
+       } else {
+           netmask = 0;
+       }
+       net = afsifinfo[i].ipaddr & netmask;
+
+#ifdef notdef
+       if (!s) {
+           if (!rx_IsLoopbackAddr(afsifinfo[i].ipaddr)) {      /* ignore loopback */
+               *cnt += 1;
+               if (*cnt > 16)
+                   return;
+               *addrp++ = afsifinfo[i].ipaddr;
+           }
+       } else
+#endif /* notdef */
+        {
+            /* XXXXXX Do the individual ip ranking below XXXXX */
+            if ((sa->sa_ip & netmask) == net) {
+                if ((sa->sa_ip & subnetmask) == subnet) {
+                    if (afsifinfo[i].ipaddr == sa->sa_ip) {   /* ie, ME!  */
+                        sa->sa_iprank = TOPR;
+                    } else {
+                        sa->sa_iprank = HI + afsifinfo[i].metric; /* case #2 */
+                    }
+                } else {
+                    sa->sa_iprank = MED + afsifinfo[i].metric;    /* case #3 */
+                }
+            } else {
+                    sa->sa_iprank = LO + afsifinfo[i].metric;     /* case #4 */
+            }
+            /* check for case #5 -- point-to-point link */
+            if ((afsifinfo[i].flags & IFF_POINTOPOINT)
+                && (afsifinfo[i].dstaddr == sa->sa_ip)) {
+
+                    if (afsifinfo[i].metric >= (MAXDEFRANK - MED) / PPWEIGHT)
+                        sa->sa_iprank = MAXDEFRANK;
+                    else
+                        sa->sa_iprank = MED + (PPWEIGHT << afsifinfo[i].metric);
+            }
+        }
+    }
+
+    rw_exit(&afsifinfo_lock);
 #else
     for (ill = (struct ill_s *)*addr /*ill_g_headp */ ; ill;
         ill = ill->ill_next) {
-#endif
 #ifdef AFS_SUN58_ENV
        /* Make sure this is an IPv4 ILL */
        if (ill->ill_isv6)
@@ -1243,7 +1413,7 @@ static int afs_SetServerPrefs(struct srvAddr *sa) {
            subnet = ipif->ipif_local_addr & ipif->ipif_net_mask;
            subnetmask = ipif->ipif_net_mask;
            /*
-            * Generate the local net using the local address and 
+            * Generate the local net using the local address and
             * whate we know about Class A, B and C networks.
             */
            if (IN_CLASSA(ipif->ipif_local_addr)) {
@@ -1258,7 +1428,7 @@ static int afs_SetServerPrefs(struct srvAddr *sa) {
            net = ipif->ipif_local_addr & netmask;
 #ifdef notdef
            if (!s) {
-               if (ipif->ipif_local_addr != 0x7f000001) {      /* ignore loopback */
+               if (!rx_IsLoopbackAddr(ipif->ipif_local_addr)) {        /* ignore loopback */
                    *cnt += 1;
                    if (*cnt > 16)
                        return;
@@ -1293,9 +1463,10 @@ static int afs_SetServerPrefs(struct srvAddr *sa) {
            }
        }
     }
+#endif /* AFS_SUN510_ENV */
 #else
 #ifndef USEIFADDR
-    struct ifnet *ifn = NULL;
+    rx_ifnet_t ifn = NULL;
     struct in_ifaddr *ifad = (struct in_ifaddr *)0;
     struct sockaddr_in *sin;
 
@@ -1360,15 +1531,36 @@ static int afs_SetServerPrefs(struct srvAddr *sa) {
 #ifdef AFS_SGI62_ENV
     (void)hash_enum(&hashinfo_inaddr, afsi_enum_set_rank, HTF_INET, NULL,
                    (caddr_t) sa, NULL);
-#elif defined(AFS_DARWIN60_ENV)
+#elif defined(AFS_DARWIN80_ENV)
+    {
+       errno_t t;
+       unsigned int count;
+       int cnt=0, m, j;
+       rx_ifaddr_t *ifads;
+       rx_ifnet_t *ifns;
+
+       if (!ifnet_list_get(AF_INET, &ifns, &count)) {
+           for (m = 0; m < count; m++) {
+               if (!ifnet_get_address_list(ifns[m], &ifads)) {
+                   for (j = 0; ifads[j] != NULL && cnt < ADDRSPERSITE; j++) {
+                       afsi_SetServerIPRank(sa, ifads[j]);
+                       cnt++;
+                   }
+                   ifnet_free_address_list(ifads);
+               }
+           }
+           ifnet_list_free(ifns);
+       }
+    }
+#elif defined(AFS_DARWIN_ENV)
     {
-       struct ifnet *ifn;
-       struct ifaddr *ifa;
+       rx_ifnet_t ifn;
+       rx_ifaddr_t ifa;
          TAILQ_FOREACH(ifn, &ifnet, if_link) {
            TAILQ_FOREACH(ifa, &ifn->if_addrhead, ifa_link) {
                afsi_SetServerIPRank(sa, ifa);
     }}}
-#elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
+#elif defined(AFS_FBSD_ENV)
     {
        struct in_ifaddr *ifa;
          TAILQ_FOREACH(ifa, &in_ifaddrhead, ia_link) {
@@ -1381,6 +1573,13 @@ static int afs_SetServerPrefs(struct srvAddr *sa) {
        for (ifa = in_ifaddr.tqh_first; ifa; ifa = ifa->ia_list.tqe_next)
            afsi_SetServerIPRank(sa, ifa);
     }
+#elif defined(AFS_NBSD40_ENV)
+     {
+       extern struct in_ifaddrhead in_ifaddrhead;
+       struct in_ifaddr *ifa;
+       for (ifa = in_ifaddrhead.tqh_first; ifa; ifa = ifa->ia_list.tqe_next)
+           afsi_SetServerIPRank(sa, ifa);
+     }
 #else
     {
        struct in_ifaddr *ifa;
@@ -1388,8 +1587,10 @@ static int afs_SetServerPrefs(struct srvAddr *sa) {
            afsi_SetServerIPRank(sa, ifa);
     }}
 #endif
-    end:
 #endif                         /* USEIFADDR */
+#ifndef USEIFADDR
+    end:
+#endif
 #endif                         /* AFS_SUN5_ENV */
 #endif                         /* else AFS_USERSPACE_IP_ADDR */
     if (sa)
@@ -1409,7 +1610,9 @@ static int afs_SetServerPrefs(struct srvAddr *sa) {
  * clean up all other structures that may reference it.
  * The afs_xserver and afs_xsrvAddr locks are assumed taken.
  */
-void afs_FlushServer(struct server *srvp) {
+void
+afs_FlushServer(struct server *srvp)
+{
     afs_int32 i;
     struct server *ts, **pts;
 
@@ -1423,7 +1626,7 @@ void afs_FlushServer(struct server *srvp) {
     if (srvp->cbrs) {
        struct afs_cbr *cb, *cbnext;
 
-         MObtainWriteLock(&afs_xvcb, 300);
+         ObtainWriteLock(&afs_xvcb, 300);
        for (cb = srvp->cbrs; cb; cb = cbnext) {
            cbnext = cb->next;
            afs_FreeCBR(cb);
@@ -1464,7 +1667,9 @@ void afs_FlushServer(struct server *srvp) {
  * The afs_xserver and afs_xsrvAddr locks are assumed taken.
  *    It is not removed from the afs_srvAddrs hash chain.
  */
-void afs_RemoveSrvAddr(struct srvAddr *sap) {
+void
+afs_RemoveSrvAddr(struct srvAddr *sap)
+{
     struct srvAddr **psa, *sa;
     struct server *srv;
 
@@ -1486,16 +1691,70 @@ void afs_RemoveSrvAddr(struct srvAddr *sap) {
     }
 }
 
+/* afs_GetCapabilities
+ * Try and retrieve capabilities of a given file server. Carps on actual
+ * failure. Servers are not expected to support this RPC. */
+void
+afs_GetCapabilities(struct server *ts)
+{
+    Capabilities caps = {0, NULL};
+    struct vrequest treq;
+    struct afs_conn *tc;
+    struct unixuser *tu;
+    afs_int32 code;
+
+    if ( !ts || !ts->cell )
+       return;
+    if ( !afs_osi_credp )
+       return;
+
+    if ((code = afs_InitReq(&treq, afs_osi_credp)))
+       return;
+    tu = afs_GetUser(treq.uid, ts->cell->cellNum, SHARED_LOCK);
+    if ( !tu )
+       return;
+    tc = afs_ConnBySA(ts->addr, ts->cell->fsport, ts->cell->cellNum, tu, 0, 1,
+                                                               SHARED_LOCK);
+    if ( !tc )
+       return;
+    /* InitCallBackStateN, triggered by our RPC, may need this */
+    ReleaseWriteLock(&afs_xserver);
+    code = RXAFS_GetCapabilities(tc->id, &caps);
+    ObtainWriteLock(&afs_xserver, 723);
+    /* we forced a conn above; important we mark it down if needed */
+    if ((code < 0) && (code != RXGEN_OPCODE)) {
+       afs_ServerDown(tc->parent->srvr);
+       ForceNewConnections(tc->parent->srvr); /* multi homed clients */
+    }
+    afs_PutConn(tc, SHARED_LOCK);
+    if ( code && code != RXGEN_OPCODE ) {
+       afs_warn("RXAFS_GetCapabilities failed with code %d\n", code);
+       /* better not be anything to free. we failed! */
+       return;
+    }
+
+    ts->flags |= SCAPS_KNOWN;
+
+    if ( caps.Capabilities_len > 0 ) {
+       ts->capabilities = caps.Capabilities_val[0];
+       xdr_free((xdrproc_t)xdr_Capabilities, &caps);
+       caps.Capabilities_len = 0;
+       caps.Capabilities_val = NULL;
+    }
+
+}
+
 /* afs_GetServer()
  * Return an updated and properly initialized server structure
  * corresponding to the server ID, cell, and port specified.
  * If one does not exist, then one will be created.
  * aserver and aport must be in NET byte order.
  */
-struct server *afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers,
-                            afs_int32 acell, u_short aport,
-                            afs_int32 locktype, afsUUID * uuidp,
-                            afs_int32 addr_uniquifier) {
+struct server *
+afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
+             u_short aport, afs_int32 locktype, afsUUID * uuidp,
+             afs_int32 addr_uniquifier)
+{
     struct server *oldts = 0, *ts, *newts, *orphts = 0;
     struct srvAddr *oldsa, *newsa, *nextsa, *orphsa;
     u_short fsport;
@@ -1545,11 +1804,11 @@ struct server *afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers,
     if (oldts) {
        newts = oldts;
     } else {
-       newts = (struct server *)afs_osi_Alloc(sizeof(struct server));
+       newts = afs_osi_Alloc(sizeof(struct server));
        if (!newts)
            panic("malloc of server struct");
        afs_totalServers++;
-       memset((char *)newts, 0, sizeof(struct server));
+       memset(newts, 0, sizeof(struct server));
 
        /* Add the server struct to the afs_servers[] hash chain */
        srvhash =
@@ -1590,11 +1849,11 @@ struct server *afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers,
        if (oldsa) {
            newsa = oldsa;
        } else {
-           newsa = (struct srvAddr *)afs_osi_Alloc(sizeof(struct srvAddr));
+           newsa = afs_osi_Alloc(sizeof(struct srvAddr));
            if (!newsa)
                panic("malloc of srvAddr struct");
            afs_totalSrvAddrs++;
-           memset((char *)newsa, 0, sizeof(struct srvAddr));
+           memset(newsa, 0, sizeof(struct srvAddr));
 
            /* Add the new srvAddr to the afs_srvAddrs[] hash chain */
            newsa->next_bkt = afs_srvAddrs[iphash];
@@ -1620,11 +1879,7 @@ struct server *afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers,
 
        /* Compute preference values and resort */
        if (!newsa->sa_iprank) {
-           if (aport == fsport) {
-               afs_SetServerPrefs(newsa);      /* new fileserver rank */
-           } else {
-               newsa->sa_iprank = 10000 + afs_randomMod127();  /* new vlserver rank */
-           }
+           afs_SetServerPrefs(newsa);  /* new server rank */
        }
     }
     afs_SortOneServer(newts);  /* Sort by rank */
@@ -1644,16 +1899,15 @@ struct server *afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers,
 
            /* Have a srvAddr struct. Now get a server struct (if not already) */
            if (!orphts) {
-               orphts =
-                   (struct server *)afs_osi_Alloc(sizeof(struct server));
+               orphts = afs_osi_Alloc(sizeof(struct server));
                if (!orphts)
                    panic("malloc of lo server struct");
-               memset((char *)orphts, 0, sizeof(struct server));
+               memset(orphts, 0, sizeof(struct server));
                afs_totalServers++;
 
                /* Add the orphaned server to the afs_servers[] hash chain.
                 * Its iphash does not matter since we never look up the server
-                * in the afs_servers table by its ip address (only by uuid - 
+                * in the afs_servers table by its ip address (only by uuid -
                 * which this has none).
                 */
                iphash = SHash(aserverp[k]);
@@ -1690,11 +1944,17 @@ struct server *afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers,
     }
 
     ReleaseWriteLock(&afs_xsrvAddr);
+
+    if ( aport == AFS_FSPORT && !(newts->flags & SCAPS_KNOWN))
+       afs_GetCapabilities(newts);
+
     ReleaseWriteLock(&afs_xserver);
     return (newts);
 }                              /* afs_GetServer */
 
-void afs_ActivateServer(struct srvAddr *sap) {
+void
+afs_ActivateServer(struct srvAddr *sap)
+{
     osi_timeval_t currTime;    /*Filled with current time */
     osi_timeval_t *currTimeP;  /*Ptr to above */
     struct afs_stats_SrvUpDownInfo *upDownP;   /*Ptr to up/down info record */
@@ -1719,30 +1979,51 @@ void afs_ActivateServer(struct srvAddr *sap) {
     }
 }
 
-
-void shutdown_server()
+void
+afs_RemoveAllConns(void)
 {
     int i;
+    struct server *ts, *nts;
+    struct srvAddr *sa;
 
-    for (i = 0; i < NSERVERS; i++) {
-       struct server *ts, *next;
+    ObtainReadLock(&afs_xserver);
+    ObtainWriteLock(&afs_xconn, 1001);
 
-        ts = afs_servers[i];
-        while(ts) {
-           next = ts->next;
-           afs_osi_Free(ts, sizeof(struct server));
-           ts = next;
+    /*printf("Destroying connections ... ");*/
+    for (i = 0; i < NSERVERS; i++) {
+        for (ts = afs_servers[i]; ts; ts = nts) {
+            nts = ts->next;
+            for (sa = ts->addr; sa; sa = sa->next_sa) {
+                if (sa->conns) {
+                    afs_ReleaseConns(sa->conns);
+                    sa->conns = NULL;
+                }
+            }
         }
     }
+    /*printf("done\n");*/
 
-    for (i = 0; i < NSERVERS; i++) {
-       struct srvAddr *sa, *next;
+    ReleaseWriteLock(&afs_xconn);
+    ReleaseReadLock(&afs_xserver);
 
-        sa = afs_srvAddrs[i];
-        while(sa) {
-           next = sa->next_bkt;
-           afs_osi_Free(sa, sizeof(struct srvAddr));
-           sa = next;
-        }
+}
+
+void
+afs_MarkAllServersUp(void)
+{
+    int i;
+    struct server *ts;
+    struct srvAddr *sa;
+
+    ObtainWriteLock(&afs_xserver, 721);
+    ObtainWriteLock(&afs_xsrvAddr, 722);
+    for (i = 0; i< NSERVERS; i++) {
+       for (ts = afs_servers[i]; ts; ts = ts->next) {
+           for (sa = ts->addr; sa; sa = sa->next_sa) {
+               afs_MarkServerUpOrDown(sa, 0);
+           }
+       }
     }
+    ReleaseWriteLock(&afs_xsrvAddr);
+    ReleaseWriteLock(&afs_xserver);
 }