FBSD: switch afsi_SetServerIPRank implementation
[openafs.git] / src / afs / afs_server.c
index 010f0b8..3f4e8d2 100644 (file)
 #include "afs/afs_stats.h"     /* afs statistics */
 #include "rx/rx_multi.h"
 
-#if    defined(AFS_SUN56_ENV)
+#if    defined(AFS_SUN5_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 <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
 #include <inet/ip.h>
 #endif
 
 /* Exported variables */
 afs_rwlock_t afs_xserver;      /* allocation lock for servers */
-struct server *afs_setTimeHost = 0;    /* last host we used for time */
 struct server *afs_servers[NSERVERS];  /* Hashed by server`s uuid & 1st ip */
 afs_rwlock_t afs_xsrvAddr;     /* allocation lock for srvAddrs */
 struct srvAddr *afs_srvAddrs[NSERVERS];        /* Hashed by server's ip */
@@ -157,11 +154,6 @@ afs_MarkServerUpOrDown(struct srvAddr *sa, int a_isDown)
         * All ips are down we treat the whole server down
         */
        a_serverP->flags |= SRVR_ISDOWN;
-       /*
-        * If this was our time server, search for another time server
-        */
-       if (a_serverP == afs_setTimeHost)
-           afs_setTimeHost = 0;
     } else {
        sa->sa_flags &= ~SRVADDR_ISDOWN;
        /* If any ips are up, the server is also marked up */
@@ -560,151 +552,19 @@ CkSrv_MarkUpDown(struct afs_conn **conns, int nconns, afs_int32 *results)
 }
 
 void
