cbd-new-magic-version-with-fixed-time-size-and-dump-switch-20090319
[openafs.git] / src / viced / callback.c
index a43edbd..24f17e5 100644 (file)
@@ -90,6 +90,7 @@ RCSID
 #include <stdio.h>
 #include <stdlib.h>            /* for malloc() */
 #include <time.h>              /* ANSI standard location for time stuff */
+#include <string.h>
 #ifdef AFS_NT40_ENV
 #include <fcntl.h>
 #include <io.h>
@@ -97,13 +98,6 @@ RCSID
 #include <sys/time.h>
 #include <sys/file.h>
 #endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
 #include <afs/assert.h>
 
 #include <afs/stds.h>
@@ -130,7 +124,10 @@ RCSID
 
 extern afsUUID FS_HostUUID;
 extern int hostCount;
+
+#ifndef INTERPRET_DUMP
 static int ShowProblems = 1;
+#endif
 
 struct cbcounters cbstuff;
 
@@ -159,7 +156,9 @@ static int TimeOuts[] = {
 };                             /* Anything more: MinTimeOut */
 
 /* minimum time given for a call back */
+#ifndef INTERPRET_DUMP
 static int MinTimeOut = (7 * 60);
+#endif
 
 /* Heads of CB queues; a timeout index is 1+index into this array */
 static afs_uint32 timeout[CB_NUM_TIMEOUT_QUEUES];
@@ -174,6 +173,8 @@ struct object {
 
 /* Prototypes for static routines */
 static struct FileEntry *FindFE(register AFSFid * fid);
+
+#ifndef INTERPRET_DUMP
 static struct CallBack *iGetCB(register int *nused);
 static int iFreeCB(register struct CallBack *cb, register int *nused);
 static struct FileEntry *iGetFE(register int *nused);
@@ -194,11 +195,12 @@ static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
 static int MultiBreakVolumeCallBack_r(struct host *host, int isheld,
                                      struct VCBParams *parms, int deletefe);
 static int MultiBreakVolumeCallBack(struct host *host, int isheld,
-                                   struct VCBParams *parms);
+                                   void *rock);
 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
-                                        struct VCBParams *parms);
+                                        void *rock);
 static int GetSomeSpace_r(struct host *hostp, int locked);
 static int ClearHostCallbacks_r(struct host *hp, int locked);
+#endif
 
 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
@@ -387,7 +389,7 @@ CDelPtr(register struct FileEntry *fe, register afs_uint32 * cbp,
        CcdelB++;
     *cbp = cb->cnext;
     FreeCB(cb);
-    if (deletefe && (--fe->ncbs == 0))
+    if ((--fe->ncbs == 0) && deletefe)
        FDel(fe);
     return 0;
 }
@@ -538,11 +540,13 @@ AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
     struct FileEntry *fe;
     struct CallBack *cb = 0, *lastcb = 0;
     struct FileEntry *newfe = 0;
-    afs_uint32 time_out;
+    afs_uint32 time_out = 0;
     afs_uint32 *Thead = thead;
     struct CallBack *newcb = 0;
     int safety;
 
