Add printf format checks to util's log functions
[openafs.git] / src / viced / callback.c
index c7f616e..cbe90d7 100644 (file)
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
 
 #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>
 #else
 #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
+#include <unistd.h>
 #endif
 #include <afs/assert.h>
 
@@ -111,7 +104,7 @@ RCSID
 #include <afs/nfs.h>           /* yuck.  This is an abomination. */
 #include <lwp.h>
 #include <rx/rx.h>
-#include <afscbint.h>
+#include <afs/afscbint.h>
 #include <afs/afsutil.h>
 #include <lock.h>
 #include <afs/ihandle.h>
@@ -130,7 +123,10 @@ RCSID
 
 extern afsUUID FS_HostUUID;
 extern int hostCount;
+
+#ifndef INTERPRET_DUMP
 static int ShowProblems = 1;
+#endif
 
 struct cbcounters cbstuff;
 
@@ -159,7 +155,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 +172,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 +194,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 +388,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;
 }
@@ -517,12 +518,13 @@ int
 AddCallBack1(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
             int locked)
 {
-    int retVal;
+    int retVal = 0;
     H_LOCK;
     if (!locked) {
        h_Lock_r(host);
     }
-    retVal = AddCallBack1_r(host, fid, thead, type, 1);
+    if (!(host->hostFlags & HOSTDELETED))
+        retVal = AddCallBack1_r(host, fid, thead, type, 1);
 
     if (!locked) {
        h_Unlock_r(host);
@@ -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
@@ -561,6 +565,11 @@ AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
     if (!locked) {
        h_Lock_r(host);         /* this can yield, so do it before we get any */
        /* fragile info */
+        if (host->hostFlags & HOSTDELETED) {
+            host->Console &= ~2;
+            h_Unlock_r(host);
+            return 0;
+        }
     }
 
     fe = FindFE(fid);
@@ -650,6 +659,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 +696,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;
@@ -711,7 +731,7 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
 
                if (!hp || !idx) {
                    ViceLog(0,
-                           ("BCB: INTERNAL ERROR: hp=%x, cba=%x, thead=%u\n", 
+                           ("BCB: INTERNAL ERROR: hp=%p, cba=%p, thead=%u\n",
                             hp, cba, idx));
                } else {
                    /* 
@@ -720,22 +740,26 @@ 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 %p (%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)));
                        }
 
                        H_LOCK;
                        h_Lock_r(hp); 
-                       hp->hostFlags |= VENUSDOWN;
-               /**
-                 * We always go into AddCallBack1_r with the host locked
-                 */
-                       AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
-                                      CB_DELAYED, 1);
+                        if (!(hp->hostFlags & HOSTDELETED)) {
+                            hp->hostFlags |= VENUSDOWN;
+                            /**
+                             * We always go into AddCallBack1_r with the host locked
+                             */
+                            AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
+                                           CB_DELAYED, 1);
+                        }
                        h_Unlock_r(hp); 
                        H_UNLOCK;
                    }
@@ -790,8 +814,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 %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));
 
     H_LOCK;