-CkSrv_SetTime(struct rx_connection **rxconns, int nconns, int nservers,
-             struct afs_conn **conns, struct srvAddr **addrs)
-{
-    struct afs_conn *tc;
-    afs_int32 start, end = 0, delta;
-    osi_timeval_t tv;
-    struct srvAddr *sa;
-    afs_int32 *conntimer, *results, *deltas;
-    afs_int32 i = 0;
-    char tbuffer[CVBS];
-
-    conntimer = afs_osi_Alloc(nservers * sizeof (afs_int32));
-    osi_Assert(conntimer != NULL);
-    results = afs_osi_Alloc(nservers * sizeof (afs_int32));
-    osi_Assert(results != NULL);
-    deltas = afs_osi_Alloc(nservers * sizeof (afs_int32));
-    osi_Assert(deltas != NULL);
-
-    /* make sure we're starting from zero */
-    memset(&deltas, 0, sizeof(deltas));
-
-    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(rxconns[multi_i], 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 < nservers ; 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();
-
-    if ( afs_setTimeHost == NULL )
-       CkSrv_MarkUpDown(conns, nconns, results);
-    else /* We lack info for other than this host */
-       CkSrv_MarkUpDown(&conns[i], 1, &results[i]);
-
-    /*
-     * 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 (afs_setTime != 0) {
-       for (i=0; i<nconns; i++) {
-           delta = deltas[i];
-           tc = conns[i];
-           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->parent->srvr->server;
-               /* see if clock has changed enough to make it worthwhile */
-               if (delta >= AFS_MINCHANGE || delta <= -AFS_MINCHANGE) {
-                   end = osi_Time();
-                   if (delta > AFS_MAXCHANGEBACK) {
-                       /* setting clock too far back, just do it a little */
-                       tv.tv_sec = end - AFS_MAXCHANGEBACK;
-                   } else {
-                       tv.tv_sec = end - delta;
-                   }
-                   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);
-                   }
-                    /* We're only going to set it once; why bother looping? */
-                   break;
-               }
-           }
-       }
-    }
-    afs_osi_Free(conntimer, nservers * sizeof(afs_int32));
-    afs_osi_Free(deltas, nservers * sizeof(afs_int32));
-    afs_osi_Free(results, nservers * sizeof(afs_int32));
-}
-
-void
-CkSrv_GetCaps(struct rx_connection **rxconns, int nconns, int nservers,
-             struct afs_conn **conns, struct srvAddr **addrs)
+CkSrv_GetCaps(int nconns, struct rx_connection **rxconns,
+             struct afs_conn **conns)
 {
     Capabilities *caps;
     afs_int32 *results;
     afs_int32 i;
     struct server *ts;
 
-    caps = afs_osi_Alloc(nservers * sizeof (Capabilities));
+    caps = afs_osi_Alloc(nconns * sizeof (Capabilities));
     osi_Assert(caps != NULL);
-    memset(caps, 0, nservers * sizeof(Capabilities));
+    memset(caps, 0, nconns * sizeof(Capabilities));
 
-    results = afs_osi_Alloc(nservers * sizeof (afs_int32));
+    results = afs_osi_Alloc(nconns * sizeof (afs_int32));
     osi_Assert(results != NULL);
 
     AFS_GUNLOCK();
@@ -716,7 +576,7 @@ CkSrv_GetCaps(struct rx_connection **rxconns, int nconns, int nservers,
     AFS_GLOCK();
 
     for ( i = 0 ; i < nconns ; i++ ) {
-       ts = addrs[i]->server;
+       ts = conns[i]->parent->srvr->server;
        if ( !ts )
            continue;
        ts->capabilities = 0;
@@ -737,16 +597,15 @@ CkSrv_GetCaps(struct rx_connection **rxconns, int nconns, int nservers,
     }
     CkSrv_MarkUpDown(conns, nconns, results);
 
-    afs_osi_Free(caps, nservers * sizeof(Capabilities));
-    afs_osi_Free(results, nservers * sizeof(afs_int32));
+    afs_osi_Free(caps, nconns * sizeof(Capabilities));
+    afs_osi_Free(results, nconns * sizeof(afs_int32));
 }
 
 /* check down servers (if adown), or running servers (if !adown) */
 void
 afs_CheckServers(int adown, struct cell *acellp)
 {
-    afs_LoopServers(adown?AFS_LS_DOWN:AFS_LS_UP, acellp, 1, CkSrv_GetCaps,
-                   afs_setTime?CkSrv_SetTime:NULL);
+    afs_LoopServers(adown?AFS_LS_DOWN:AFS_LS_UP, acellp, 1, CkSrv_GetCaps, NULL);
 }
 
 /* adown: AFS_LS_UP   - check only up
@@ -754,12 +613,10 @@ afs_CheckServers(int adown, struct cell *acellp)
  *        AFS_LS_ALL  - check all */
 void
 afs_LoopServers(int adown, struct cell *acellp, int vlalso,
-               void (*func1) (struct rx_connection **rxconns, int nconns,
-                              int nservers, struct afs_conn **conns,
-                              struct srvAddr **addrs),
-               void (*func2) (struct rx_connection **rxconns, int nconns,
-                              int nservers, struct afs_conn **conns,
-                              struct srvAddr **addrs))
+               void (*func1) (int nservers, struct rx_connection **rxconns,
+                              struct afs_conn **conns),
+               void (*func2) (int nservers, struct rx_connection **rxconns,
+                              struct afs_conn **conns))
 {
     struct vrequest treq;
     struct server *ts;
@@ -773,7 +630,7 @@ afs_LoopServers(int adown, struct cell *acellp, int vlalso,
     struct afs_conn **conns;
     int nconns;
     struct rx_connection **rxconns;
-    afs_int32 *conntimer, *results;
+    afs_int32 *conntimer;
 
     AFS_STATCNT(afs_CheckServers);
 
@@ -821,8 +678,6 @@ afs_LoopServers(int adown, struct cell *acellp, int vlalso,
     osi_Assert(rxconns != NULL);
     conntimer = afs_osi_Alloc(j * sizeof (afs_int32));
     osi_Assert(conntimer != NULL);
-    results = afs_osi_Alloc(j * sizeof (afs_int32));
-    osi_Assert(results != NULL);
 
     for (i = 0; i < j; i++) {
        struct rx_connection *rxconn;
@@ -859,8 +714,7 @@ afs_LoopServers(int adown, struct cell *acellp, int vlalso,
        if (!tc)
            continue;
 
-       if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(sa->server)
-           || (tc->parent->srvr->server == afs_setTimeHost)) {
+       if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(sa->server)) {
            conns[nconns]=tc;
            rxconns[nconns]=rxconn;
            if (sa->sa_flags & SRVADDR_ISDOWN) {
@@ -873,10 +727,13 @@ afs_LoopServers(int adown, struct cell *acellp, int vlalso,
        }
     } /* Outer loop over addrs */
 
-    (*func1)(rxconns, nconns, j, conns, addrs);
+    afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
+    addrs = NULL;
+
+    (*func1)(nconns, rxconns, conns);
 
     if (func2) {
-       (*func2)(rxconns, nconns, j, conns, addrs);
+       (*func2)(nconns, rxconns, conns);
     }
 
     for (i = 0; i < nconns; i++) {
@@ -885,11 +742,9 @@ afs_LoopServers(int adown, struct cell *acellp, int vlalso,
        afs_PutConn(conns[i], rxconns[i], SHARED_LOCK);     /* done with it now */
     }
 
-    afs_osi_Free(addrs, srvAddrCount * sizeof(*addrs));
     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(results, j * sizeof(afs_int32));
 
 } /*afs_CheckServers*/
 
@@ -1118,108 +973,6 @@ afs_SortServers(struct server *aservers[], int count)
 
 #define        USEIFADDR
 
-
-#if    defined(AFS_SUN5_ENV) && ! defined(AFS_SUN56_ENV)
-#include <inet/common.h>
-/* IP interface structure, one per local address */
-typedef struct ipif_s {
-     /**/ struct ipif_s *ipif_next;
-    struct ill_s *ipif_ill;    /* Back pointer to our ill */
-    long ipif_id;              /* Logical unit number */
-    u_int ipif_mtu;            /* Starts at ipif_ill->ill_max_frag */
-    afs_int32 ipif_local_addr; /* Local IP address for this if. */
-    afs_int32 ipif_net_mask;   /* Net mask for this interface. */
-    afs_int32 ipif_broadcast_addr;     /* Broadcast addr for this interface. */
-    afs_int32 ipif_pp_dst_addr;        /* Point-to-point dest address. */
-    u_int ipif_flags;          /* Interface flags. */
-    u_int ipif_metric;         /* BSD if metric, for compatibility. */
-    u_int ipif_ire_type;       /* LOCAL or LOOPBACK */
-    mblk_t *ipif_arp_down_mp;  /* Allocated at time arp comes up to
-                                * prevent awkward out of mem condition
-                                * later
-                                */
-    mblk_t *ipif_saved_ire_mp; /* Allocated for each extra IRE_SUBNET/
-                                * RESOLVER on this interface so that
-                                * they can survive ifconfig down.
-                                */
-    /*
-     * The packet counts in the ipif contain the sum of the
-     * packet counts in dead IREs that were affiliated with
-     * this ipif.
-     */
-    u_long ipif_fo_pkt_count;  /* Forwarded thru our dead IREs */
-    u_long ipif_ib_pkt_count;  /* Inbound packets for our dead IREs */
-    u_long ipif_ob_pkt_count;  /* Outbound packets to our dead IREs */
-    unsigned int
-      ipif_multicast_up:1,     /* We have joined the allhosts group */
-    : 0;
-} ipif_t;
-
-typedef struct ipfb_s {
-     /**/ struct ipf_s *ipfb_ipf;      /* List of ... */
-    kmutex_t ipfb_lock;                /* Protect all ipf in list */
-} ipfb_t;
-
-typedef struct ilm_s {
-     /**/ afs_int32 ilm_addr;
-    int ilm_refcnt;
-    u_int ilm_timer;           /* IGMP */
-    struct ipif_s *ilm_ipif;   /* Back pointer to ipif */
-    struct ilm_s *ilm_next;    /* Linked list for each ill */
-} ilm_t;
-
-typedef struct ill_s {
-     /**/ struct ill_s *ill_next;      /* Chained in at ill_g_head. */
-    struct ill_s **ill_ptpn;   /* Pointer to previous next. */
-    queue_t *ill_rq;           /* Read queue. */
-    queue_t *ill_wq;           /* Write queue. */
-
-    int ill_error;             /* Error value sent up by device. */
-
-    ipif_t *ill_ipif;          /* Interface chain for this ILL. */
-    u_int ill_ipif_up_count;   /* Number of IPIFs currently up. */
-    u_int ill_max_frag;                /* Max IDU. */
-    char *ill_name;            /* Our name. */
-    u_int ill_name_length;     /* Name length, incl. terminator. */
-    u_int ill_subnet_type;     /* IRE_RESOLVER or IRE_SUBNET. */
-    u_int ill_ppa;             /* Physical Point of Attachment num. */
-    u_long ill_sap;
-    int ill_sap_length;                /* Including sign (for position) */
-    u_int ill_phys_addr_length;        /* Excluding the sap. */
-    mblk_t *ill_frag_timer_mp; /* Reassembly timer state. */
-    ipfb_t *ill_frag_hash_tbl; /* Fragment hash list head. */
-
-    queue_t *ill_bind_pending_q;       /* Queue waiting for DL_BIND_ACK. */
-    ipif_t *ill_ipif_pending;  /* IPIF waiting for DL_BIND_ACK. */
-
-    /* ill_hdr_length and ill_hdr_mp will be non zero if
-     * the underlying device supports the M_DATA fastpath
-     */
-    int ill_hdr_length;
-
-    ilm_t *ill_ilm;            /* Multicast mebership for lower ill */
-
-    /* All non-nil cells between 'ill_first_mp_to_free' and
-     * 'ill_last_mp_to_free' are freed in ill_delete.
-     */
-#define        ill_first_mp_to_free    ill_hdr_mp
-    mblk_t *ill_hdr_mp;                /* Contains fastpath template */
-    mblk_t *ill_bcast_mp;      /* DLPI header for broadcasts. */
-    mblk_t *ill_bind_pending;  /* T_BIND_REQ awaiting completion. */
-    mblk_t *ill_resolver_mp;   /* Resolver template. */
-    mblk_t *ill_attach_mp;
-    mblk_t *ill_bind_mp;
-    mblk_t *ill_unbind_mp;
-    mblk_t *ill_detach_mp;
-#define        ill_last_mp_to_free     ill_detach_mp
-
-    u_int ill_frag_timer_running:1, ill_needs_attach:1, ill_is_ptp:1,
-       ill_priv_stream:1, ill_unbind_pending:1, ill_pad_to_bit_31:27;
-      MI_HRT_DCL(ill_rtime)
-      MI_HRT_DCL(ill_rtmp)
-} ill_t;
-#endif
-
 #ifdef AFS_USERSPACE_IP_ADDR
 #ifndef afs_min
 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
@@ -1272,7 +1025,7 @@ afsi_SetServerIPRank(struct srvAddr *sa, afs_int32 addr,
     return;
 }
 #else /* AFS_USERSPACE_IP_ADDR */
-#if (! defined(AFS_SUN5_ENV)) && (! defined(AFS_DARWIN_ENV)) && (! defined(AFS_OBSD47_ENV)) && defined(USEIFADDR)
+#if (! defined(AFS_SUN5_ENV)) && (! defined(AFS_DARWIN_ENV)) && (! defined(AFS_OBSD47_ENV)) && (! defined(AFS_FBSD_ENV)) && defined(USEIFADDR)
 void
 afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
 {
@@ -1309,7 +1062,7 @@ afsi_SetServerIPRank(struct srvAddr *sa, struct in_ifaddr *ifa)
 #endif /* IFF_POINTTOPOINT */
 }
 #endif /*(!defined(AFS_SUN5_ENV)) && defined(USEIFADDR) */
-#if (defined(AFS_DARWIN_ENV) || defined(AFS_OBSD47_ENV)) && defined(USEIFADDR)
+#if (defined(AFS_DARWIN_ENV) || defined(AFS_OBSD47_ENV) || defined(AFS_FBSD_ENV)) && defined(USEIFADDR)
 #ifndef afs_min
 #define afs_min(A,B) ((A)<(B)) ? (A) : (B)
 #endif
@@ -1318,7 +1071,11 @@ afsi_SetServerIPRank(struct srvAddr *sa, rx_ifaddr_t ifa)
 {
     struct sockaddr sout;
     struct sockaddr_in *sin;
+#if defined(AFS_DARWIN80_ENV) && !defined(UKERNEL)
     int t;
+#else
+    void *t;
+#endif
 
     afs_uint32 subnetmask, myAddr, myNet, myDstaddr, mySubnet, netMask;
     afs_uint32 serverAddr;
@@ -1478,11 +1235,9 @@ afs_SetServerPrefs(struct srvAddr *sa)
 #else
     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;
@@ -1637,8 +1392,12 @@ afs_SetServerPrefs(struct srvAddr *sa)
 #elif defined(AFS_FBSD_ENV)
     {
        struct in_ifaddr *ifa;
+#if defined(AFS_FBSD80_ENV)
+         TAILQ_FOREACH(ifa, &V_in_ifaddrhead, ia_link) {
+#else
          TAILQ_FOREACH(ifa, &in_ifaddrhead, ia_link) {
-           afsi_SetServerIPRank(sa, ifa);
+#endif
+           afsi_SetServerIPRank(sa, &ifa->ia_ifa);
     }}
 #elif defined(AFS_OBSD_ENV)
     {
@@ -1682,30 +1441,28 @@ afs_SetServerPrefs(struct srvAddr *sa)
 /* afs_FlushServer()
  * The addresses on this server struct has changed in some way and will
  * clean up all other structures that may reference it.
- * The afs_xserver and afs_xsrvAddr locks are assumed taken.
+ * The afs_xserver, afs_xvcb and afs_xsrvAddr locks are assumed taken.
  */
-void
-afs_FlushServer(struct server *srvp)
+static void
+afs_FlushServer(struct server *srvp, struct volume *tv)
 {
     afs_int32 i;
     struct server *ts, **pts;
 
     /* Find any volumes residing on this server and flush their state */
-      afs_ResetVolumes(srvp);
+    afs_ResetVolumes(srvp, tv);
 
     /* Flush all callbacks in the all vcaches for this specific server */
-      afs_FlushServerCBs(srvp);
+    afs_FlushServerCBs(srvp);
 
     /* Remove all the callbacks structs */
     if (srvp->cbrs) {
        struct afs_cbr *cb, *cbnext;
 
-         ObtainWriteLock(&afs_xvcb, 300);
        for (cb = srvp->cbrs; cb; cb = cbnext) {
            cbnext = cb->next;
            afs_FreeCBR(cb);
        } srvp->cbrs = (struct afs_cbr *)0;
-       ReleaseWriteLock(&afs_xvcb);
     }
 
     /* If no more srvAddr structs hanging off of this server struct,
@@ -1740,9 +1497,10 @@ afs_FlushServer(struct server *srvp)
  * remains connected to a server struct.
  * The afs_xserver and afs_xsrvAddr locks are assumed taken.
  *    It is not removed from the afs_srvAddrs hash chain.
+ * If resetting volumes, do not reset volume tv
  */
-void
-afs_RemoveSrvAddr(struct srvAddr *sap)
+static void
+afs_RemoveSrvAddr(struct srvAddr *sap, struct volume *tv)
 {
     struct srvAddr **psa, *sa;
     struct server *srv;
@@ -1761,7 +1519,7 @@ afs_RemoveSrvAddr(struct srvAddr *sap)
        sa->server = 0;
 
        /* Flush the server struct since it's IP address has changed */
-       afs_FlushServer(srv);
+       afs_FlushServer(srv, tv);
     }
 }
 
@@ -1791,6 +1549,7 @@ afs_GetCapabilities(struct server *ts)
     tc = afs_ConnBySA(ts->addr, ts->cell->fsport, ts->cell->cellNum, tu, 0, 1,
                                                                SHARED_LOCK,
                                                                 &rxconn);
+    afs_PutUser(tu, SHARED_LOCK);
     if ( !tc )
        return;
     /* InitCallBackStateN, triggered by our RPC, may need this */
@@ -1820,16 +1579,53 @@ afs_GetCapabilities(struct server *ts)
 
 }
 
-/* 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.
+static struct server *
+afs_SearchServer(u_short aport, afsUUID * uuidp, afs_int32 locktype,
+                struct server **oldts, afs_int32 addr_uniquifier)
+{
+    struct server *ts = afs_FindServer(0, aport, uuidp, locktype);
+    if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
+       /* Found a server struct that is multihomed and same
+        * uniqufier (same IP addrs). The above if statement is the
+        * same as in InstallUVolumeEntry().
+        */
+       return ts;
+    }
+    if (ts)
+       *oldts = ts;            /* Will reuse if same uuid */
+    return NULL;
+}
+
+/*!
+ * Return an updated and properly initialized server structure.
+ *
+ * Takes a server ID, cell, and port.
+ * If server does not exist, then one will be created.
+ * @param[in] aserverp
+ *      The server address in network byte order
+ * @param[in] nservers
+ *      The number of IP addresses claimed by the server
+ * @param[in] acell
+ *      The cell the server is in
+ * @param[in] aport
+ *      The port for the server (fileserver or vlserver) in network byte order
+ * @param[in] locktype
+ *      The type of lock to hold when iterating server hash (unused).
+ * @param[in] uuidp
+ *      The uuid for servers supporting one.
+ * @param[in] addr_uniquifier
+ *      The vldb-provider per-instantiated-server uniquifer counter.
+ * @param[in] tv
+ *      A volume not to reset information for if the server addresses
+ *      changed.
+ *
+ * @return
+ *      A server structure matching the request.
  */
 struct server *
-afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
+afs_GetServer(afs_uint32 *aserverp, afs_int32 nservers, afs_int32 acell,
              u_short aport, afs_int32 locktype, afsUUID * uuidp,
-             afs_int32 addr_uniquifier)
+             afs_int32 addr_uniquifier, struct volume *tv)
 {
     struct server *oldts = 0, *ts, *newts, *orphts = 0;
     struct srvAddr *oldsa, *newsa, *nextsa, *orphsa;
@@ -1843,7 +1639,7 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
     /* Check if the server struct exists and is up to date */
     if (!uuidp) {
        if (nservers != 1)
-           panic("afs_GetServer: incorect count of servers");
+           panic("afs_GetServer: incorrect count of servers");
        ObtainReadLock(&afs_xsrvAddr);
        ts = afs_FindServer(aserverp[0], aport, NULL, locktype);
        ReleaseReadLock(&afs_xsrvAddr);
@@ -1857,22 +1653,37 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
     } else {
        if (nservers <= 0)
            panic("afs_GetServer: incorrect count of servers");
-       ts = afs_FindServer(0, aport, uuidp, locktype);
-       if (ts && (ts->sr_addr_uniquifier == addr_uniquifier) && ts->addr) {
-           /* Found a server struct that is multihomed and same
-            * uniqufier (same IP addrs). The above if statement is the
-            * same as in InstallUVolumeEntry().
-            */
+
+       ts = afs_SearchServer(aport, uuidp, locktype, &oldts, addr_uniquifier);
+       if (ts) {
            ReleaseSharedLock(&afs_xserver);
            return ts;
        }
-       if (ts)
-           oldts = ts;         /* Will reuse if same uuid */
     }
 
-    UpgradeSToWLock(&afs_xserver, 36);
+    /*
+     * Lock hierarchy requires xvcb, then xserver. We *have* xserver.
+     * Do a little dance and see if we can grab xvcb. If not, we
+     * need to recheck that oldts is still right after a drop and reobtain.
+     */
+    if (EWOULDBLOCK == NBObtainWriteLock(&afs_xvcb, 300)) {
+       ReleaseSharedLock(&afs_xserver);
+       ObtainWriteLock(&afs_xvcb, 299);
+       ObtainWriteLock(&afs_xserver, 35);
+
+       /* we don't know what changed while we didn't hold the lock */
+       oldts = 0;
+       ts = afs_SearchServer(aport, uuidp, locktype, &oldts,
+                             addr_uniquifier);
+       if (ts) {
+           ReleaseWriteLock(&afs_xserver);
+           ReleaseWriteLock(&afs_xvcb);
+           return ts;
+       }
+    } else {
+       UpgradeSToWLock(&afs_xserver, 36);
+    }
     ObtainWriteLock(&afs_xsrvAddr, 116);
-
     srvcount = afs_totalServers;
 
     /* Reuse/allocate a new server structure */
@@ -1913,7 +1724,7 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
                break;
        }
        if (oldsa && (oldsa->server != newts)) {
-           afs_RemoveSrvAddr(oldsa);   /* Remove from its server struct */
+           afs_RemoveSrvAddr(oldsa, tv);       /* Remove from its server struct */
            oldsa->next_sa = newts->addr;       /* Add to the  new server struct */
            newts->addr = oldsa;
        }
@@ -1994,7 +1805,7 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
            /* Hang the srvAddr struct off of the server structure. The server
             * may have multiple srvAddrs, but it won't be marked multihomed.
             */
-           afs_RemoveSrvAddr(orphsa);  /* remove */
+           afs_RemoveSrvAddr(orphsa, tv);      /* remove */
            orphsa->next_sa = orphts->addr;     /* hang off server struct */
            orphts->addr = orphsa;
            orphsa->server = orphts;
@@ -2002,6 +1813,8 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
            orphsa->sa_flags &= ~SRVADDR_MH;    /* Not multihomed */
        }
     }
+    /* We can't need this below, and won't reacquire */
+    ReleaseWriteLock(&afs_xvcb);
 
     srvcount = afs_totalServers - srvcount;    /* # servers added and removed */
     if (srvcount) {
@@ -2015,6 +1828,8 @@ afs_GetServer(afs_uint32 * aserverp, afs_int32 nservers, afs_int32 acell,
        if (afs_stats_cmperf.srvRecords > afs_stats_cmperf.srvRecordsHWM)
            afs_stats_cmperf.srvRecordsHWM = afs_stats_cmperf.srvRecords;
     }
+    /* We can't need this below, and won't reacquire */
+    ReleaseWriteLock(&afs_xvcb);
 
     ReleaseWriteLock(&afs_xsrvAddr);