viced/callback.c: Ignore dump write errors even harder
[openafs.git] / src / viced / callback.c
index 07f52f6..9d22156 100644 (file)
 #include <sys/file.h>
 #endif
 
+#include <afs/opr.h>
+#include <opr/lock.h>
 #include <afs/nfs.h>           /* yuck.  This is an abomination. */
-#include <lwp.h>
 #include <rx/rx.h>
+#include <rx/rx_queue.h>
 #include <afs/afscbint.h>
 #include <afs/afsutil.h>
-#include <lock.h>
 #include <afs/ihandle.h>
+#include <afs/partition.h>
 #include <afs/vnode.h>
 #include <afs/volume.h>
 #include "viced_prototypes.h"
@@ -410,7 +412,7 @@ FDel(struct FileEntry *fe)
 
     while (*p && *p != fei)
        p = &itofe(*p)->fnext;
-    osi_Assert(*p);
+    opr_Assert(*p);
     *p = fe->fnext;
     FreeFE(fe);
     return 0;
@@ -420,11 +422,13 @@ FDel(struct FileEntry *fe)
 int
 InitCallBack(int nblks)
 {
+    opr_Assert(nblks > 0);
+
     H_LOCK;
-    tfirst = CBtime(FT_ApproxTime());
+    tfirst = CBtime(time(NULL));
     /* N.B. The "-1", below, is because
      * FE[0] and CB[0] are not used--and not allocated */
-    FE = ((struct FileEntry *)(calloc(nblks, sizeof(struct FileEntry))));
+    FE = calloc(nblks, sizeof(struct FileEntry));
     if (!FE) {
        ViceLogThenPanic(0, ("Failed malloc in InitCallBack\n"));
     }
@@ -432,7 +436,7 @@ InitCallBack(int nblks)
     cbstuff.nFEs = nblks;
     while (cbstuff.nFEs)
        FreeFE(&FE[cbstuff.nFEs]);      /* This is correct */
-    CB = ((struct CallBack *)(calloc(nblks, sizeof(struct CallBack))));
+    CB = calloc(nblks, sizeof(struct CallBack));
     if (!CB) {
        ViceLogThenPanic(0, ("Failed malloc in InitCallBack\n"));
     }
@@ -457,10 +461,8 @@ XCallBackBulk_r(struct host * ahost, struct AFSFid * fids, afs_int32 nfids)
     int j;
     struct rx_connection *cb_conn = NULL;
 
-#ifdef ADAPT_MTU
     rx_SetConnDeadTime(ahost->callback_rxcon, 4);
     rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
-#endif
 
     code = 0;
     j = 0;
@@ -560,18 +562,18 @@ AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
     fe = FindFE(fid);
     if (type == CB_NORMAL) {
        time_out =
-           TimeCeiling(FT_ApproxTime() + TimeOut(fe ? fe->ncbs : 0) +
+           TimeCeiling(time(NULL) + TimeOut(fe ? fe->ncbs : 0) +
                        ServerBias);
        Thead = THead(CBtime(time_out));
     } else if (type == CB_VOLUME) {
-       time_out = TimeCeiling((60 * 120 + FT_ApproxTime()) + ServerBias);
+       time_out = TimeCeiling((60 * 120 + time(NULL)) + ServerBias);
        Thead = THead(CBtime(time_out));
     } else if (type == CB_BULK) {
        /* bulk status can get so many callbacks all at once, and most of them
         * are probably not for things that will be used for long.
         */
        time_out =
-           TimeCeiling(FT_ApproxTime() + ServerBias +
+           TimeCeiling(time(NULL) + ServerBias +
                        TimeOut(22 + (fe ? fe->ncbs : 0)));
        Thead = THead(CBtime(time_out));
     }
@@ -625,6 +627,7 @@ AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
        cb->cnext = 0;
        cb->fhead = fetoi(fe);
        cb->status = type;
+       cb->flags = 0;
        HAdd(cb, host);
        TAdd(cb, Thead);
     }
@@ -679,9 +682,22 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
     static struct AFSCBs tc = { 0, 0 };
     int multi_to_cba_map[MAX_CB_HOSTS];
 
-    osi_Assert(ncbas <= MAX_CB_HOSTS);
-
-    /* sort cba list to avoid makecall issues */
+    opr_Assert(ncbas <= MAX_CB_HOSTS);
+
+    /*
+     * When we issue a multi_Rx callback break, we must rx_NewCall a call for
+     * each host before we do anything. If there are no call channels
+     * available on the conn, we must wait for one of the existing calls to
+     * finish. If another thread is breaking callbacks at the same time, it is
+     * possible for us to be waiting on NewCall for one of their multi_Rx
+     * CallBack calls to finish, but they are waiting on NewCall for one of
+     * our calls to finish. So we deadlock.
+     *
+     * This can be thought of as similar to obtaining multiple locks at the
+     * same time. So if we establish an ordering, the possibility of deadlock
+     * goes away. Here we provide such an ordering, by sorting our CBAs
+     * according to CompareCBA.
+     */
     qsort(cba, ncbas, sizeof(struct cbstruct), CompareCBA);
 
     /* set up conns for multi-call */
@@ -694,10 +710,8 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
        multi_to_cba_map[j] = i;
        conns[j++] = thishost->callback_rxcon;
 
-#ifdef ADAPT_MTU
        rx_SetConnDeadTime(thishost->callback_rxcon, 4);
        rx_SetConnHardDeadTime(thishost->callback_rxcon, AFS_HARDDEADTIME);
-#endif
     }
 
     if (j) {                   /* who knows what multi would do with 0 conns? */
@@ -792,16 +806,21 @@ BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
 {
     struct FileEntry *fe;
     struct CallBack *cb, *nextcb;
-    struct cbstruct cbaDef[MAX_CB_HOSTS], *cba = cbaDef;
-    unsigned int ncbas, cbaAlloc = MAX_CB_HOSTS;
+    struct cbstruct cba[MAX_CB_HOSTS];
+    int ncbas;
     struct AFSCBFids tf;
     int hostindex;
     char hoststr[16];
 
-    ViceLog(7,
-           ("BCB: BreakCallBack(Host %p all but %s:%d, (%u,%u,%u))\n",
-            xhost, afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
-            fid->Volume, fid->Vnode, fid->Unique));
+    if (xhost)
+       ViceLog(7,
+               ("BCB: BreakCallBack(Host %p all but %s:%d, (%u,%u,%u))\n",
+                xhost, afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
+                fid->Volume, fid->Vnode, fid->Unique));
+    else
+       ViceLog(7,
+               ("BCB: BreakCallBack(No Host, (%u,%u,%u))\n",
+               fid->Volume, fid->Vnode, fid->Unique));
 
     H_LOCK;
     cbstuff.BreakCallBacks++;
@@ -809,7 +828,7 @@ BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
     if (!fe) {
        goto done;
     }
-    hostindex = h_htoi(xhost);
+    hostindex = xhost ? h_htoi(xhost) : 0;
     cb = itocb(fe->firstcb);
     if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
        /* the most common case is what follows the || */
@@ -818,12 +837,31 @@ BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
     tf.AFSCBFids_len = 1;
     tf.AFSCBFids_val = fid;
 
-       for (ncbas = 0; cb ; cb = nextcb) {
+    /* Set CBFLAG_BREAKING flag on all CBs we're looking at. We do this so we
+     * can loop through all relevant CBs while dropping H_LOCK, and not lose
+     * track of which CBs we want to look at. If we look at all CBs over and
+     * over again, we can loop indefinitely as new CBs are added. */
+    for (; cb; cb = nextcb) {
+       nextcb = itocb(cb->cnext);
+
+       if ((cb->hhead != hostindex || flag)
+           && (cb->status == CB_BULK || cb->status == CB_NORMAL
+               || cb->status == CB_VOLUME)) {
+           cb->flags |= CBFLAG_BREAKING;
+       }
+    }
+
+    cb = itocb(fe->firstcb);
+    opr_Assert(cb);
+
+    /* loop through all CBs, only looking at ones with the CBFLAG_BREAKING
+     * flag set */
+    for (; cb;) {
+       for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
            nextcb = itocb(cb->cnext);
-           if ((cb->hhead != hostindex || flag)
-               && (cb->status == CB_BULK || cb->status == CB_NORMAL
-                   || cb->status == CB_VOLUME)) {
+           if ((cb->flags & CBFLAG_BREAKING)) {
                struct host *thishost = h_itoh(cb->hhead);
+               cb->flags &= ~CBFLAG_BREAKING;
                if (!thishost) {
                    ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
                } else if (thishost->hostFlags & VENUSDOWN) {
@@ -835,21 +873,6 @@ BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
                } else {
                    if (!(thishost->hostFlags & HOSTDELETED)) {
                        h_Hold_r(thishost);
-                       if (ncbas == cbaAlloc) {        /* Need more space */
-                           int curLen = cbaAlloc*sizeof(cba[0]);
-                           struct cbstruct *cbaOld = (cba == cbaDef) ? NULL : cba;
-
-                           /* There are logical contraints elsewhere that the number of hosts
-                              (i.e. h_HTSPERBLOCK*h_MAXHOSTTABLES) remains in the realm of a signed "int".
-                              cbaAlloc is defined unsigned int hence doubling below cannot overflow
-                           */
-                           cbaAlloc = cbaAlloc<<1;     /* double */
-                           cba = realloc(cbaOld, cbaAlloc * sizeof(cba[0]));
-
-                           if (cbaOld == NULL) {       /* realloc wouldn't have copied from cbaDef */
-                               memcpy(cba, cbaDef, curLen);
-                           }
-                       }
                        cba[ncbas].hp = thishost;
                        cba[ncbas].thead = cb->thead;
                        ncbas++;
@@ -863,16 +886,20 @@ BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
        }
 
        if (ncbas) {
-           struct cbstruct *cba2;
-           int num;
+           MultiBreakCallBack_r(cba, ncbas, &tf);
 
-           for (cba2 = cba, num = ncbas; ncbas > 0; cba2 += num, ncbas -= num) {
-               num = (ncbas > MAX_CB_HOSTS) ? MAX_CB_HOSTS : ncbas;
-               MultiBreakCallBack_r(cba2, num, &tf);
+           /* we need to to all these initializations again because MultiBreakCallBack may block */
+           fe = FindFE(fid);
+           if (!fe) {
+               goto done;
+           }
+           cb = itocb(fe->firstcb);
+           if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
+               /* the most common case is what follows the || */
+               goto done;
            }
        }
-
-       if (cba != cbaDef) free(cba);
+    }
 
   done:
     H_UNLOCK;
@@ -1138,7 +1165,7 @@ MultiBreakVolumeCallBack_r(struct host *host,
        h_Unlock_r(host);
        return 0;
     }
-    osi_Assert(parms->ncbas <= MAX_CB_HOSTS);
+    opr_Assert(parms->ncbas <= MAX_CB_HOSTS);
 
     /* Do not call MultiBreakCallBack on the current host structure
      ** because it would prematurely release the hold on the host
@@ -1190,7 +1217,7 @@ MultiBreakVolumeLaterCallBack(struct host *host, void *rock)
 extern pthread_cond_t fsync_cond;
 
 int
-BreakVolumeCallBacksLater(afs_uint32 volume)
+BreakVolumeCallBacksLater(VolumeId volume)
 {
     int hash;
     afs_uint32 *feip;
@@ -1199,7 +1226,8 @@ BreakVolumeCallBacksLater(afs_uint32 volume)
     struct host *host;
     int found = 0;
 
-    ViceLog(25, ("Setting later on volume %u\n", volume));
+    ViceLog(25, ("Setting later on volume %" AFS_VOLID_FMT "\n",
+                afs_printable_VolumeId_lu(volume)));
     H_LOCK;
     for (hash = 0; hash < FEHASH_SIZE; hash++) {
        for (feip = &HashTable[hash]; (fe = itofe(*feip)) != NULL; ) {
@@ -1227,7 +1255,7 @@ BreakVolumeCallBacksLater(afs_uint32 volume)
 
     ViceLog(25, ("Fsync thread wakeup\n"));
     FSYNC_LOCK;
-    CV_BROADCAST(&fsync_cond);
+    opr_cv_broadcast(&fsync_cond);
     FSYNC_UNLOCK;
     return 0;
 }
@@ -1260,8 +1288,8 @@ BreakLaterCallBacks(void)
                /* Ugly, but used to avoid left side casting */
                struct object *tmpfe;
                ViceLog(125,
-                       ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
-                        fe->volid));
+                       ("Unchaining for %u:%u:%" AFS_VOLID_FMT "\n", fe->vnode,
+                        fe->unique, afs_printable_VolumeId_lu(fe->volid)));
                fid.Volume = fe->volid;
                *feip = fe->fnext;
                fe->status &= ~FE_LATER; /* not strictly needed */
@@ -1301,9 +1329,10 @@ BreakLaterCallBacks(void)
                /* leave flag for MultiBreakVolumeCallBack to clear */
            } else {
                ViceLog(125,
-                       ("Found host %p (%s:%d) non-DELAYED cb for %u:%u:%u\n",
+                       ("Found host %p (%s:%d) non-DELAYED cb for %u:%u:%" AFS_VOLID_FMT "\n",
                         host, afs_inet_ntoa_r(host->host, hoststr),
-                        ntohs(host->port), fe->vnode, fe->unique, fe->volid));
+                        ntohs(host->port), fe->vnode, fe->unique,
+                        afs_printable_VolumeId_lu(fe->volid)));
            }
        }
        myfe = fe;
@@ -1350,7 +1379,7 @@ CleanupTimedOutCallBacks(void)
 int
 CleanupTimedOutCallBacks_r(void)
 {
-    afs_uint32 now = CBtime(FT_ApproxTime());
+    afs_uint32 now = CBtime(time(NULL));
     afs_uint32 *thead;
     struct CallBack *cb;
     int ntimedout = 0;
@@ -1364,10 +1393,11 @@ CleanupTimedOutCallBacks_r(void)
                cb = itocb(cbi);
                cbi = cb->tnext;
                ViceLog(8,
-                       ("CCB: deleting timed out call back %x (%s:%d), (%u,%u,%u)\n",
+                       ("CCB: deleting timed out call back %x (%s:%d), (%" AFS_VOLID_FMT ",%u,%u)\n",
                          h_itoh(cb->hhead)->host,
                          afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
-                        h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
+                        h_itoh(cb->hhead)->port,
+                        afs_printable_VolumeId_lu(itofe(cb->fhead)->volid),
                         itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
                HDel(cb);
                CDel(cb, 1);
@@ -2638,11 +2668,13 @@ cb_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new)
 }
 #endif /* AFS_DEMAND_ATTACH_FS */
 
+#define DumpBytes(fd,buf,req) if (write(fd, buf, req) < 0) {} /* don't care */
+
 static int
 DumpCallBackState_r(void)
 {
     int fd, oflag;
-    afs_uint32 magic = MAGICV2, now = (afs_int32) FT_ApproxTime(), freelisthead;
+    afs_uint32 magic = MAGICV2, now = (afs_int32) time(NULL), freelisthead;
 
     oflag = O_WRONLY | O_CREAT | O_TRUNC;
 #ifdef AFS_NT40_ENV
@@ -2655,19 +2687,23 @@ DumpCallBackState_r(void)
                 AFSDIR_SERVER_CBKDUMP_FILEPATH));
        return 0;
     }
-    (void)write(fd, &magic, sizeof(magic));
-    (void)write(fd, &now, sizeof(now));
-    (void)write(fd, &cbstuff, sizeof(cbstuff));
-    (void)write(fd, TimeOuts, sizeof(TimeOuts));
-    (void)write(fd, timeout, sizeof(timeout));
-    (void)write(fd, &tfirst, sizeof(tfirst));
+    /*
+     * Collect but ignoring the return value of write(2) here,
+     * to avoid compiler warnings on some platforms.
+     */
+    DumpBytes(fd, &magic, sizeof(magic));
+    DumpBytes(fd, &now, sizeof(now));
+    DumpBytes(fd, &cbstuff, sizeof(cbstuff));
+    DumpBytes(fd, TimeOuts, sizeof(TimeOuts));
+    DumpBytes(fd, timeout, sizeof(timeout));
+    DumpBytes(fd, &tfirst, sizeof(tfirst));
     freelisthead = cbtoi((struct CallBack *)CBfree);
-    (void)write(fd, &freelisthead, sizeof(freelisthead));      /* This is a pointer */
+    DumpBytes(fd, &freelisthead, sizeof(freelisthead));        /* This is a pointer */
     freelisthead = fetoi((struct FileEntry *)FEfree);
-    (void)write(fd, &freelisthead, sizeof(freelisthead));      /* This is a pointer */
-    (void)write(fd, HashTable, sizeof(HashTable));
-    (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks);    /* CB stuff */
-    (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks);    /* FE stuff */
+    DumpBytes(fd, &freelisthead, sizeof(freelisthead));        /* This is a pointer */
+    DumpBytes(fd, HashTable, sizeof(HashTable));
+    DumpBytes(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks);      /* CB stuff */
+    DumpBytes(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks);      /* FE stuff */
     close(fd);
 
     return 0;
@@ -2688,6 +2724,22 @@ DumpCallBackState(void) {
 
 #ifdef INTERPRET_DUMP
 
+static void
+ReadBytes(int fd, void *buf, size_t req)
+{
+    ssize_t count;
+
+    count = read(fd, buf, req);
+    if (count < 0) {
+       perror("read");
+       exit(-1);
+    } else if (count != req) {
+       fprintf(stderr, "read: premature EOF (expected %lu, got %lu)\n",
+               (unsigned long)req, (unsigned long)count);
+       exit(-1);
+    }
+}
+
 /* This is only compiled in for the callback analyzer program */
 /* Returns the time of the dump */
 time_t
@@ -2707,7 +2759,7 @@ ReadDump(char *file, int timebits)
        fprintf(stderr, "Couldn't read dump file %s\n", file);
        exit(1);
     }
-    read(fd, &magic, sizeof(magic));
+    ReadBytes(fd, &magic, sizeof(magic));
     if (magic == MAGICV2) {
        timebits = 32;
     } else {
@@ -2721,26 +2773,26 @@ ReadDump(char *file, int timebits)
        }
     }
     if (timebits == 64) {
-       read(fd, &now64, sizeof(afs_int64));
+       ReadBytes(fd, &now64, sizeof(afs_int64));
        now = (afs_int32) now64;
     } else
-       read(fd, &now, sizeof(afs_int32));
+       ReadBytes(fd, &now, sizeof(afs_int32));
 
-    read(fd, &cbstuff, sizeof(cbstuff));
-    read(fd, TimeOuts, sizeof(TimeOuts));
-    read(fd, timeout, sizeof(timeout));
-    read(fd, &tfirst, sizeof(tfirst));
-    read(fd, &freelisthead, sizeof(freelisthead));
+    ReadBytes(fd, &cbstuff, sizeof(cbstuff));
+    ReadBytes(fd, TimeOuts, sizeof(TimeOuts));
+    ReadBytes(fd, timeout, sizeof(timeout));
+    ReadBytes(fd, &tfirst, sizeof(tfirst));
+    ReadBytes(fd, &freelisthead, sizeof(freelisthead));
     CB = ((struct CallBack
           *)(calloc(cbstuff.nblks, sizeof(struct CallBack)))) - 1;
     FE = ((struct FileEntry
           *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
     CBfree = (struct CallBack *)itocb(freelisthead);
-    read(fd, &freelisthead, sizeof(freelisthead));
+    ReadBytes(fd, &freelisthead, sizeof(freelisthead));
     FEfree = (struct FileEntry *)itofe(freelisthead);
-    read(fd, HashTable, sizeof(HashTable));
-    read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks);   /* CB stuff */
-    read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks);   /* FE stuff */
+    ReadBytes(fd, HashTable, sizeof(HashTable));
+    ReadBytes(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks);      /* CB stuff */
+    ReadBytes(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks);      /* FE stuff */
     if (close(fd)) {
        perror("Error reading dumpfile");
        exit(1);
@@ -2916,9 +2968,9 @@ PrintCB(struct CallBack *cb, afs_uint32 now)
     if (fe == NULL)
        return;
 
-    printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %lu secs at %s",
-          fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
-          expires - now, ctime(&expires));
+    printf("vol=%" AFS_VOLID_FMT " vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %lu secs at %s",
+          afs_printable_VolumeId_lu(fe->volid), fe->vnode, fe->ncbs,
+          cb->hhead, cb->status, fe->status, expires - now, ctime(&expires));
 }
 
 #endif
