comment assumptions in lih0_r
[openafs.git] / src / viced / callback.c
index 82bdce2..9cfd1d5 100644 (file)
@@ -84,8 +84,6 @@
 #include <afsconfig.h>
 #include <afs/param.h>
 
-RCSID
-    ("$Header$");
 
 #include <stdio.h>
 #include <stdlib.h>            /* for malloc() */
@@ -97,6 +95,7 @@ RCSID
 #else
 #include <sys/time.h>
 #include <sys/file.h>
+#include <unistd.h>
 #endif
 #include <afs/assert.h>
 
@@ -105,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>
@@ -124,7 +123,10 @@ RCSID
 
 extern afsUUID FS_HostUUID;
 extern int hostCount;
+
+#ifndef INTERPRET_DUMP
 static int ShowProblems = 1;
+#endif
 
 struct cbcounters cbstuff;
 
@@ -153,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];
@@ -168,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);
@@ -188,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))
@@ -381,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;
 }
@@ -511,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);
@@ -532,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
@@ -555,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);
@@ -644,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.
@@ -673,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;
@@ -705,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 {
                    /* 
@@ -714,7 +740,8 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
                    if (MultiBreakCallBackAlternateAddress(hp, afidp)) {
                        if (ShowProblems) {
                            ViceLog(7,
-                                   ("BCB: Failed on file %u.%u.%u, Host %x (%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,
@@ -725,12 +752,14 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
 
                        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;
                    }
@@ -785,7 +814,7 @@ BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
     char hoststr[16];
 
     ViceLog(7,
-           ("BCB: BreakCallBack(Host %x all but %s:%d, (%u,%u,%u))\n",
+           ("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));
 
@@ -815,15 +844,17 @@ 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: %x (%s:%d) is down; delaying break call back\n",
+                           ("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 {
-                   h_Hold_r(thishost);
-                   cba[ncbas].hp = thishost;
-                   cba[ncbas].thead = cb->thead;
-                   ncbas++;
+                   if (!(thishost->hostFlags & HOSTDELETED)) {
+                       h_Hold_r(thishost);
+                       cba[ncbas].hp = thishost;
+                       cba[ncbas].thead = cb->thead;
+                       ncbas++;
+                   }
                    TDel(cb);
                    HDel(cb);
                    CDel(cb, 1);        /* Usually first; so this delete 
@@ -861,10 +892,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);
@@ -877,7 +909,7 @@ DeleteCallBack(struct host *host, AFSFid * fid)
     pcb = FindCBPtr(fe, host);
     if (!*pcb) {
        ViceLog(8,
-               ("DCB: No call back for host %x (%s:%d), (%u, %u, %u)\n",
+               ("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);
@@ -922,6 +954,7 @@ DeleteFileCallBacks(AFSFid * fid)
        TDel(cb);
        HDel(cb);
        FreeCB(cb);
+       fe->ncbs--;
     }
     FDel(fe);
     H_UNLOCK;
@@ -998,15 +1031,17 @@ BreakDelayedCallBacks_r(struct host *host)
        if (code) {
            if (ShowProblems) {
                ViceLog(0,
-                       ("CB: Call back connect back failed (in break delayed) for Host %x (%s:%d)\n",
+                       ("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 %x (%s:%d)\n",
-                    host, afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
+                   ("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;
@@ -1045,14 +1080,16 @@ BreakDelayedCallBacks_r(struct host *host)
                int i;
                if (ShowProblems) {
                    ViceLog(0,
-                           ("CB: XCallBackBulk failed, Host %x (%s:%d); callback list follows:\n",
+                           ("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 %x (%s:%d), file %u.%u.%u (part of bulk callback)\n",
+                               ("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));
@@ -1095,16 +1132,10 @@ 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 %x (%s:%d) failed\n",
-                 host, 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 %x (%s:%d) failed\n",
+                   ("BVCB: volume callback for Host %p (%s:%d) failed\n",
                     host, afs_inet_ntoa_r(host->host, hoststr),
                     ntohs(host->port)));
        }
@@ -1143,9 +1174,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);
@@ -1158,9 +1190,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);
@@ -1202,11 +1234,14 @@ BreakVolumeCallBacks(afs_uint32 volume)
                register struct CallBack *cbnext;
                for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
                    host = h_itoh(cb->hhead);
-                   h_Hold_r(host);
-                   cbnext = itocb(cb->cnext);
-                   if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
-                       tthead = cb->thead;
+
+                   if (!(host->hostFlags & HOSTDELETED)) {
+                       h_Hold_r(host);
+                       if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
+                           tthead = cb->thead;
+                       }
                    }
+                   cbnext = itocb(cb->cnext);
                    TDel(cb);
                    HDel(cb);
                    FreeCB(cb);
@@ -1229,7 +1264,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;
@@ -1329,6 +1364,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;
@@ -1352,9 +1388,11 @@ BreakLaterCallBacks(void)
            cbnext = itocb(cb->cnext);
            host = h_itoh(cb->hhead);
            if (cb->status == CB_DELAYED) {
-               h_Hold_r(host);
-               if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
-                   tthead = cb->thead;
+               if (!(host->hostFlags & HOSTDELETED)) {
+                   h_Hold_r(host);
+                   if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
+                       tthead = cb->thead;
+                   }
                }
                TDel(cb);
                HDel(cb);
@@ -1362,7 +1400,7 @@ BreakLaterCallBacks(void)
                /* leave hold for MultiBreakVolumeCallBack to clear */
            } else {
                ViceLog(125,
-                       ("Found host %x (%s:%d) non-DELAYED cb for %u:%u:%u\n", 
+                       ("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));
            }
@@ -1448,54 +1486,89 @@ CleanupTimedOutCallBacks_r(void)
     return (ntimedout > 0);
 }
 
-static struct host *lih_host;
-static int lih_host_held;
+/**
+ * parameters to pass to lih*_r from h_Enumerate_r when trying to find a host
+ * from which to clear callbacks.
+ */
+struct lih_params {
+    /**
+     * Points to the least interesting host found; try to clear callbacks on
+     * this host after h_Enumerate_r(lih*_r)'ing.
+     */
+    struct host *lih;
+
+    /**
+     * The last host we got from lih*_r, but we couldn't clear its callbacks
+     * for some reason. Choose the next-best host after this one (with the
+     * current lih*_r, this means to only select hosts that have an ActiveCall
+     * newer than lastlih).
+     */
+    struct host *lastlih;
+};
+
+/* 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.
+ * is newer than 'params->lastlih' 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.
+ *
+ * There is a small problem here, but it may not be easily fixable. Say we
+ * select some host A, and give it back to GetSomeSpace_r. GSS_r for some
+ * reason cannot clear the callbacks on A, and so calls us again with
+ * lastlih = A. Suppose there is another host B that has the same ActiveCall
+ * time as A. We will now skip over host B, since
+ * 'hostB->ActiveCall > hostA->ActiveCall' is not true. This could result in
+ * us prematurely going to the GSS_r 2nd or 3rd pass, and making us a little
+ * inefficient. This should be pretty rare, though, except perhaps in cases
+ * with very small numbers of hosts.
+ *
+ * Also filter out any hosts with HOSTDELETED set. h_Enumerate_r should in
+ * theory not give these to us anyway, but be paranoid.
  */
 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 lih_params *params = (struct lih_params *)rock;
+
+    /* OTHER_MUSTHOLD_LIH is because the h_Enum loop holds us once */
     if (host->cblist
-       && (hostp && host != hostp) 
-       && (!held && !h_OtherHolds_r(host))
-       && (!lih_host || host->ActiveCall < lih_host->ActiveCall) 
-       && (!hostp || host->ActiveCall > hostp->ActiveCall)) {
-       if (lih_host != NULL && lih_host_held) {
-           h_Release_r(lih_host);
+       && (!(host->hostFlags & HOSTDELETED))
+       && (host->refCount < OTHER_MUSTHOLD_LIH)
+       && (!params->lih || host->ActiveCall < params->lih->ActiveCall)
+       && (!params->lastlih || host->ActiveCall > params->lastlih->ActiveCall)) {
+
+       if (params->lih) {
+           h_Release_r(params->lih); /* release prev host */
        }
-       lih_host = host;
-       lih_host_held = !held;
-       held = 1;
+
+       h_Hold_r(host);
+       params->lih = host;
     }
-    return held;
+    return flags;
 }
 
-/* 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).  In this second varient, we do not 
- * prevent held hosts from being selected.
- */
+/* same as lih0_r, except we do not 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 lih_params *params = (struct lih_params *)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);
+       && (!(host->hostFlags & HOSTDELETED))
+       && (!params->lih || host->ActiveCall < params->lih->ActiveCall)
+       && (!params->lastlih || host->ActiveCall > params->lastlih->ActiveCall)) {
+
+       if (params->lih) {
+           h_Release_r(params->lih); /* release prev host */
        }
-       lih_host = host;
-       lih_host_held = !held;
-       held = 1;
+
+       h_Hold_r(host);
+       params->lih = host;
     }