+    cbstuff.AddCallBacks++;
+
     host->Console |= 2;
 
     /* allocate these guys first, since we can't call the allocator with
@@ -650,6 +654,14 @@ AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
     return 0;
 }
 
+static int
+CompareCBA(const void *e1, const void *e2)
+{
+    const struct cbstruct *cba1 = (const struct cbstruct *)e1;
+    const struct cbstruct *cba2 = (const struct cbstruct *)e2;
+    return ((cba1->hp)->index - (cba2->hp)->index);
+}
+
 /* Take an array full of hosts, all held.  Break callbacks to them, and 
  * release the holds once you're done, except don't release xhost.  xhost 
  * may be NULL.  Currently only works for a single Fid in afidp array.
@@ -679,6 +691,9 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
 
     assert(ncbas <= MAX_CB_HOSTS);
 
+    /* sort cba list to avoid makecall issues */
+    qsort(cba, ncbas, sizeof(struct cbstruct), CompareCBA);
+
     /* set up conns for multi-call */
     for (i = 0, j = 0; i < ncbas; i++) {
        struct host *thishost = cba[i].hp;
@@ -720,10 +735,11 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
                    if (MultiBreakCallBackAlternateAddress(hp, afidp)) {
                        if (ShowProblems) {
                            ViceLog(7,
-                                   ("BCB: Failed on file %u.%u.%u, Host %s:%d is down\n",
+                                   ("BCB: Failed on file %u.%u.%u, Host %x (%s:%d) is down\n",
                                     afidp->AFSCBFids_val->Volume,
                                     afidp->AFSCBFids_val->Vnode,
                                     afidp->AFSCBFids_val->Unique,
+                                     hp,
                                     afs_inet_ntoa_r(hp->host, hoststr),
                                     ntohs(hp->port)));
                        }
@@ -790,8 +806,8 @@ BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
     char hoststr[16];
 
     ViceLog(7,
-           ("BCB: BreakCallBack(all but %s:%d, (%u,%u,%u))\n",
-            afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
+           ("BCB: BreakCallBack(Host %x 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));
 
     H_LOCK;
@@ -820,8 +836,8 @@ BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
                    ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
                } else if (thishost->hostFlags & VENUSDOWN) {
                    ViceLog(7,
-                           ("BCB: %s:%d is down; delaying break call back\n",
-                            afs_inet_ntoa_r(thishost->host, hoststr),
+                           ("BCB: %x (%s:%d) is down; delaying break call back\n",
+                            thishost, afs_inet_ntoa_r(thishost->host, hoststr),
                             ntohs(thishost->port)));
                    cb->status = CB_DELAYED;
                } else {
@@ -866,9 +882,9 @@ DeleteCallBack(struct host *host, AFSFid * fid)
     register afs_uint32 *pcb;
     char hoststr[16];
 
+    H_LOCK;
     cbstuff.DeleteCallBacks++;
 
-    H_LOCK;
     h_Lock_r(host);
     fe = FindFE(fid);
     if (!fe) {
@@ -882,8 +898,8 @@ DeleteCallBack(struct host *host, AFSFid * fid)
     pcb = FindCBPtr(fe, host);
     if (!*pcb) {
        ViceLog(8,
-               ("DCB: No call back for host %s:%d, (%u, %u, %u)\n",
-                afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
+               ("DCB: No call back for host %x (%s:%d), (%u, %u, %u)\n",
+                host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
                 fid->Volume, fid->Vnode, fid->Unique));
        h_Unlock_r(host);
        H_UNLOCK;
@@ -927,6 +943,7 @@ DeleteFileCallBacks(AFSFid * fid)
        TDel(cb);
        HDel(cb);
        FreeCB(cb);
+       fe->ncbs--;
     }
     FDel(fe);
     H_UNLOCK;
@@ -1003,15 +1020,15 @@ BreakDelayedCallBacks_r(struct host *host)
        if (code) {
            if (ShowProblems) {
                ViceLog(0,
-                       ("CB: Call back connect back failed (in break delayed) for Host %s:%d\n",
-                        afs_inet_ntoa_r(host->host, hoststr),
+                       ("CB: Call back connect back failed (in break delayed) for Host %x (%s:%d)\n",
+                        host, afs_inet_ntoa_r(host->host, hoststr),
                         ntohs(host->port)));
            }
            host->hostFlags |= VENUSDOWN;
        } else {
            ViceLog(25,
-                   ("InitCallBackState success on %s\n",
-                    afs_inet_ntoa_r(host->host, hoststr)));
+                   ("InitCallBackState success on %x (%s:%d)\n",
+                    host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
            /* reset was done successfully */
            host->hostFlags |= RESETDONE;
            host->hostFlags &= ~VENUSDOWN;
@@ -1050,15 +1067,15 @@ BreakDelayedCallBacks_r(struct host *host)
                int i;
                if (ShowProblems) {
                    ViceLog(0,
-                           ("CB: XCallBackBulk failed, Host %s:%d; callback list follows:\n",
-                            afs_inet_ntoa_r(host->host, hoststr),
+                           ("CB: XCallBackBulk failed, Host %x (%s:%d); callback list follows:\n",
+                             host, afs_inet_ntoa_r(host->host, hoststr),
                             ntohs(host->port)));
                }
                for (i = 0; i < nfids; i++) {
                    if (ShowProblems) {
                        ViceLog(0,
-                               ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
-                                afs_inet_ntoa_r(host->host, hoststr),
+                               ("CB: Host %x (%s:%d), file %u.%u.%u (part of bulk callback)\n",
+                                host, afs_inet_ntoa_r(host->host, hoststr),
                                 ntohs(host->port), fids[i].Volume,
                                 fids[i].Vnode, fids[i].Unique));
                    }
@@ -1078,7 +1095,7 @@ BreakDelayedCallBacks_r(struct host *host)
 
     cbstuff.nbreakers--;
     /* If we succeeded it's always ok to unset HFE_LATER */
-    if (!host->hostFlags & VENUSDOWN)
+    if (!(host->hostFlags & VENUSDOWN))
        host->hostFlags &= ~HFE_LATER;
     return (host->hostFlags & VENUSDOWN);
 }
@@ -1105,12 +1122,12 @@ MultiBreakVolumeCallBack_r(struct host *host, int isheld,
            return 0;           /* Release hold */
        }
        ViceLog(8,
-               ("BVCB: volume call back for Host %s:%d failed\n",
-                afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
+               ("BVCB: volume call back for Host %x (%s:%d) failed\n",
+                 host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
        if (ShowProblems) {
            ViceLog(0,
-                   ("CB: volume callback for Host %s:%d failed\n",
-                    afs_inet_ntoa_r(host->host, hoststr),
+                   ("CB: volume callback for Host %x (%s:%d) failed\n",
+                    host, afs_inet_ntoa_r(host->host, hoststr),
                     ntohs(host->port)));
        }
        DeleteAllCallBacks_r(host, deletefe);   /* Delete all callback state 
@@ -1148,9 +1165,10 @@ MultiBreakVolumeCallBack_r(struct host *host, int isheld,
 ** isheld is 1 if the host is held in BreakVolumeCallBacks
 */
 static int
-MultiBreakVolumeCallBack(struct host *host, int isheld,
-                        struct VCBParams *parms)
+MultiBreakVolumeCallBack(struct host *host, int isheld, void *rock)
 {
+    struct VCBParams *parms = (struct VCBParams *) rock;
+    
     int retval;
     H_LOCK;
     retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
@@ -1163,9 +1181,9 @@ MultiBreakVolumeCallBack(struct host *host, int isheld,
 ** isheld is 1 if the host is held in BreakVolumeCallBacks
 */
 static int
-MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
-                             struct VCBParams *parms)
+MultiBreakVolumeLaterCallBack(struct host *host, int isheld, void *rock)
 {
+    struct VCBParams *parms = (struct VCBParams *)rock;
     int retval;
     H_LOCK;
     retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
@@ -1234,7 +1252,7 @@ BreakVolumeCallBacks(afs_uint32 volume)
     henumParms.fid = &fid;
     henumParms.thead = tthead;
     H_UNLOCK;
-    h_Enumerate(MultiBreakVolumeCallBack, (char *)&henumParms);
+    h_Enumerate(MultiBreakVolumeCallBack, &henumParms);
     H_LOCK;
     if (henumParms.ncbas) {    /* do left-overs */
        struct AFSCBFids tf;
@@ -1367,8 +1385,8 @@ BreakLaterCallBacks(void)
                /* leave hold for MultiBreakVolumeCallBack to clear */
            } else {
                ViceLog(125,
-                       ("Found host %s:%d non-DELAYED cb for %u:%u:%u\n", 
-                        afs_inet_ntoa_r(host->host, hoststr),
+                       ("Found host %x (%s:%d) non-DELAYED cb for %u:%u:%u\n", 
+                        host, afs_inet_ntoa_r(host->host, hoststr),
                         ntohs(host->port), fe->vnode, fe->unique, fe->volid));
            }
        }
@@ -1430,8 +1448,9 @@ CleanupTimedOutCallBacks_r(void)
                cb = itocb(cbi);
                cbi = cb->tnext;
                ViceLog(8,
-                       ("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
-                        afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
+                       ("CCB: deleting timed out call back %x (%s:%d), (%u,%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,
                         itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
                HDel(cb);
@@ -1461,9 +1480,9 @@ static int lih_host_held;
  * are held by other threads.
  */
 static int
-lih0_r(register struct host *host, register int held,
-      register struct host *hostp)
+lih0_r(register struct host *host, register int held, void *rock)
 {
+    struct host *hostp = (struct host *) rock;
     if (host->cblist
        && (hostp && host != hostp) 
        && (!held && !h_OtherHolds_r(host))
@@ -1485,9 +1504,10 @@ lih0_r(register struct host *host, register int held,
  * prevent held hosts from being selected.
  */
 static int
-lih1_r(register struct host *host, register int held,
-      register struct host *hostp)
+lih1_r(register struct host *host, register int held, void *rock)
 {
+    struct host *hostp = (struct host *) rock;
+
     if (host->cblist
        && (hostp && host != hostp) 
        && (!lih_host || host->ActiveCall < lih_host->ActiveCall) 
@@ -1588,8 +1608,8 @@ ClearHostCallbacks_r(struct host *hp, int locked)
     struct rx_connection *cb_conn = NULL;
 
     ViceLog(5,
-           ("GSS: Delete longest inactive host %s\n",
-            afs_inet_ntoa_r(hp->host, hoststr)));
+           ("GSS: Delete longest inactive host %x (%s:%d)\n",
+             hp, afs_inet_ntoa_r(hp->host, hoststr), ntohs(hp->port)));
     if (!(held = h_Held_r(hp)))
        h_Hold_r(hp);
 
@@ -1671,6 +1691,8 @@ PrintCallBackStats(void)
 }
 
 #define MAGIC 0x12345678       /* To check byte ordering of dump when it is read in */
+#define MAGICV2 0x12345679      /* To check byte ordering & version of dump when it is read in */
+
 
 #ifndef INTERPRET_DUMP
 
@@ -2313,7 +2335,7 @@ cb_stateRestoreFEs(struct fs_dump_state * state)
 static int
 cb_stateSaveFE(struct fs_dump_state * state, struct FileEntry * fe)
 {
-    int ret = 0, iovcnt, cbi, idx, len, written = 0;
+    int ret = 0, iovcnt, cbi, written = 0;
     afs_uint32 fei;
     struct callback_state_entry_header hdr;
     struct FEDiskEntry fedsk;
@@ -2334,24 +2356,24 @@ cb_stateSaveFE(struct fs_dump_state * state, struct FileEntry * fe)
     }
 
     iov[0].iov_base = (char *)&hdr;
-    len = iov[0].iov_len = sizeof(hdr);
+    iov[0].iov_len = sizeof(hdr);
     iov[1].iov_base = (char *)&fedsk;
-    len += iov[1].iov_len = sizeof(struct FEDiskEntry);
+    iov[1].iov_len = sizeof(struct FEDiskEntry);
     iovcnt = 2;
 
-    for (cbi = fe->firstcb, cb = itocb(cbi), idx = 2; 
+    for (cbi = fe->firstcb, cb = itocb(cbi); 
         cb != NULL; 
-        cbi = cb->cnext, cb = itocb(cbi), idx++, hdr.nCBs++) {
+        cbi = cb->cnext, cb = itocb(cbi), hdr.nCBs++) {
        if (cbi > state->cb_hdr->cb_max) {
            state->cb_hdr->cb_max = cbi;
        }
-       if (cb_stateCBToDiskEntry(cb, &cbdsk[idx])) {
+       if (cb_stateCBToDiskEntry(cb, &cbdsk[iovcnt])) {
            ret = 1;
            goto done;
        }
-       cbdsk[idx].index = cbi;
-       iov[idx].iov_base = (char *)&cbdsk[idx];
-       len += iov[idx].iov_len = sizeof(struct CBDiskEntry);
+       cbdsk[iovcnt].index = cbi;
+       iov[iovcnt].iov_base = (char *)&cbdsk[iovcnt];
+       iov[iovcnt].iov_len = sizeof(struct CBDiskEntry);
        iovcnt++;
        if ((iovcnt == 16) || (!cb->cnext)) {
            if (fs_stateWriteV(state, iov, iovcnt)) {
@@ -2360,7 +2382,6 @@ cb_stateSaveFE(struct fs_dump_state * state, struct FileEntry * fe)
            }
            written = 1;
            iovcnt = 0;
-           len = 0;
        }
     }
 
@@ -2399,7 +2420,7 @@ cb_stateSaveFE(struct fs_dump_state * state, struct FileEntry * fe)
 static int
 cb_stateRestoreFE(struct fs_dump_state * state)
 {
-    int ret = 0, iovcnt, len, nCBs, idx;
+    int ret = 0, iovcnt, nCBs;
     struct callback_state_entry_header hdr;
     struct FEDiskEntry fedsk;
     struct CBDiskEntry cbdsk[16];
@@ -2408,9 +2429,9 @@ cb_stateRestoreFE(struct fs_dump_state * state)
     struct CallBack * cb;
 
     iov[0].iov_base = (char *)&hdr;
-    len = iov[0].iov_len = sizeof(hdr);
+    iov[0].iov_len = sizeof(hdr);
     iov[1].iov_base = (char *)&fedsk;
-    len += iov[1].iov_len = sizeof(fedsk);
+    iov[1].iov_len = sizeof(fedsk);
     iovcnt = 2;
 
     if (fs_stateReadV(state, iov, iovcnt)) {
@@ -2436,11 +2457,11 @@ cb_stateRestoreFE(struct fs_dump_state * state)
     }
 
     if (hdr.nCBs) {
-       for (iovcnt = 0, idx = 0, len = 0, nCBs = 0;
+       for (iovcnt = 0, nCBs = 0;
             nCBs < hdr.nCBs;
-            idx++, nCBs++) {
-           iov[idx].iov_base = (char *)&cbdsk[idx];
-           len += iov[idx].iov_len = sizeof(struct CBDiskEntry);
+            nCBs++) {
+           iov[iovcnt].iov_base = (char *)&cbdsk[iovcnt];
+           iov[iovcnt].iov_len = sizeof(struct CBDiskEntry);
            iovcnt++;
            if ((iovcnt == 16) || (nCBs == hdr.nCBs - 1)) {
                if (fs_stateReadV(state, iov, iovcnt)) {
@@ -2451,7 +2472,6 @@ cb_stateRestoreFE(struct fs_dump_state * state)
                    ret = 1;
                    goto done;
                }
-               len = 0;
                iovcnt = 0;
            }
        }
@@ -2644,11 +2664,14 @@ cb_OldToNew(struct fs_dump_state * state, afs_uint32 old, afs_uint32 * new)
 int
 DumpCallBackState(void)
 {
-    int fd;
-    afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
+    int fd, oflag;
+    afs_uint32 magic = MAGICV2, now = (afs_int32) FT_ApproxTime(), freelisthead;
 
-    fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY | O_CREAT | O_TRUNC,
-             0666);
+    oflag = O_WRONLY | O_CREAT | O_TRUNC;
+#ifdef AFS_NT40_ENV
+    oflag |= O_BINARY;
+#endif
+    fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, oflag, 0666);
     if (fd < 0) {
        ViceLog(0,
                ("Couldn't create callback dump file %s\n",
@@ -2680,34 +2703,51 @@ DumpCallBackState(void)
 /* This is only compiled in for the callback analyzer program */
 /* Returns the time of the dump */
 time_t
-ReadDump(char *file)
+ReadDump(char *file, int timebits)
 {
-    int fd;
+    int fd, oflag;
     afs_uint32 magic, freelisthead;
-    time_t now;
+    afs_uint32 now;
+#ifdef AFS_64BIT_ENV
+    afs_int64 now64;
+#endif
 
-    fd = open(file, O_RDONLY);
+    oflag = O_RDONLY;
+#ifdef AFS_NT40_ENV
+    oflag |= O_BINARY;
+#endif
+    fd = open(file, oflag);
     if (fd < 0) {
        fprintf(stderr, "Couldn't read dump file %s\n", file);
        exit(1);
     }
     read(fd, &magic, sizeof(magic));
-    if (magic != MAGIC) {
-       fprintf(stderr,
-               "Magic number of %s is invalid.  You might be trying to\n",
-               file);
-       fprintf(stderr,
-               "run this program on a machine type with a different byte ordering.\n");
-       exit(1);
+    if (magic == MAGICV2) {
+       timebits = 32;
+    } else {
+       if (magic != MAGIC) {
+           fprintf(stderr,
+                   "Magic number of %s is invalid.  You might be trying to\n",
+                   file);
+           fprintf(stderr,
+                   "run this program on a machine type with a different byte ordering.\n");
+           exit(1);
+       }
     }
-    read(fd, &now, sizeof(now));
+#ifdef AFS_64BIT_ENV
+    if (timebits == 64) {
+       read(fd, &now64, sizeof(afs_int64));
+       now = (afs_int32) now64;
+    } else
+#endif
+       read(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));
     CB = ((struct CallBack
-          *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
+          *)(calloc(cbstuff.nblks, sizeof(struct CallBack)))) - 1;
     FE = ((struct FileEntry
           *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
     CBfree = (struct CallBack *)itocb(freelisthead);
@@ -2723,7 +2763,11 @@ ReadDump(char *file)
     return now;
 }
 
+#ifdef AFS_NT40_ENV
 #include "AFS_component_version_number.h"
+#else
+#include "AFS_component_version_number.c"
+#endif
 
 int
 main(int argc, char **argv)
@@ -2732,8 +2776,9 @@ main(int argc, char **argv)
     static AFSFid fid;
     register struct FileEntry *fe;
     register struct CallBack *cb;
-    time_t now;
-
+    afs_int32 now;
+    int timebits = 32;
+    
     memset(&fid, 0, sizeof(fid));
     argc--;
     argv++;
@@ -2765,6 +2810,19 @@ main(int argc, char **argv)
            all = 1;
        } else if (!strcmp(*argv, "-raw")) {
            raw = 1;
+       } else if (!strcmp(*argv, "-timebits")) {
+           if (argc < 1) {
+               err++;
+               break;
+           }
+           argc--;
+           timebits = atoi(*++argv);
+           if ((timebits != 32)
+#ifdef AFS_64BIT_ENV
+               && (timebits != 64)
+#endif
+               ) 
+               err++;
        } else if (!strcmp(*argv, "-volume")) {
            if (argc < 1) {
                err++;
@@ -2778,16 +2836,20 @@ main(int argc, char **argv)
     }
     if (err || argc != 1) {
        fprintf(stderr,
-               "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
+               "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] [-timebits 32"
+#ifdef AFS_64BIT_ENV
+               "|64"
+#endif
+               "] callbackdumpfile\n");
        fprintf(stderr,
                "[cbid is shown for each host in the hosts.dump file]\n");
        exit(1);
     }
-    now = ReadDump(*argv);
+    now = ReadDump(*argv, timebits);
     if (stats || noptions == 0) {
        time_t uxtfirst = UXtime(tfirst);
-       printf("The time of the dump was %u %s", now, ctime(&now));
-       printf("The last time cleanup ran was %u %s", uxtfirst,
+       printf("The time of the dump was %u %s", (unsigned int) now, ctime(&now));
+       printf("The last time cleanup ran was %u %s", (unsigned int) uxtfirst,
               ctime(&uxtfirst));
        PrintCallBackStats();
     }
@@ -2851,7 +2913,7 @@ PrintCB(register 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 %d secs at %s",
+    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));
 }
@@ -2889,10 +2951,8 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
     if (!host->interface)
        return 1;               /* failure */
 
-    assert(host->interface->numberOfInterfaces > 0);
-
     /* the only address is the primary interface */
-    if (host->interface->numberOfInterfaces == 1)
+    if (host->interface->numberOfInterfaces <= 1)
        return 1;               /* failure */
 
     /* initialise a security object only once */
@@ -2926,8 +2986,8 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
 
     assert(j);                 /* at least one alternate address */
     ViceLog(125,
-           ("Starting multibreakcall back on all addr for host %s\n",
-            afs_inet_ntoa_r(host->host, hoststr)));
+           ("Starting multibreakcall back on all addr for host %x (%s:%d)\n",
+             host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
     H_UNLOCK;
     multi_Rx(conns, j) {
        multi_RXAFSCB_CallBack(afidp, &tc);
@@ -2937,14 +2997,17 @@ 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);
            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);
            ViceLog(125,
-                   ("multibreakcall success with addr %s\n",
-                    afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
+                   ("multibreakcall success with addr %s:%d\n",
+                    afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr),
+                     ntohs(interfaces[multi_i].port)));
            H_UNLOCK;
            multi_Abort;
        }
@@ -2984,11 +3047,9 @@ MultiProbeAlternateAddress_r(struct host *host)
     if (!host->interface)
        return 1;               /* failure */
 
-    assert(host->interface->numberOfInterfaces > 0);
-
     /* the only address is the primary interface */
-    if (host->interface->numberOfInterfaces == 1)
-       return 1;               /* failure */
+    if (host->interface->numberOfInterfaces <= 1)
+        return 1;               /* failure */
 
     /* initialise a security object only once */
     if (!sc)
@@ -3011,8 +3072,8 @@ MultiProbeAlternateAddress_r(struct host *host)
 
        interfaces[j] = host->interface->interface[i];
        conns[j] =
-           rx_NewConnection(interfaces[i].addr, 
-                            interfaces[i].port, 1, sc, 0);
+           rx_NewConnection(interfaces[j].addr, 
+                            interfaces[j].port, 1, sc, 0);
        rx_SetConnDeadTime(conns[j], 2);
        rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
        j++;
@@ -3020,8 +3081,9 @@ MultiProbeAlternateAddress_r(struct host *host)
 
     assert(j);                 /* at least one alternate address */
     ViceLog(125,
-           ("Starting multiprobe on all addr for host %s\n",
-            afs_inet_ntoa_r(host->host, hoststr)));
+           ("Starting multiprobe on all addr for host %x (%s:%d)\n",
+             host, afs_inet_ntoa_r(host->host, hoststr),
+             ntohs(host->port)));
     H_UNLOCK;
     multi_Rx(conns, j) {
        multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
@@ -3031,20 +3093,24 @@ 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);
            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);
            ViceLog(125,
-                   ("multiprobe success with addr %s\n",
-                    afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
+                   ("multiprobe success with addr %s:%d\n",
+                    afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr),
+                     ntohs(interfaces[multi_i].port)));
            H_UNLOCK;
            multi_Abort;
        } else {
            ViceLog(125,
-                   ("multiprobe failure with addr %s\n",
-                    afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
+                   ("multiprobe failure with addr %s:%d\n",
+                    afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr),
+                     ntohs(interfaces[multi_i].port)));
             
             /* This is less than desirable but its the best we can do.
              * The AFS Cache Manager will return either 0 for a Uuid  
@@ -3056,14 +3122,7 @@ MultiProbeAlternateAddress_r(struct host *host)
             if (multi_error == 1) {
                 /* remove the current alternate address from this host */
                 H_LOCK;
-                for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
-                    if (interfaces[multi_i].addr != host->interface->interface[i].addr &&
-                       interfaces[multi_i].port != host->interface->interface[i].port) {
-                        host->interface->interface[j] = host->interface->interface[i];
-                        j++;
-                    }
-                }
-                host->interface->numberOfInterfaces--;
+                removeInterfaceAddr_r(host, interfaces[multi_i].addr, interfaces[multi_i].port);
                 H_UNLOCK;
             }
         }