@@ -820,8 +844,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: %p (%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,10 +890,11 @@ DeleteCallBack(struct host *host, AFSFid * fid)
     register afs_uint32 *pcb;
     char hoststr[16];
 
+    H_LOCK;
     cbstuff.DeleteCallBacks++;
 
-    H_LOCK;
     h_Lock_r(host);
+    /* do not care if the host has been HOSTDELETED */
     fe = FindFE(fid);
     if (!fe) {
        h_Unlock_r(host);
@@ -882,8 +907,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 %p (%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 +952,7 @@ DeleteFileCallBacks(AFSFid * fid)
        TDel(cb);
        HDel(cb);
        FreeCB(cb);
+       fe->ncbs--;
     }
     FDel(fe);
     H_UNLOCK;
@@ -1003,15 +1029,17 @@ 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 %p (%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 %p (%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 +1078,17 @@ 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 %p (%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 %p (%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 +1108,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);
 }
@@ -1100,17 +1130,11 @@ MultiBreakVolumeCallBack_r(struct host *host, int isheld,
 
     if (host->hostFlags & VENUSDOWN) {
        h_Lock_r(host);
-       if (host->hostFlags & HOSTDELETED) {
-           h_Unlock_r(host);
-           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)));
+        /* Do not care if the host is now HOSTDELETED */
        if (ShowProblems) {
            ViceLog(0,
-                   ("CB: volume callback for Host %s:%d failed\n",
-                    afs_inet_ntoa_r(host->host, hoststr),
+                   ("BVCB: volume callback for Host %p (%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 +1172,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 +1188,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 +1259,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;
@@ -1334,6 +1359,7 @@ BreakLaterCallBacks(void)
                         fe->volid));
                fid.Volume = fe->volid;
                *feip = fe->fnext;
+               fe->status &= ~FE_LATER; /* not strictly needed */
                /* Works since volid is deeper than the largest pointer */
                tmpfe = (struct object *)fe;
                tmpfe->next = (struct object *)myfe;
@@ -1367,8 +1393,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 %p (%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 +1456,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);
@@ -1455,28 +1482,32 @@ CleanupTimedOutCallBacks_r(void)
 static struct host *lih_host;
 static int lih_host_held;
 
+/* Value of host->refCount that allows us to reliably infer that
+ * host may be held by some other thread */
+#define OTHER_MUSTHOLD_LIH 2
+
 /* This version does not allow 'host' to be selected unless its ActiveCall 
  * is newer than 'hostp' which is the host with the oldest ActiveCall from
  * the last pass (if it is provided).  We filter out any hosts that are
  * 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 flags, void *rock)
 {
+    struct host *hostp = (struct host *) rock;
     if (host->cblist
        && (hostp && host != hostp) 
-       && (!held && !h_OtherHolds_r(host))
+       && (host->refCount < OTHER_MUSTHOLD_LIH)
        && (!lih_host || host->ActiveCall < lih_host->ActiveCall) 
        && (!hostp || host->ActiveCall > hostp->ActiveCall)) {
-       if (lih_host != NULL && lih_host_held) {
-           h_Release_r(lih_host);
-       }
-       lih_host = host;
-       lih_host_held = !held;
-       held = 1;
+        if (lih_host != NULL && lih_host_held) {
+            h_Release_r(lih_host); /* release prev host */
+        }
+        lih_host = host;
+        lih_host_held = !flags; /* on i==1, this === (lih_host_held = 1) */
+        flags = 1; /* now flags is 1, but at next(i), it will be 0 again */
     }
-    return held;
+    return flags;
 }
 
 /* This version does not allow 'host' to be selected unless its ActiveCall 
@@ -1485,21 +1516,22 @@ 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 flags, void *rock)
 {
+    struct host *hostp = (struct host *) rock;
+
     if (host->cblist
        && (hostp && host != hostp) 
        && (!lih_host || host->ActiveCall < lih_host->ActiveCall) 
        && (!hostp || host->ActiveCall > hostp->ActiveCall)) {
-       if (lih_host != NULL && lih_host_held) {
-           h_Release_r(lih_host);
-       }
-       lih_host = host;
-       lih_host_held = !held;
-       held = 1;
+           if (lih_host != NULL && lih_host_held) {
+                   h_Release_r(lih_host); /* really? */
+           }
+           lih_host = host;
+           lih_host_held = !flags; /* see note above */
+           flags = 1; /* see note above */
     }
-    return held;
+    return flags;
 }
 
 /* This could be upgraded to get more space each time */
@@ -1540,12 +1572,14 @@ GetSomeSpace_r(struct host *hostp, int locked)
            int lih_host_held2=lih_host_held;   
            cbstuff.GSS4++;
            if ((hp != hostp) && !ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
-               if (lih_host_held2)
-                   h_Release_r(hp);
+                if (lih_host_held2)
+                    h_Release_r(hp);
                return 0;
            }
-           if (lih_host_held2)
-               h_Release_r(hp);
+            if (lih_host_held2) {
+                h_Release_r(hp);
+                hp = NULL;
+            }
            hp1 = hp;
            hp2 = hostList;
        } else {
@@ -1583,25 +1617,23 @@ static int
 ClearHostCallbacks_r(struct host *hp, int locked)
 {
     int code;
-    int held = 0;
     char hoststr[16];
     struct rx_connection *cb_conn = NULL;
 
     ViceLog(5,
-           ("GSS: Delete longest inactive host %s\n",
-            afs_inet_ntoa_r(hp->host, hoststr)));
-    if (!(held = h_Held_r(hp)))
-       h_Hold_r(hp);
+           ("GSS: Delete longest inactive host %p (%s:%d)\n",
+             hp, afs_inet_ntoa_r(hp->host, hoststr), ntohs(hp->port)));
+
+    h_Hold_r(hp);
 
     /** Try a non-blocking lock. If the lock is already held return
       * after releasing hold on hp
       */
     if (!locked) {
-       if (h_NBLock_r(hp)) {
-           if (!held)
-               h_Release_r(hp);
-           return 1;
-       }
+        if (h_NBLock_r(hp)) {
+            h_Release_r(hp);
+            return 1;
+        }
     }
     if (hp->Console & 2) {
        /*
@@ -1618,7 +1650,7 @@ ClearHostCallbacks_r(struct host *hp, int locked)
     DeleteAllCallBacks_r(hp, 1);
     if (hp->hostFlags & VENUSDOWN) {
        hp->hostFlags &= ~RESETDONE;    /* remember that we must do a reset */
-    } else {
+    } else if (!(hp->hostFlags & HOSTDELETED)) {
        /* host is up, try a call */
        hp->hostFlags &= ~ALTADDR;      /* alternate addresses are invalid */
        cb_conn = hp->callback_rxcon;
@@ -1644,11 +1676,9 @@ ClearHostCallbacks_r(struct host *hp, int locked)
            hp->hostFlags |= RESETDONE;
        }
     }