-    return held;
+    return flags;
 }
 
 /* This could be upgraded to get more space each time */
@@ -1513,7 +1586,8 @@ extern struct host *hostList;
 static int
 GetSomeSpace_r(struct host *hostp, int locked)
 {
-    register struct host *hp, *hp1, *hp2;
+    struct host *hp;
+    struct lih_params params;
     int i = 0;
 
     cbstuff.GotSomeSpaces++;
@@ -1525,36 +1599,39 @@ GetSomeSpace_r(struct host *hostp, int locked)
     }
 
     i = 0;
-    hp1 = NULL;
-    hp2 = hostList;
+    params.lastlih = NULL;
+
     do {
-       lih_host = 0;
-       h_Enumerate_r(i == 0 ? lih0_r : lih1_r, hp2, (char *)hp1);
-       hp = lih_host;
+       params.lih = NULL;
+
+       h_Enumerate_r(i == 0 ? lih0_r : lih1_r, hostList, &params);
+
+       hp = params.lih;
+       if (params.lastlih) {
+           h_Release_r(params.lastlih);
+           params.lastlih = NULL;
+       }
+
        if (hp) {
-           /* set in lih_r! private copy before giving up H_LOCK */
-           int lih_host_held2=lih_host_held;   
+           /* note that 'hp' was held by lih*_r; we will need to release it */
            cbstuff.GSS4++;
            if ((hp != hostp) && !ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
-               if (lih_host_held2)
-                   h_Release_r(hp);
+                h_Release_r(hp);
                return 0;
            }
-           if (lih_host_held2)
-               h_Release_r(hp);
-           hp1 = hp;
-           hp2 = hostList;
+
+           params.lastlih = hp;
+           /* params.lastlih will be released on the next iteration, after
+            * h_Enumerate_r */
+
        } else {
            /*
             * Next time try getting callbacks from any host even if
-            * it's deleted (that's actually great since we can freely
-            * remove its callbacks) or it's held since the only other
-            * option is starvation for the file server (i.e. until the
-            * callback timeout arrives).
+            * it's held, since the only other option is starvation for
+            * the file server (i.e. until the callback timeout arrives).
             */
            i++;
-           hp1 = NULL;
-           hp2 = hostList;
+           params.lastlih = NULL;
            cbstuff.GSS1++;
            ViceLog(5,
                    ("GSS: Try harder for longest inactive host cnt= %d\n",
@@ -1579,25 +1656,30 @@ 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 %x (%s:%d)\n",
+           ("GSS: Delete longest inactive host %p (%s:%d)\n",
              hp, afs_inet_ntoa_r(hp->host, hoststr), ntohs(hp->port)));
-    if (!(held = h_Held_r(hp)))
-       h_Hold_r(hp);
+
+    if ((hp->hostFlags & HOSTDELETED)) {
+       /* hp could go away after reacquiring H_LOCK in h_NBLock_r, so we can't
+        * really use it; its callbacks will get cleared anyway when
+        * h_TossStuff_r gets its hands on it */
+       return 1;
+    }
+
+    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) {
        /*
@@ -1614,7 +1696,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;
@@ -1640,11 +1722,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;
 }
@@ -1667,6 +1747,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
 
@@ -1903,7 +1985,6 @@ cb_stateVerify(struct fs_dump_state * state)
        ret = 1;
     }
 
- done:
     return ret;
 }
 
@@ -1937,7 +2018,6 @@ cb_stateVerifyFEHash(struct fs_dump_state * state)
        }
     }
 
- done:
     return ret;
 }
 
@@ -1948,16 +2028,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;
 }
 
@@ -2115,7 +2197,6 @@ cb_stateVerifyTimeoutQueues(struct fs_dump_state * state)
        }
     }
 
- done:
     return ret;
 }
 
@@ -2400,7 +2481,6 @@ cb_stateRestoreFE(struct fs_dump_state * state)
     struct CBDiskEntry cbdsk[16];
     struct iovec iov[16];
     struct FileEntry * fe;
-    struct CallBack * cb;
 
     iov[0].iov_base = (char *)&hdr;
     iov[0].iov_len = sizeof(hdr);
@@ -2638,11 +2718,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",
@@ -2674,34 +2757,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);
@@ -2730,8 +2830,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++;
@@ -2763,6 +2864,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++;
@@ -2776,16 +2890,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();
     }
@@ -2796,7 +2914,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) {
@@ -2849,7 +2967,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));
 }
@@ -2922,7 +3040,7 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
 
     assert(j);                 /* at least one alternate address */
     ViceLog(125,
-           ("Starting multibreakcall back on all addr for host %x (%s:%d)\n",
+           ("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) {
@@ -3017,7 +3135,7 @@ MultiProbeAlternateAddress_r(struct host *host)
 
     assert(j);                 /* at least one alternate address */
     ViceLog(125,
-           ("Starting multiprobe on all addr for host %x (%s:%d)\n",
+           ("Starting multiprobe on all addr for host %p (%s:%d)\n",
              host, afs_inet_ntoa_r(host->host, hoststr),
              ntohs(host->port)));
     H_UNLOCK;