@@ -2986,7 +3038,7 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
        j++;
     }
 
-    osi_Assert(j);                     /* at least one alternate address */
+    opr_Assert(j);                     /* at least one alternate address */
     ViceLog(125,
            ("Starting multibreakcall back on all addr for host %p (%s:%d)\n",
              host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
@@ -2999,10 +3051,12 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
            if (host->callback_rxcon)
                rx_DestroyConnection(host->callback_rxcon);
            host->callback_rxcon = conns[multi_i];
-            h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
+           /* add then remove */
+           addInterfaceAddr_r(host, interfaces[multi_i].addr,
+                                    interfaces[multi_i].port);
+           removeInterfaceAddr_r(host, host->host, host->port);
            host->host = interfaces[multi_i].addr;
            host->port = interfaces[multi_i].port;
-            h_AddHostToAddrHashTable_r(host->host, host->port, host);
            connSuccess = conns[multi_i];
            rx_SetConnDeadTime(host->callback_rxcon, 50);
            rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
@@ -3081,7 +3135,7 @@ MultiProbeAlternateAddress_r(struct host *host)
        j++;
     }
 
-    osi_Assert(j);                     /* at least one alternate address */
+    opr_Assert(j);                     /* at least one alternate address */
     ViceLog(125,
            ("Starting multiprobe on all addr for host %p (%s:%d)\n",
              host, afs_inet_ntoa_r(host->host, hoststr),
@@ -3095,10 +3149,12 @@ MultiProbeAlternateAddress_r(struct host *host)
            if (host->callback_rxcon)
                rx_DestroyConnection(host->callback_rxcon);
            host->callback_rxcon = conns[multi_i];
-            h_DeleteHostFromAddrHashTable_r(host->host, host->port, host);
+           /* add then remove */
+           addInterfaceAddr_r(host, interfaces[multi_i].addr,
+                                    interfaces[multi_i].port);
+           removeInterfaceAddr_r(host, host->host, host->port);
            host->host = interfaces[multi_i].addr;
            host->port = interfaces[multi_i].port;
-            h_AddHostToAddrHashTable_r(host->host, host->port, host);
            connSuccess = conns[multi_i];
            rx_SetConnDeadTime(host->callback_rxcon, 50);
            rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);