-    if (!locked) {
-       h_Unlock_r(hp);
-    }
-    if (!held)
-       h_Release_r(hp);
+    if (!locked)
+        h_Unlock_r(hp);
+    h_Release_r(hp);
 
     return 0;
 }
@@ -1671,6 +1701,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
 
@@ -1907,7 +1939,6 @@ cb_stateVerify(struct fs_dump_state * state)
        ret = 1;
     }
 
- done:
     return ret;
 }
 
@@ -1941,7 +1972,6 @@ cb_stateVerifyFEHash(struct fs_dump_state * state)
        }
     }
 
- done:
     return ret;
 }
 
@@ -1952,16 +1982,18 @@ cb_stateVerifyFE(struct fs_dump_state * state, struct FileEntry * fe)
 
     if ((fe->firstcb && !fe->ncbs) ||
        (!fe->firstcb && fe->ncbs)) {
-       ViceLog(0, ("cb_stateVerifyFE: error: fe->firstcb does not agree with fe->ncbs (fei=%d, fe->firstcb=%d, fe->ncbs=%d)\n",
-                   fetoi(fe), fe->firstcb, fe->ncbs));
+       ViceLog(0, ("cb_stateVerifyFE: error: fe->firstcb does not agree with fe->ncbs (fei=%lu, fe->firstcb=%lu, fe->ncbs=%lu)\n",
+                   afs_printable_uint32_lu(fetoi(fe)),
+                   afs_printable_uint32_lu(fe->firstcb),
+                   afs_printable_uint32_lu(fe->ncbs)));
        ret = 1;
     }
     if (cb_stateVerifyFCBList(state, fe)) {
-       ViceLog(0, ("cb_stateVerifyFE: error: FCBList failed verification (fei=%d)\n", fetoi(fe)));
+       ViceLog(0, ("cb_stateVerifyFE: error: FCBList failed verification (fei=%lu)\n",
+                   afs_printable_uint32_lu(fetoi(fe))));
        ret = 1;
     }
 
- done:
     return ret;
 }
 
@@ -2119,7 +2151,6 @@ cb_stateVerifyTimeoutQueues(struct fs_dump_state * state)
        }
     }
 
- done:
     return ret;
 }
 
@@ -2313,7 +2344,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 +2365,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 +2391,6 @@ cb_stateSaveFE(struct fs_dump_state * state, struct FileEntry * fe)
            }
            written = 1;
            iovcnt = 0;
-           len = 0;
        }
     }
 
@@ -2399,18 +2429,17 @@ 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];
     struct iovec iov[16];
     struct FileEntry * fe;
-    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 +2465,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 +2480,6 @@ cb_stateRestoreFE(struct fs_dump_state * state)
                    ret = 1;
                    goto done;
                }
-               len = 0;
                iovcnt = 0;
            }
        }
@@ -2644,11 +2672,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 +2711,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);
@@ -2736,8 +2784,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++;
@@ -2769,6 +2818,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++;
@@ -2782,16 +2844,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,
+       time_t uxtfirst = UXtime(tfirst), tnow = now;
+       printf("The time of the dump was %u %s", (unsigned int) now, ctime(&tnow));
+       printf("The last time cleanup ran was %u %s", (unsigned int) uxtfirst,
               ctime(&uxtfirst));
        PrintCallBackStats();
     }
@@ -2802,7 +2868,7 @@ main(int argc, char **argv)
        struct FileEntry *fe;
 
        for (hash = 0; hash < FEHASH_SIZE; hash++) {
-           for (feip = &HashTable[hash]; fe = itofe(*feip);) {
+           for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
                if (!vol || (fe->volid == vol)) {
                    register struct CallBack *cbnext;
                    for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
@@ -2855,7 +2921,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));
 }
@@ -2893,10 +2959,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 */
@@ -2930,8 +2994,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 %p (%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);
@@ -2941,14 +3005,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;
        }
@@ -2988,11 +3055,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)
@@ -3015,8 +3080,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++;
@@ -3024,8 +3089,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 %p (%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);
@@ -3035,20 +3101,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  
@@ -3060,14 +3130,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;
             }
         }