viced-log-add-ports-20060202
[openafs.git] / src / viced / callback.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * NEW callback package callback.c (replaces vicecb.c)
12  * Updated call back routines, NOW with:
13  * 
14  *     Faster DeleteVenus (Now called DeleteAllCallBacks)
15  *     Call back breaking for volumes
16  *     Adaptive timeouts on call backs
17  *     Architected for Multi RPC
18  *     No locks (currently implicit vnode locks--these will go, to)
19  *     Delayed call back when rpc connection down.
20  *     Bulk break of delayed call backs when rpc connection
21  *         reestablished
22  *     Strict limit on number of call backs.
23  *
24  * InitCallBack(nblocks)
25  *     Initialize: nblocks is max number # of file entries + # of callback entries
26  *     nblocks must be < 65536
27  *     Space used is nblocks*16 bytes
28  *     Note that space will be reclaimed by breaking callbacks of old hosts
29  * 
30  * time = AddCallBack(host, fid)
31  *     Add a call back.
32  *     Returns the expiration time at the workstation.
33  * 
34  * BreakCallBack(host, fid)
35  *     Break all call backs for fid, except for the specified host.
36  *     Delete all of them.
37  * 
38  * BreakVolumeCallBacks(volume)
39  *     Break all call backs on volume, using single call to each host
40  *     Delete all the call backs.
41  * 
42  * DeleteCallBack(host,fid)
43  *     Delete (do not break) single call back for fid.
44  * 
45  * DeleteFileCallBacks(fid)
46  *     Delete (do not break) all call backs for fid.
47  *
48  * DeleteAllCallBacks(host)
49  *     Delete (do not break) all call backs for host.
50  * 
51  * CleanupTimedOutCallBacks()
52  *     Delete all timed out call back entries
53  *     Must be called periodically by file server.
54  * 
55  * BreakDelayedCallBacks(host)
56  *     Break all delayed call backs for host.
57  *     Returns 1: one or more failed, 0: success.
58  * 
59  * PrintCallBackStats()
60  *     Print statistics about call backs to stdout.
61  * 
62  * DumpCallBacks() ---wishful thinking---
63  *     Dump call back state to /tmp/callback.state.
64  *     This is separately interpretable by the program pcb.
65  *
66  * Notes:  In general, if a call back to a host doesn't get through,
67  * then HostDown, supplied elsewhere, is called.  BreakDelayedCallBacks,
68  * however, does not call HostDown, but instead returns an indication of
69  * success if all delayed call backs were finally broken.
70  *
71  * BreakDelayedCallBacks MUST be called at the first sign of activity
72  * from the host after HostDown has been called (or a previous
73  * BreakDelayedCallBacks failed). The BreakDelayedCallBacks must be
74  * allowed to complete before any requests from that host are handled.
75  * If BreakDelayedCallBacks fails, then the host should remain
76  * down (and the request should be failed).
77
78  * CleanupCallBacks MUST be called periodically by the file server for
79  * this package to work correctly.  Every 5 minutes is suggested.
80  */
81
82 #include <afsconfig.h>
83 #include <afs/param.h>
84
85 RCSID
86     ("$Header$");
87
88 #include <stdio.h>
89 #include <stdlib.h>             /* for malloc() */
90 #include <time.h>               /* ANSI standard location for time stuff */
91 #ifdef AFS_NT40_ENV
92 #include <fcntl.h>
93 #include <io.h>
94 #else
95 #include <sys/time.h>
96 #include <sys/file.h>
97 #endif
98 #ifdef HAVE_STRING_H
99 #include <string.h>
100 #else
101 #ifdef HAVE_STRINGS_H
102 #include <strings.h>
103 #endif
104 #endif
105 #include <afs/assert.h>
106
107 #include <afs/stds.h>
108
109 #include <afs/nfs.h>            /* yuck.  This is an abomination. */
110 #include <lwp.h>
111 #include <rx/rx.h>
112 #include <afscbint.h>
113 #include <afs/afsutil.h>
114 #include <lock.h>
115 #include <afs/ihandle.h>
116 #include <afs/vnode.h>
117 #include <afs/volume.h>
118 #include "viced_prototypes.h"
119 #include "viced.h"
120
121 #include <afs/ptclient.h>       /* need definition of prlist for host.h */
122 #include "host.h"
123
124 extern afsUUID FS_HostUUID;
125 extern int hostCount;
126 int ShowProblems = 1;
127
128 /* Maximum number of call backs to break at once, single fid */
129 /* There is some debate as to just how large this value should be */
130 /* Ideally, it would be very very large, but I am afraid that the */
131 /* cache managers will all send in their responses simultaneously, */
132 /* thereby swamping the file server.  As a result, something like */
133 /* 10 or 15 might be a better bet. */
134 #define MAX_CB_HOSTS    10
135
136 /* max time to break a callback, otherwise client is dead or net is hosed */
137 #define MAXCBT 25
138
139 #define u_byte  unsigned char
140
141 struct cbcounters cbstuff;
142
143 struct cbstruct {
144     struct host *hp;
145     afs_uint32 thead;
146 };
147
148 struct FileEntry {
149     afs_uint32 vnode;
150     afs_uint32 unique;
151     afs_uint32 volid;
152     afs_uint32 fnext;
153     afs_uint32 ncbs;
154     afs_uint32 firstcb;
155     afs_uint32 status;
156     afs_uint32 spare;
157 } *FE;                          /* Don't use FE[0] */
158 #define FE_LATER 0x1
159
160 struct CallBack {
161     afs_uint32 cnext;           /* Next call back entry */
162     afs_uint32 fhead;           /* Head of this call back chain */
163     u_byte thead;               /* Head of timeout chain */
164     u_byte status;              /* Call back status; see definitions, below */
165     afs_uint32 hhead;           /* Head of host table chain */
166     afs_uint32 tprev, tnext;    /* Timeout chain */
167     afs_uint32 hprev, hnext;    /* Chain from host table */
168     unsigned short spare;       /* make it a multiple of 32 bits. */
169 } *CB;                          /* Don't use CB[0] */
170
171 /* status values for status field of CallBack structure */
172 #define CB_NORMAL   1           /* Normal call back */
173 #define CB_DELAYED  2           /* Delayed call back due to rpc problems.
174                                  * The call back entry will be added back to the
175                                  * host list at the END of the list, so that
176                                  * searching backwards in the list will find all
177                                  * the (consecutive)host. delayed call back entries */
178 #define CB_VOLUME   3           /* Callback for a volume */
179 #define CB_BULK     4           /* Normal callbacks, handed out from FetchBulkStatus */
180
181 /* call back indices to pointers, and vice-versa */
182 #define itocb(i)    ((i)?CB+(i):0)
183 #define cbtoi(cbp)  (!(cbp)?0:(cbp)-CB)
184
185 /* file entry indices to pointers, and vice-versa */
186 #define itofe(i)    ((i)?FE+(i):0)
187 #define fetoi(fep)  (!(fep)?0:(fep)-FE)
188
189 /* Timeouts:  there are 128 possible timeout values in effect at any
190  * given time.  Each timeout represents timeouts in an interval of 128
191  * seconds.  So the maximum timeout for a call back is 128*128=16384
192  * seconds, or 4 1/2 hours.  The timeout cleanup stuff is called only
193  * if space runs out or by the file server every 5 minutes.  This 5
194  * minute slack should be allowed for--so a maximum time of 4 hours
195  * is safer.
196  *
197  * Timeouts must be chosen to correspond to an exact multiple
198  * of 128, because all times are truncated to a 128 multiple, and
199  * timed out if the current truncated time is <= to the truncated time
200  * corresponding to the timeout queue.
201  */
202
203 /* Unix time to Call Back time, and vice-versa.  Call back time is
204    in units of 128 seconds, corresponding to time queues. */
205 #define CBtime(uxtime)  ((uxtime)>>7)
206 #define UXtime(cbtime)  ((cbtime)<<7)
207
208 /* Given a Unix time, compute the closest Unix time that corresponds to
209    a time queue, rounding up */
210 #define TimeCeiling(uxtime)     (((uxtime)+127)&~127)
211
212 /* Time to live for call backs depends upon number of users of the file.
213  * TimeOuts is indexed by this number/8 (using TimeOut macro).  Times
214  * in this table are for the workstation; server timeouts, add
215  * ServerBias */
216
217 static int TimeOuts[] = {
218 /* Note: don't make the first entry larger than 4 hours (see above) */
219     4 * 60 * 60,                /* 0-7 users */
220     1 * 60 * 60,                /* 8-15 users */
221     30 * 60,                    /* 16-23 users */
222     15 * 60,                    /* 24-31 users */
223     15 * 60,                    /* 32-39 users */
224     10 * 60,                    /* 40-47 users */
225     10 * 60,                    /* 48-55 users */
226     10 * 60,                    /* 56-63 users */
227 };                              /* Anything more: MinTimeOut */
228
229 /* minimum time given for a call back */
230 static int MinTimeOut = (7 * 60);
231
232 #define TimeOutCutoff   ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
233 #define TimeOut(nusers)  ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
234
235 /* time out at server is 3 minutes more than ws */
236 #define ServerBias        (3*60)
237
238 /* Heads of CB queues; a timeout index is 1+index into this array */
239 static afs_uint32 timeout[128];
240
241 /* Convert cbtime to timeout queue index */
242 #define TIndex(cbtime)  (((cbtime)&127)+1)
243
244 /* Convert cbtime to pointer to timeout queue head */
245 #define THead(cbtime)   (&timeout[TIndex(cbtime)-1])
246
247 static afs_int32 tfirst;        /* cbtime of oldest unexpired call back time queue */
248
249 /* Normalize index into timeout array so that two such indices will be
250    ordered correctly, so that they can be compared to see which times
251    sooner, or so that the difference in time out times between them
252    can be computed. */
253 #define TNorm(index)   ((index)<TIndex(tfirst)?(index)+128:(index))
254
255 /* This converts a timeout index into the actual time it will expire */
256 #define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
257
258
259 /* Convert pointer to timeout queue head to index, and vice versa */
260 #define ttoi(t)         ((t-timeout)+1)
261 #define itot(i)         ((timeout)+(i-1))
262
263 /* 16 byte object get/free routines */
264 struct object {
265     struct object *next;
266 };
267
268 struct VCBParams {
269     struct cbstruct cba[MAX_CB_HOSTS];  /* re-entrant storage */
270     unsigned int ncbas;
271     afs_uint32 thead;           /* head of timeout queue for youngest callback */
272     struct AFSFid *fid;
273 };
274
275 struct CallBack *CBfree = 0;
276 struct FileEntry *FEfree = 0;
277
278 /* Prototypes for static routines */
279 static struct FileEntry *FindFE(register AFSFid * fid);
280 static struct CallBack *iGetCB(register int *nused);
281 static int iFreeCB(register struct CallBack *cb, register int *nused);
282 static struct FileEntry *iGetFE(register int *nused);
283 static int iFreeFE(register struct FileEntry *fe, register int *nused);
284 static int TAdd(register struct CallBack *cb, register afs_uint32 * thead);
285 static int TDel(register struct CallBack *cb);
286 static int HAdd(register struct CallBack *cb, register struct host *host);
287 static int HDel(register struct CallBack *cb);
288 static int CDel(struct CallBack *cb, int deletefe);
289 static int CDelPtr(register struct FileEntry *fe, register afs_uint32 * cbp,
290                    int deletefe);
291 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host);
292 static int FDel(register struct FileEntry *fe);
293 static int AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead,
294                           int type, int locked);
295 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
296                                  struct AFSCBFids *afidp, struct host *xhost);
297 static int MultiBreakVolumeCallBack_r(struct host *host, int isheld,
298                                       struct VCBParams *parms, int deletefe);
299 static int MultiBreakVolumeCallBack(struct host *host, int isheld,
300                                     struct VCBParams *parms);
301 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
302                                          struct VCBParams *parms);
303 static int lih_r(register struct host *host, register int held,
304                  register struct host *hostp);
305 static int GetSomeSpace_r(struct host *hostp, int locked);
306 static int ClearHostCallbacks_r(struct host *hp, int locked);
307
308 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
309 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
310 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
311 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
312
313 /* Other protos - move out sometime */
314 extern void ShutDown();
315
316 #define VHASH 512               /* Power of 2 */
317 static afs_uint32 HashTable[VHASH];     /* File entry hash table */
318 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
319
320 static struct FileEntry *
321 FindFE(register AFSFid * fid)
322 {
323     int hash;
324     register int fei;
325     register struct FileEntry *fe;
326
327     hash = VHash(fid->Volume, fid->Unique);
328     for (fei = HashTable[hash]; fei; fei = fe->fnext) {
329         fe = itofe(fei);
330         if (fe->volid == fid->Volume && fe->unique == fid->Unique
331             && fe->vnode == fid->Vnode && (fe->status & FE_LATER) != FE_LATER)
332             return fe;
333     }
334     return 0;
335 }
336
337 #ifndef INTERPRET_DUMP
338
339 static struct CallBack *
340 iGetCB(register int *nused)
341 {
342     register struct CallBack *ret;
343
344     if ((ret = CBfree)) {
345         CBfree = (struct CallBack *)(((struct object *)ret)->next);
346         (*nused)++;
347     }
348     return ret;
349 }
350
351 static int
352 iFreeCB(register struct CallBack *cb, register int *nused)
353 {
354     ((struct object *)cb)->next = (struct object *)CBfree;
355     CBfree = cb;
356     (*nused)--;
357     return 0;
358 }
359
360 static struct FileEntry *
361 iGetFE(register int *nused)
362 {
363     register struct FileEntry *ret;
364
365     if ((ret = FEfree)) {
366         FEfree = (struct FileEntry *)(((struct object *)ret)->next);
367         (*nused)++;
368     }
369     return ret;
370 }
371
372 static int
373 iFreeFE(register struct FileEntry *fe, register int *nused)
374 {
375     ((struct object *)fe)->next = (struct object *)FEfree;
376     FEfree = fe;
377     (*nused)--;
378     return 0;
379 }
380
381 /* Add cb to end of specified timeout list */
382 static int
383 TAdd(register struct CallBack *cb, register afs_uint32 * thead)
384 {
385     if (!*thead) {
386         (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
387     } else {
388         register struct CallBack *thp = itocb(*thead);
389
390         cb->tprev = thp->tprev;
391         cb->tnext = *thead;
392         if (thp) {
393             if (thp->tprev)
394                 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
395             else
396                 thp->tprev = cbtoi(cb);
397         }
398     }
399     cb->thead = ttoi(thead);
400     return 0;
401 }
402
403 /* Delete call back entry from timeout list */
404 static int
405 TDel(register struct CallBack *cb)
406 {
407     register afs_uint32 *thead = itot(cb->thead);
408
409     if (*thead == cbtoi(cb))
410         *thead = (*thead == cb->tnext ? 0 : cb->tnext);
411     if (itocb(cb->tprev))
412         itocb(cb->tprev)->tnext = cb->tnext;
413     if (itocb(cb->tnext))
414         itocb(cb->tnext)->tprev = cb->tprev;
415     return 0;
416 }
417
418 /* Add cb to end of specified host list */
419 static int
420 HAdd(register struct CallBack *cb, register struct host *host)
421 {
422     cb->hhead = h_htoi(host);
423     if (!host->cblist) {
424         host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
425     } else {
426         register struct CallBack *hhp = itocb(host->cblist);
427
428         cb->hprev = hhp->hprev;
429         cb->hnext = host->cblist;
430         hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
431     }
432     return 0;
433 }
434
435 /* Delete call back entry from host list */
436 static int
437 HDel(register struct CallBack *cb)
438 {
439     register afs_uint32 *hhead = &h_itoh(cb->hhead)->cblist;
440
441     if (*hhead == cbtoi(cb))
442         *hhead = (*hhead == cb->hnext ? 0 : cb->hnext);
443     itocb(cb->hprev)->hnext = cb->hnext;
444     itocb(cb->hnext)->hprev = cb->hprev;
445     return 0;
446 }
447
448 /* Delete call back entry from fid's chain of cb's */
449 /* N.B.  This one also deletes the CB, and also possibly parent FE, so
450  * make sure that it is not on any other list before calling this
451  * routine */
452 static int
453 CDel(struct CallBack *cb, int deletefe)
454 {
455     int cbi = cbtoi(cb);
456     struct FileEntry *fe = itofe(cb->fhead);
457     register afs_uint32 *cbp;
458     register int safety;
459
460     for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
461          cbp = &itocb(*cbp)->cnext, safety++) {
462         if (safety > cbstuff.nblks + 10) {
463             assert(0);
464             ViceLog(0,
465                     ("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",
466                      cbi, fe->firstcb, *cbp));
467             DumpCallBackState();
468             ShutDownAndCore(PANIC);
469         }
470     }
471     CDelPtr(fe, cbp, deletefe);
472     return 0;
473 }
474
475 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
476  * as well as file entry */
477 /* N.B.  This one also deletes the CB, and also possibly parent FE, so
478  * make sure that it is not on any other list before calling this
479  * routine */
480 int Ccdelpt = 0, CcdelB = 0;
481
482 static int
483 CDelPtr(register struct FileEntry *fe, register afs_uint32 * cbp,
484         int deletefe)
485 {
486     register struct CallBack *cb;
487
488     if (!*cbp)
489         return 0;
490     Ccdelpt++;
491     cb = itocb(*cbp);
492     if (cb != &CB[*cbp])
493         CcdelB++;
494     *cbp = cb->cnext;
495     FreeCB(cb);
496     if (deletefe && (--fe->ncbs == 0))
497         FDel(fe);
498     return 0;
499 }
500
501 static afs_uint32 *
502 FindCBPtr(struct FileEntry *fe, struct host *host)
503 {
504     register afs_uint32 hostindex = h_htoi(host);
505     register struct CallBack *cb;
506     register afs_uint32 *cbp;
507     register int safety;
508
509     for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
510         if (safety > cbstuff.nblks) {
511             ViceLog(0, ("FindCBPtr: Internal Error -- shutting down.\n"));
512             DumpCallBackState();
513             ShutDownAndCore(PANIC);
514         }
515         cb = itocb(*cbp);
516         if (cb->hhead == hostindex)
517             break;
518     }
519     return cbp;
520 }
521
522 /* Delete file entry from hash table */
523 static int
524 FDel(register struct FileEntry *fe)
525 {
526     register int fei = fetoi(fe);
527     register afs_uint32 *p = &HashTable[VHash(fe->volid, fe->unique)];
528
529     while (*p && *p != fei)
530         p = &itofe(*p)->fnext;
531     assert(*p);
532     *p = fe->fnext;
533     FreeFE(fe);
534     return 0;
535 }
536
537 int
538 InitCallBack(int nblks)
539 {
540     H_LOCK;
541     tfirst = CBtime(FT_ApproxTime());
542     /* N.B. The "-1", below, is because
543      * FE[0] and CB[0] are not used--and not allocated */
544     FE = ((struct FileEntry *)(calloc(nblks, sizeof(struct FileEntry)))) - 1;
545     if (!FE) {
546         ViceLog(0, ("Failed malloc in InitCallBack\n"));
547         assert(0);
548     }
549     cbstuff.nFEs = nblks;
550     while (cbstuff.nFEs)
551         FreeFE(&FE[cbstuff.nFEs]);      /* This is correct */
552     CB = ((struct CallBack *)(calloc(nblks, sizeof(struct CallBack)))) - 1;
553     if (!CB) {
554         ViceLog(0, ("Failed malloc in InitCallBack\n"));
555         assert(0);
556     }
557     cbstuff.nCBs = nblks;
558     while (cbstuff.nCBs)
559         FreeCB(&CB[cbstuff.nCBs]);      /* This is correct */
560     cbstuff.nblks = nblks;
561     cbstuff.nbreakers = 0;
562     H_UNLOCK;
563     return 0;
564 }
565
566 afs_int32
567 XCallBackBulk_r(struct host * ahost, struct AFSFid * fids, afs_int32 nfids)
568 {
569     struct AFSCallBack tcbs[AFSCBMAX];
570     register int i;
571     struct AFSCBFids tf;
572     struct AFSCBs tc;
573     int code;
574     int j;
575     struct rx_connection *cb_conn = NULL;
576
577 #ifdef  ADAPT_MTU
578     rx_SetConnDeadTime(ahost->callback_rxcon, 4);
579     rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
580 #endif
581
582     code = 0;
583     j = 0;
584     while (nfids > 0) {
585
586         for (i = 0; i < nfids && i < AFSCBMAX; i++) {
587             tcbs[i].CallBackVersion = CALLBACK_VERSION;
588             tcbs[i].ExpirationTime = 0;
589             tcbs[i].CallBackType = CB_DROPPED;
590         }
591         tf.AFSCBFids_len = i;
592         tf.AFSCBFids_val = &(fids[j]);
593         nfids -= i;
594         j += i;
595         tc.AFSCBs_len = i;
596         tc.AFSCBs_val = tcbs;
597
598         cb_conn = ahost->callback_rxcon;
599         rx_GetConnection(cb_conn);
600         H_UNLOCK;
601         code |= RXAFSCB_CallBack(cb_conn, &tf, &tc);
602         rx_PutConnection(cb_conn);
603         cb_conn = NULL;
604         H_LOCK;
605     }
606
607     return code;
608 }
609
610 /* the locked flag tells us if the host entry has already been locked 
611  * by our parent.  I don't think anybody actually calls us with the
612  * host locked, but here's how to make that work:  GetSomeSpace has to
613  * change so that it doesn't attempt to lock any hosts < "host".  That
614  * means that it might be unable to free any objects, so it has to
615  * return an exit status.  If it fails, then AddCallBack1 might fail,
616  * as well. If so, the host->ResetDone should probably be set to 0,
617  * and we probably don't want to return a callback promise to the
618  * cache manager, either. */
619 int
620 AddCallBack1(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
621              int locked)
622 {
623     int retVal;
624     H_LOCK;
625     if (!locked) {
626         h_Lock_r(host);
627     }
628     retVal = AddCallBack1_r(host, fid, thead, type, 1);
629
630     if (!locked) {
631         h_Unlock_r(host);
632     }
633     H_UNLOCK;
634     return retVal;
635 }
636
637 static int
638 AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
639                int locked)
640 {
641     struct FileEntry *fe;
642     struct CallBack *cb = 0, *lastcb = 0;
643     struct FileEntry *newfe = 0;
644     afs_uint32 time_out;
645     afs_uint32 *Thead = thead;
646     struct CallBack *newcb = 0;
647     int safety;
648
649     host->Console |= 2;
650
651     /* allocate these guys first, since we can't call the allocator with
652      * the host structure locked -- or we might deadlock. However, we have 
653      * to avoid races with FindFE... */
654     while (!(newcb = GetCB())) {
655         GetSomeSpace_r(host, locked);
656     }
657     while (!(newfe = GetFE())) {        /* Get it now, so we don't have to call */
658         /* GetSomeSpace with the host locked, later.  This might turn out to */
659         /* have been unneccessary, but that's actually kind of unlikely, since */
660         /* most files are not shared. */
661         GetSomeSpace_r(host, locked);
662     }
663
664     if (!locked) {
665         h_Lock_r(host);         /* this can yield, so do it before we get any */
666         /* fragile info */
667     }
668
669     fe = FindFE(fid);
670     if (type == CB_NORMAL) {
671         time_out =
672             TimeCeiling(FT_ApproxTime() + TimeOut(fe ? fe->ncbs : 0) +
673                         ServerBias);
674         Thead = THead(CBtime(time_out));
675     } else if (type == CB_VOLUME) {
676         time_out = TimeCeiling((60 * 120 + FT_ApproxTime()) + ServerBias);
677         Thead = THead(CBtime(time_out));
678     } else if (type == CB_BULK) {
679         /* bulk status can get so many callbacks all at once, and most of them
680          * are probably not for things that will be used for long.
681          */
682         time_out =
683             TimeCeiling(FT_ApproxTime() + ServerBias +
684                         TimeOut(22 + (fe ? fe->ncbs : 0)));
685         Thead = THead(CBtime(time_out));
686     }
687
688     host->Console &= ~2;
689
690     if (!fe) {
691         register afs_uint32 hash;
692
693         fe = newfe;
694         newfe = NULL;
695         fe->firstcb = 0;
696         fe->volid = fid->Volume;
697         fe->vnode = fid->Vnode;
698         fe->unique = fid->Unique;
699         fe->ncbs = 0;
700         fe->status = 0;
701         hash = VHash(fid->Volume, fid->Unique);
702         fe->fnext = HashTable[hash];
703         HashTable[hash] = fetoi(fe);
704     }
705     for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
706          lastcb = cb, cb = itocb(cb->cnext), safety++) {
707         if (safety > cbstuff.nblks) {
708             ViceLog(0, ("AddCallBack1: Internal Error -- shutting down.\n"));
709             DumpCallBackState();
710             ShutDownAndCore(PANIC);
711         }
712         if (cb->hhead == h_htoi(host))
713             break;
714     }
715     if (cb) {                   /* Already have call back:  move to new timeout list */
716         /* don't change delayed callbacks back to normal ones */
717         if (cb->status != CB_DELAYED)
718             cb->status = type;
719         /* Only move if new timeout is longer */
720         if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
721             TDel(cb);
722             TAdd(cb, Thead);
723         }
724         if (newfe == NULL) {    /* we are using the new FE */
725             fe->firstcb = cbtoi(cb);
726             fe->ncbs++;
727             cb->fhead = fetoi(fe);
728         }
729     } else {
730         cb = newcb;
731         newcb = NULL;
732         *(lastcb ? &lastcb->cnext : &fe->firstcb) = cbtoi(cb);
733         fe->ncbs++;
734         cb->cnext = 0;
735         cb->fhead = fetoi(fe);
736         cb->status = type;
737         HAdd(cb, host);
738         TAdd(cb, Thead);
739     }
740
741     /* now free any still-unused callback or host entries */
742     if (newcb)
743         FreeCB(newcb);
744     if (newfe)
745         FreeFE(newfe);
746
747     if (!locked)                /* freecb and freefe might(?) yield */
748         h_Unlock_r(host);
749
750     if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK)
751         return time_out - ServerBias;   /* Expires sooner at workstation */
752
753     return 0;
754 }
755
756 /* Take an array full of hosts, all held.  Break callbacks to them, and 
757  * release the holds once you're done, except don't release xhost.  xhost 
758  * may be NULL.  Currently only works for a single Fid in afidp array.
759  * If you want to make this work with multiple fids, you need to fix
760  * the error handling.  One approach would be to force a reset if a
761  * multi-fid call fails, or you could add delayed callbacks for each
762  * fid.   You probably also need to sort and remove duplicate hosts.
763  * When this is called from the BreakVolumeCallBacks path, it does NOT 
764  * force a reset if the RPC fails, it just marks the host down and tries 
765  * to create a delayed callback. */
766 /* N.B.  be sure that code works when ncbas == 0 */
767 /* N.B.  requires all the cba[*].hp pointers to be valid... */
768 /* This routine does not hold a lock on the host for the duration of 
769  * the BreakCallBack RPC, which is a significant deviation from tradition.
770  * It _does_ get a lock on the host before setting VenusDown = 1,
771  * which is sufficient only if VenusDown = 0 only happens when the
772  * lock is held over the RPC and the subsequent VenusDown == 0
773  * wherever that is done. */
774 static void
775 MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
776                      struct AFSCBFids *afidp, struct host *xhost)
777 {
778     int i, j;
779     struct rx_connection *conns[MAX_CB_HOSTS];
780     static struct AFSCBs tc = { 0, 0 };
781     int multi_to_cba_map[MAX_CB_HOSTS];
782
783     assert(ncbas <= MAX_CB_HOSTS);
784
785     /* set up conns for multi-call */
786     for (i = 0, j = 0; i < ncbas; i++) {
787         struct host *thishost = cba[i].hp;
788         if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
789             continue;
790         }
791         rx_GetConnection(thishost->callback_rxcon);
792         multi_to_cba_map[j] = i;
793         conns[j++] = thishost->callback_rxcon;
794
795 #ifdef  ADAPT_MTU
796         rx_SetConnDeadTime(thishost->callback_rxcon, 4);
797         rx_SetConnHardDeadTime(thishost->callback_rxcon, AFS_HARDDEADTIME);
798 #endif
799     }
800
801     if (j) {                    /* who knows what multi would do with 0 conns? */
802         cbstuff.nbreakers++;
803         H_UNLOCK;
804         multi_Rx(conns, j) {
805             multi_RXAFSCB_CallBack(afidp, &tc);
806             if (multi_error) {
807                 afs_uint32 idx;
808                 struct host *hp;
809                 char hoststr[16];
810
811                 i = multi_to_cba_map[multi_i];
812                 hp = cba[i].hp;
813                 idx = cba[i].thead;
814
815                 if (!hp || !idx) {
816                     ViceLog(0,
817                             ("BCB: INTERNAL ERROR: hp=%x, cba=%x, thead=%u\n", 
818                              hp, cba, idx));
819                 } else {
820                     /* 
821                      ** try breaking callbacks on alternate interface addresses
822                      */
823                     if (MultiBreakCallBackAlternateAddress(hp, afidp)) {
824                         if (ShowProblems) {
825                             ViceLog(7,
826                                     ("BCB: Failed on file %u.%u.%u, Host %s:%d is down\n",
827                                      afidp->AFSCBFids_val->Volume,
828                                      afidp->AFSCBFids_val->Vnode,
829                                      afidp->AFSCBFids_val->Unique,
830                                      afs_inet_ntoa_r(hp->host, hoststr),
831                                      ntohs(hp->port)));
832                         }
833
834                         H_LOCK;
835                         h_Lock_r(hp); 
836                         hp->hostFlags |= VENUSDOWN;
837                 /**
838                   * We always go into AddCallBack1_r with the host locked
839                   */
840                         AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
841                                        CB_DELAYED, 1);
842                         h_Unlock_r(hp); 
843                         H_UNLOCK;
844                     }
845                 }
846             }
847         }
848         multi_End;
849         H_LOCK;
850         cbstuff.nbreakers--;
851     }
852
853     for (i = 0; i < ncbas; i++) {
854         struct host *hp;
855         hp = cba[i].hp;
856         if (hp && xhost != hp) {
857             h_Release_r(hp);
858         }
859     }
860
861     /* H_UNLOCK around this so h_FreeConnection does not deadlock.
862        h_FreeConnection should *never* be called on a callback connection,
863        but on 10/27/04 a deadlock occurred where it was, when we know why,
864        this should be reverted. -- shadow */
865     H_UNLOCK;
866     for (i = 0; i < j; i++) {
867         rx_PutConnection(conns[i]);
868     }
869     H_LOCK;
870
871     return;
872 }
873
874 /*
875  * Break all call backs for fid, except for the specified host (unless flag
876  * is true, in which case all get a callback message. Assumption: the specified
877  * host is h_Held, by the caller; the others aren't.
878  * Specified host may be bogus, that's ok.  This used to check to see if the 
879  * host was down in two places, once right after the host was h_held, and 
880  * again after it was locked.  That race condition is incredibly rare and
881  * relatively harmless even when it does occur, so we don't check for it now. 
882  */
883 /* if flag is true, send a break callback msg to "host", too */
884 int
885 BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
886 {
887     struct FileEntry *fe;
888     struct CallBack *cb, *nextcb;
889     struct cbstruct cba[MAX_CB_HOSTS];
890     int ncbas;
891     struct AFSCBFids tf;
892     int hostindex;
893     char hoststr[16];
894
895     ViceLog(7,
896             ("BCB: BreakCallBack(all but %s:%d, (%u,%u,%u))\n",
897              afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
898              fid->Volume, fid->Vnode, fid->Unique));
899
900     H_LOCK;
901     cbstuff.BreakCallBacks++;
902     fe = FindFE(fid);
903     if (!fe) {
904         goto done;
905     }
906     hostindex = h_htoi(xhost);
907     cb = itocb(fe->firstcb);
908     if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
909         /* the most common case is what follows the || */
910         goto done;
911     }
912     tf.AFSCBFids_len = 1;
913     tf.AFSCBFids_val = fid;
914
915     for (; cb;) {
916         for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
917             nextcb = itocb(cb->cnext);
918             if ((cb->hhead != hostindex || flag)
919                 && (cb->status == CB_BULK || cb->status == CB_NORMAL
920                     || cb->status == CB_VOLUME)) {
921                 struct host *thishost = h_itoh(cb->hhead);
922                 if (!thishost) {
923                     ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
924                 } else if (thishost->hostFlags & VENUSDOWN) {
925                     ViceLog(7,
926                             ("BCB: %s:%d is down; delaying break call back\n",
927                              afs_inet_ntoa_r(thishost->host, hoststr),
928                              ntohs(thishost->port)));
929                     cb->status = CB_DELAYED;
930                 } else {
931                     h_Hold_r(thishost);
932                     cba[ncbas].hp = thishost;
933                     cba[ncbas].thead = cb->thead;
934                     ncbas++;
935                     TDel(cb);
936                     HDel(cb);
937                     CDel(cb, 1);        /* Usually first; so this delete 
938                                          * is reasonably inexpensive */
939                 }
940             }
941         }
942
943         if (ncbas) {
944             MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
945
946             /* we need to to all these initializations again because MultiBreakCallBack may block */
947             fe = FindFE(fid);
948             if (!fe) {
949                 goto done;
950             }
951             cb = itocb(fe->firstcb);
952             if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
953                 /* the most common case is what follows the || */
954                 goto done;
955             }
956         }
957     }
958
959   done:
960     H_UNLOCK;
961     return 0;
962 }
963
964 /* Delete (do not break) single call back for fid */
965 int
966 DeleteCallBack(struct host *host, AFSFid * fid)
967 {
968     register struct FileEntry *fe;
969     register afs_uint32 *pcb;
970     char hoststr[16];
971
972     cbstuff.DeleteCallBacks++;
973
974     H_LOCK;
975     h_Lock_r(host);
976     fe = FindFE(fid);
977     if (!fe) {
978         h_Unlock_r(host);
979         H_UNLOCK;
980         ViceLog(8,
981                 ("DCB: No call backs for fid (%u, %u, %u)\n", fid->Volume,
982                  fid->Vnode, fid->Unique));
983         return 0;
984     }
985     pcb = FindCBPtr(fe, host);
986     if (!*pcb) {
987         ViceLog(8,
988                 ("DCB: No call back for host %s:%d, (%u, %u, %u)\n",
989                  afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
990                  fid->Volume, fid->Vnode, fid->Unique));
991         h_Unlock_r(host);
992         H_UNLOCK;
993         return 0;
994     }
995     HDel(itocb(*pcb));
996     TDel(itocb(*pcb));
997     CDelPtr(fe, pcb, 1);
998     h_Unlock_r(host);
999     H_UNLOCK;
1000     return 0;
1001 }
1002
1003 /*
1004  * Delete (do not break) all call backs for fid.  This call doesn't
1005  * set all of the various host locks, but it shouldn't really matter
1006  * since we're not adding callbacks, but deleting them.  I'm not sure
1007  * why it doesn't set the lock, however; perhaps it should.
1008  */
1009 int
1010 DeleteFileCallBacks(AFSFid * fid)
1011 {
1012     register struct FileEntry *fe;
1013     register struct CallBack *cb;
1014     register afs_uint32 cbi;
1015     register int n;
1016
1017     H_LOCK;
1018     cbstuff.DeleteFiles++;
1019     fe = FindFE(fid);
1020     if (!fe) {
1021         H_UNLOCK;
1022         ViceLog(8,
1023                 ("DF: No fid (%u,%u,%u) to delete\n", fid->Volume, fid->Vnode,
1024                  fid->Unique));
1025         return 0;
1026     }
1027     for (n = 0, cbi = fe->firstcb; cbi; n++) {
1028         cb = itocb(cbi);
1029         cbi = cb->cnext;
1030         TDel(cb);
1031         HDel(cb);
1032         FreeCB(cb);
1033     }
1034     FDel(fe);
1035     H_UNLOCK;
1036     return 0;
1037 }
1038
1039 /* Delete (do not break) all call backs for host.  The host should be
1040  * locked. */
1041 int
1042 DeleteAllCallBacks_r(struct host *host, int deletefe)
1043 {
1044     register struct CallBack *cb;
1045     register int cbi, first;
1046
1047     cbstuff.DeleteAllCallBacks++;
1048     cbi = first = host->cblist;
1049     if (!cbi) {
1050         ViceLog(8, ("DV: no call backs\n"));
1051         return 0;
1052     }
1053     do {
1054         cb = itocb(cbi);
1055         cbi = cb->hnext;
1056         TDel(cb);
1057         CDel(cb, deletefe);
1058     } while (cbi != first);
1059     host->cblist = 0;
1060     return 0;
1061 }
1062
1063 /*
1064  * Break all delayed call backs for host.  Returns 1 if all call backs
1065  * successfully broken; 0 otherwise.  Assumes host is h_Held and h_Locked.
1066  * Must be called with VenusDown set for this host
1067  */
1068 int
1069 BreakDelayedCallBacks(struct host *host)
1070 {
1071     int retVal;
1072     H_LOCK;
1073     retVal = BreakDelayedCallBacks_r(host);
1074     H_UNLOCK;
1075     return retVal;
1076 }
1077
1078 int
1079 BreakDelayedCallBacks_r(struct host *host)
1080 {
1081     struct AFSFid fids[AFSCBMAX];
1082     u_byte thead[AFSCBMAX];     /* This should match thead in struct Callback */
1083     int cbi, first, nfids;
1084     struct CallBack *cb;
1085     int code;
1086     char hoststr[16];
1087     struct rx_connection *cb_conn;
1088
1089     cbstuff.nbreakers++;
1090     if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1091         host->hostFlags &= ~ALTADDR;    /* alternate addresses are invalid */
1092         cb_conn = host->callback_rxcon;
1093         rx_GetConnection(cb_conn);
1094         if (host->interface) {
1095             H_UNLOCK;
1096             code =
1097                 RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
1098         } else {
1099             H_UNLOCK;
1100             code = RXAFSCB_InitCallBackState(cb_conn);
1101         }
1102         rx_PutConnection(cb_conn);
1103         cb_conn = NULL;
1104         H_LOCK;
1105         host->hostFlags |= ALTADDR;     /* alternate addresses are valid */
1106         if (code) {
1107             if (ShowProblems) {
1108                 ViceLog(0,
1109                         ("CB: Call back connect back failed (in break delayed) for Host %s:%d\n",
1110                          afs_inet_ntoa_r(host->host, hoststr),
1111                          ntohs(host->port)));
1112             }
1113             host->hostFlags |= VENUSDOWN;
1114         } else {
1115             ViceLog(25,
1116                     ("InitCallBackState success on %s\n",
1117                      afs_inet_ntoa_r(host->host, hoststr)));
1118             /* reset was done successfully */
1119             host->hostFlags |= RESETDONE;
1120             host->hostFlags &= ~VENUSDOWN;
1121         }
1122     } else
1123         while (!(host->hostFlags & HOSTDELETED)) {
1124             nfids = 0;
1125             host->hostFlags &= ~VENUSDOWN;      /* presume up */
1126             cbi = first = host->cblist;
1127             if (!cbi)
1128                 break;
1129             do {
1130                 first = host->cblist;
1131                 cb = itocb(cbi);
1132                 cbi = cb->hnext;
1133                 if (cb->status == CB_DELAYED) {
1134                     register struct FileEntry *fe = itofe(cb->fhead);
1135                     thead[nfids] = cb->thead;
1136                     fids[nfids].Volume = fe->volid;
1137                     fids[nfids].Vnode = fe->vnode;
1138                     fids[nfids].Unique = fe->unique;
1139                     nfids++;
1140                     HDel(cb);
1141                     TDel(cb);
1142                     CDel(cb, 1);
1143                 }
1144             } while (cbi && cbi != first && nfids < AFSCBMAX);
1145
1146             if (nfids == 0) {
1147                 break;
1148             }
1149
1150             if (XCallBackBulk_r(host, fids, nfids)) {
1151                 /* Failed, again:  put them back, probably with old
1152                  * timeout values */
1153                 int i;
1154                 if (ShowProblems) {
1155                     ViceLog(0,
1156                             ("CB: XCallBackBulk failed, Host %s:%d; callback list follows:\n",
1157                              afs_inet_ntoa_r(host->host, hoststr),
1158                              ntohs(host->port)));
1159                 }
1160                 for (i = 0; i < nfids; i++) {
1161                     if (ShowProblems) {
1162                         ViceLog(0,
1163                                 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1164                                  afs_inet_ntoa_r(host->host, hoststr),
1165                                  ntohs(host->port), fids[i].Volume,
1166                                  fids[i].Vnode, fids[i].Unique));
1167                     }
1168                     /* used to do this:
1169                      * AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1170                      * * but it turns out to cause too many tricky locking problems.
1171                      * * now, if break delayed fails, screw it. */
1172                 }
1173                 host->hostFlags |= VENUSDOWN;   /* Failed */
1174                 ClearHostCallbacks_r(host, 1 /* locked */ );
1175                 nfids = 0;
1176                 break;
1177             }
1178             if (nfids < AFSCBMAX)
1179                 break;
1180         }
1181
1182     cbstuff.nbreakers--;
1183     /* If we succeeded it's always ok to unset HFE_LATER */
1184     if (!host->hostFlags & VENUSDOWN)
1185         host->hostFlags &= ~HFE_LATER;
1186     return (host->hostFlags & VENUSDOWN);
1187 }
1188
1189 /*
1190 ** isheld is 0 if the host is held in h_Enumerate
1191 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1192 */
1193 static int
1194 MultiBreakVolumeCallBack_r(struct host *host, int isheld,
1195                            struct VCBParams *parms, int deletefe)
1196 {
1197     char hoststr[16];
1198
1199     if (!isheld)
1200         return isheld;          /* host is held only by h_Enumerate, do nothing */
1201     if (host->hostFlags & HOSTDELETED)
1202         return 0;               /* host is deleted, release hold */
1203
1204     if (host->hostFlags & VENUSDOWN) {
1205         h_Lock_r(host);
1206         if (host->hostFlags & HOSTDELETED) {
1207             h_Unlock_r(host);
1208             return 0;           /* Release hold */
1209         }
1210         ViceLog(8,
1211                 ("BVCB: volume call back for Host %s:%d failed\n",
1212                  afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1213         if (ShowProblems) {
1214             ViceLog(0,
1215                     ("CB: volume callback for Host %s:%d failed\n",
1216                      afs_inet_ntoa_r(host->host, hoststr),
1217                      ntohs(host->port)));
1218         }
1219         DeleteAllCallBacks_r(host, deletefe);   /* Delete all callback state 
1220                                                  * rather than attempting to 
1221                                                  * selectively remember to
1222                                                  * delete the volume callbacks
1223                                                  * later */
1224         host->hostFlags &= ~RESETDONE;  /* Do InitCallBackState when host returns */
1225         h_Unlock_r(host);
1226         return 0;               /* release hold */
1227     }
1228     assert(parms->ncbas <= MAX_CB_HOSTS);
1229
1230     /* Do not call MultiBreakCallBack on the current host structure
1231      ** because it would prematurely release the hold on the host
1232      */
1233     if (parms->ncbas == MAX_CB_HOSTS) {
1234         struct AFSCBFids tf;
1235
1236         tf.AFSCBFids_len = 1;
1237         tf.AFSCBFids_val = parms->fid;
1238
1239         /* this releases all the hosts */
1240         MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */ );
1241
1242         parms->ncbas = 0;
1243     }
1244     parms->cba[parms->ncbas].hp = host;
1245     parms->cba[(parms->ncbas)++].thead = parms->thead;
1246     return 1;                   /* DON'T release hold, because we still need it. */
1247 }
1248
1249 /*
1250 ** isheld is 0 if the host is held in h_Enumerate
1251 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1252 */
1253 static int
1254 MultiBreakVolumeCallBack(struct host *host, int isheld,
1255                          struct VCBParams *parms)
1256 {
1257     int retval;
1258     H_LOCK;
1259     retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1260     H_UNLOCK;
1261     return retval;
1262 }
1263
1264 /*
1265 ** isheld is 0 if the host is held in h_Enumerate
1266 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1267 */
1268 static int
1269 MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1270                               struct VCBParams *parms)
1271 {
1272     int retval;
1273     H_LOCK;
1274     retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1275     H_UNLOCK;
1276     return retval;
1277 }
1278
1279 /*
1280  * Break all call backs on a single volume.  Don't call this with any
1281  * hosts h_held.  Note that this routine clears the callbacks before
1282  * actually breaking them, and that the vnode isn't locked during this
1283  * operation, so that people might see temporary callback loss while
1284  * this function is executing.  It is just a temporary state, however,
1285  * since the callback will be broken later by this same function.
1286  *
1287  * Now uses multi-RX for CallBack RPC.  Note that the
1288  * multiBreakCallBacks routine does not force a reset if the RPC
1289  * fails, unlike the previous version of this routine, but does create
1290  * a delayed callback.  Resets will be forced if the host is
1291  * determined to be down before the RPC is executed.
1292  */
1293 int
1294 BreakVolumeCallBacks(afs_uint32 volume)
1295 {
1296     struct AFSFid fid;
1297     int hash;
1298     afs_uint32 *feip;
1299     struct CallBack *cb;
1300     struct FileEntry *fe;
1301     struct host *host;
1302     struct VCBParams henumParms;
1303     afs_uint32 tthead = 0;      /* zero is illegal value */
1304
1305     H_LOCK;
1306     fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1307     for (hash = 0; hash < VHASH; hash++) {
1308         for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
1309             if (fe->volid == volume) {
1310                 register struct CallBack *cbnext;
1311                 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1312                     host = h_itoh(cb->hhead);
1313                     h_Hold_r(host);
1314                     cbnext = itocb(cb->cnext);
1315                     if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1316                         tthead = cb->thead;
1317                     }
1318                     TDel(cb);
1319                     HDel(cb);
1320                     FreeCB(cb);
1321                     /* leave hold for MultiBreakVolumeCallBack to clear */
1322                 }
1323                 *feip = fe->fnext;
1324                 FreeFE(fe);
1325             } else {
1326                 feip = &fe->fnext;
1327             }
1328         }
1329     }
1330
1331     if (!tthead) {
1332         /* didn't find any callbacks, so return right away. */
1333         H_UNLOCK;
1334         return 0;
1335     }
1336     henumParms.ncbas = 0;
1337     henumParms.fid = &fid;
1338     henumParms.thead = tthead;
1339     H_UNLOCK;
1340     h_Enumerate(MultiBreakVolumeCallBack, (char *)&henumParms);
1341     H_LOCK;
1342     if (henumParms.ncbas) {     /* do left-overs */
1343         struct AFSCBFids tf;
1344         tf.AFSCBFids_len = 1;
1345         tf.AFSCBFids_val = &fid;
1346
1347         MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1348
1349         henumParms.ncbas = 0;
1350     }
1351     H_UNLOCK;
1352     return 0;
1353 }
1354
1355 #ifdef AFS_PTHREAD_ENV
1356 extern pthread_cond_t fsync_cond;
1357 #else
1358 extern char fsync_wait[];
1359 #endif
1360
1361 int
1362 BreakVolumeCallBacksLater(afs_uint32 volume)
1363 {
1364     int hash;
1365     afs_int32 *feip;
1366     struct FileEntry *fe;
1367     struct CallBack *cb;
1368     struct host *host;
1369     int found = 0;
1370
1371     ViceLog(25, ("Setting later on volume %u\n", volume));
1372     H_LOCK;
1373     for (hash = 0; hash < VHASH; hash++) {
1374         for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1375             if (fe->volid == volume) {
1376                 register struct CallBack *cbnext;
1377                 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1378                     host = h_itoh(cb->hhead);
1379                     host->hostFlags |= HFE_LATER;
1380                     cb->status = CB_DELAYED;
1381                     cbnext = itocb(cb->cnext);
1382                 }
1383                 FSYNC_LOCK;
1384                 fe->status |= FE_LATER;
1385                 FSYNC_UNLOCK;
1386                 found++;
1387             }
1388             feip = &fe->fnext;
1389         }
1390     }
1391     H_UNLOCK;
1392     if (!found) {
1393         /* didn't find any callbacks, so return right away. */
1394         return 0;
1395     }
1396
1397     ViceLog(25, ("Fsync thread wakeup\n"));
1398 #ifdef AFS_PTHREAD_ENV
1399     FSYNC_LOCK;
1400     assert(pthread_cond_broadcast(&fsync_cond) == 0);
1401     FSYNC_UNLOCK;
1402 #else
1403     LWP_NoYieldSignal(fsync_wait);
1404 #endif
1405     return 0;
1406 }
1407
1408 int
1409 BreakLaterCallBacks(void)
1410 {
1411     struct AFSFid fid;
1412     int hash;
1413     afs_int32 *feip;
1414     struct CallBack *cb;
1415     struct FileEntry *fe = NULL;
1416     struct FileEntry *myfe = NULL;
1417     struct host *host;
1418     struct VCBParams henumParms;
1419     unsigned short tthead = 0;  /* zero is illegal value */
1420     char hoststr[16];
1421
1422     /* Unchain first */
1423     ViceLog(25, ("Looking for FileEntries to unchain\n"));
1424     H_LOCK;
1425     FSYNC_LOCK;
1426     /* Pick the first volume we see to clean up */
1427     fid.Volume = fid.Vnode = fid.Unique = 0;
1428
1429     for (hash = 0; hash < VHASH; hash++) {
1430         for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1431             if (fe && (fe->status & FE_LATER)
1432                 && (fid.Volume == 0 || fid.Volume == fe->volid)) {
1433                 /* Ugly, but used to avoid left side casting */
1434                 struct object *tmpfe;
1435                 ViceLog(125,
1436                         ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
1437                          fe->volid));
1438                 fid.Volume = fe->volid;
1439                 *feip = fe->fnext;
1440                 /* Works since volid is deeper than the largest pointer */
1441                 tmpfe = (struct object *)fe;
1442                 tmpfe->next = (struct object *)myfe;
1443                 myfe = fe;
1444             } else
1445                 feip = &fe->fnext;
1446         }
1447     }
1448     FSYNC_UNLOCK;
1449
1450     if (!myfe) {
1451         H_UNLOCK;
1452         return 0;
1453     }
1454
1455     /* loop over FEs from myfe and free/break */
1456     tthead = 0;
1457     for (fe = myfe; fe;) {
1458         register struct CallBack *cbnext;
1459         for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1460             cbnext = itocb(cb->cnext);
1461             host = h_itoh(cb->hhead);
1462             if (cb->status == CB_DELAYED) {
1463                 h_Hold_r(host);
1464                 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1465                     tthead = cb->thead;
1466                 }
1467                 TDel(cb);
1468                 HDel(cb);
1469                 CDel(cb, 0);    /* Don't let CDel clean up the fe */
1470                 /* leave hold for MultiBreakVolumeCallBack to clear */
1471             } else {
1472                 ViceLog(125,
1473                         ("Found host %s:%d non-DELAYED cb for %u:%u:%u\n", 
1474                          afs_inet_ntoa_r(host->host, hoststr),
1475                          ntohs(host->port), fe->vnode, fe->unique, fe->volid));
1476             }
1477         }
1478         myfe = fe;
1479         fe = (struct FileEntry *)((struct object *)fe)->next;
1480         FreeFE(myfe);
1481     }
1482
1483     if (tthead) {
1484         ViceLog(125, ("Breaking volume %u\n", fid.Volume));
1485         henumParms.ncbas = 0;
1486         henumParms.fid = &fid;
1487         henumParms.thead = tthead;
1488         H_UNLOCK;
1489         h_Enumerate(MultiBreakVolumeLaterCallBack, (char *)&henumParms);
1490         H_LOCK;
1491         if (henumParms.ncbas) { /* do left-overs */
1492             struct AFSCBFids tf;
1493             tf.AFSCBFids_len = 1;
1494             tf.AFSCBFids_val = &fid;
1495
1496             MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1497             henumParms.ncbas = 0;
1498         }
1499     }
1500     H_UNLOCK;
1501
1502     /* Arrange to be called again */
1503     return 1;
1504 }
1505
1506 /*
1507  * Delete all timed-out call back entries (to be called periodically by file
1508  * server)
1509  */
1510 int
1511 CleanupTimedOutCallBacks(void)
1512 {
1513     H_LOCK;
1514     CleanupTimedOutCallBacks_r();
1515     H_UNLOCK;
1516     return 0;
1517 }
1518
1519 int
1520 CleanupTimedOutCallBacks_r(void)
1521 {
1522     afs_uint32 now = CBtime(FT_ApproxTime());
1523     register afs_uint32 *thead;
1524     register struct CallBack *cb;
1525     register int ntimedout = 0;
1526     char hoststr[16];
1527
1528     while (tfirst <= now) {
1529         register int cbi;
1530         cbi = *(thead = THead(tfirst));
1531         if (cbi) {
1532             do {
1533                 cb = itocb(cbi);
1534                 cbi = cb->tnext;
1535                 ViceLog(8,
1536                         ("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1537                          afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
1538                          h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
1539                          itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
1540                 HDel(cb);
1541                 CDel(cb, 1);
1542                 ntimedout++;
1543                 if (ntimedout > cbstuff.nblks) {
1544                     ViceLog(0, ("CCB: Internal Error -- shutting down...\n"));
1545                     DumpCallBackState();
1546                     ShutDownAndCore(PANIC);
1547                 }
1548             } while (cbi != *thead);
1549             *thead = 0;
1550         }
1551         tfirst++;
1552     }
1553     cbstuff.CBsTimedOut += ntimedout;
1554     ViceLog(7, ("CCB: deleted %d timed out callbacks\n", ntimedout));
1555     return (ntimedout > 0);
1556 }
1557
1558 static struct host *lih_host;
1559 static int lih_host_held;
1560
1561 static int
1562 lih_r(register struct host *host, register int held,
1563       register struct host *hostp)
1564 {
1565     if (host->cblist
1566         && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1567         && (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
1568         if (lih_host != NULL && lih_host_held) {
1569             h_Release_r(lih_host);
1570         }
1571         lih_host = host;
1572         lih_host_held = !held;
1573         held = 1;
1574     }
1575     return held;
1576 }
1577
1578 /* This version does not allow 'host' to be selected unless its ActiveCall 
1579  * is newer than 'hostp' which is the host with the oldest ActiveCall from
1580  * the last pass (if it is provided).  We filter out any hosts that are
1581  * are held by other threads.
1582  */
1583 static int
1584 lih0_r(register struct host *host, register int held,
1585       register struct host *hostp)
1586 {
1587     if (host->cblist
1588         && (hostp && host != hostp) 
1589         && (!held && !h_OtherHolds_r(host))
1590         && (!lih_host || host->ActiveCall < lih_host->ActiveCall) 
1591         && (!hostp || host->ActiveCall > hostp->ActiveCall)) {
1592         if (lih_host != NULL && lih_host_held) {
1593             h_Release_r(lih_host);
1594         }
1595         lih_host = host;
1596         lih_host_held = !held;
1597         held = 1;
1598     }
1599     return held;
1600 }
1601
1602 /* This version does not allow 'host' to be selected unless its ActiveCall 
1603  * is newer than 'hostp' which is the host with the oldest ActiveCall from
1604  * the last pass (if it is provided).  In this second varient, we do not 
1605  * prevent held hosts from being selected.
1606  */
1607 static int
1608 lih1_r(register struct host *host, register int held,
1609       register struct host *hostp)
1610 {
1611     if (host->cblist
1612         && (hostp && host != hostp) 
1613         && (!lih_host || host->ActiveCall < lih_host->ActiveCall) 
1614         && (!hostp || host->ActiveCall > hostp->ActiveCall)) {
1615         if (lih_host != NULL && lih_host_held) {
1616             h_Release_r(lih_host);
1617         }
1618         lih_host = host;
1619         lih_host_held = !held;
1620         held = 1;
1621     }
1622     return held;
1623 }
1624
1625 /* This could be upgraded to get more space each time */
1626 /* first pass: sequentially find the oldest host which isn't held by
1627                anyone for which we can clear callbacks;
1628                skipping 'hostp' */
1629 /* second pass: sequentially find the oldest host regardless of 
1630                whether or not the host is held; skipping 'hostp' */
1631 /* third pass: attempt to clear callbacks from 'hostp' */
1632 /* always called with hostp unlocked */
1633
1634 /* Note: hostlist is ordered most recently created host first and 
1635  * its order has no relationship to the most recently used. */
1636 extern struct host *hostList;
1637 static int
1638 GetSomeSpace_r(struct host *hostp, int locked)
1639 {
1640     register struct host *hp, *hp1, *hp2;
1641     int i = 0;
1642
1643     cbstuff.GotSomeSpaces++;
1644     ViceLog(5,
1645             ("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1646     if (CleanupTimedOutCallBacks_r()) {
1647         cbstuff.GSS3++;
1648         return 0;
1649     }
1650
1651     i = 0;
1652     hp1 = NULL;
1653     hp2 = hostList;
1654     do {
1655         lih_host = 0;
1656         h_Enumerate_r(i == 0 ? lih0_r : lih1_r, hp2, (char *)hp1);
1657         hp = lih_host;
1658         if (hp) {
1659             /* set in lih_r! private copy before giving up H_LOCK */
1660             int lih_host_held2=lih_host_held;   
1661             cbstuff.GSS4++;
1662             if ((hp != hostp) && !ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
1663                 if (lih_host_held2)
1664                     h_Release_r(hp);
1665                 return 0;
1666             }
1667             if (lih_host_held2)
1668                 h_Release_r(hp);
1669             hp1 = hp;
1670             hp2 = hostList;
1671         } else {
1672             /*
1673              * Next time try getting callbacks from any host even if
1674              * it's deleted (that's actually great since we can freely
1675              * remove its callbacks) or it's held since the only other
1676              * option is starvation for the file server (i.e. until the
1677              * callback timeout arrives).
1678              */
1679             i++;
1680             hp1 = NULL;
1681             hp2 = hostList;
1682             cbstuff.GSS1++;
1683             ViceLog(5,
1684                     ("GSS: Try harder for longest inactive host cnt= %d\n",
1685                      i));
1686         }
1687     } while (i < 2);
1688
1689     /* Could not obtain space from other hosts, clear hostp's callback state */
1690     cbstuff.GSS2++;
1691     if (!locked) {
1692         h_Lock_r(hostp);
1693     }
1694     ClearHostCallbacks_r(hostp, 1 /*already locked */ );
1695     if (!locked) {
1696         h_Unlock_r(hostp);
1697     }
1698     return 0;
1699 }
1700
1701 /* locked - set if caller has already locked the host */
1702 static int
1703 ClearHostCallbacks_r(struct host *hp, int locked)
1704 {
1705     int code;
1706     int held = 0;
1707     char hoststr[16];
1708     struct rx_connection *cb_conn = NULL;
1709
1710     ViceLog(5,
1711             ("GSS: Delete longest inactive host %s\n",
1712              afs_inet_ntoa_r(hp->host, hoststr)));
1713     if (!(held = h_Held_r(hp)))
1714         h_Hold_r(hp);
1715
1716     /** Try a non-blocking lock. If the lock is already held return
1717       * after releasing hold on hp
1718       */
1719     if (!locked) {
1720         if (h_NBLock_r(hp)) {
1721             if (!held)
1722                 h_Release_r(hp);
1723             return 1;
1724         }
1725     }
1726     if (hp->Console & 2) {
1727         /*
1728          * If the special console field is set it means that a thread
1729          * is waiting in AddCallBack1 after it set pointers to the
1730          * file entry and/or callback entry. Because of the bogus
1731          * usage of h_hold it won't prevent from another thread, this
1732          * one, to remove all the callbacks so just to be safe we keep
1733          * a reference. NOTE, on the last phase we'll free the calling
1734          * host's callbacks but that's ok...
1735          */
1736         cbstuff.GSS5++;
1737     }
1738     DeleteAllCallBacks_r(hp, 1);
1739     if (hp->hostFlags & VENUSDOWN) {
1740         hp->hostFlags &= ~RESETDONE;    /* remember that we must do a reset */
1741     } else {
1742         /* host is up, try a call */
1743         hp->hostFlags &= ~ALTADDR;      /* alternate addresses are invalid */
1744         cb_conn = hp->callback_rxcon;
1745         rx_GetConnection(hp->callback_rxcon);
1746         if (hp->interface) {
1747             H_UNLOCK;
1748             code =
1749                 RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
1750         } else {
1751             H_UNLOCK;
1752             code = RXAFSCB_InitCallBackState(cb_conn);
1753         }
1754         rx_PutConnection(cb_conn);
1755         cb_conn = NULL;
1756         H_LOCK;
1757         hp->hostFlags |= ALTADDR;       /* alternate addresses are valid */
1758         if (code) {
1759             /* failed, mark host down and need reset */
1760             hp->hostFlags |= VENUSDOWN;
1761             hp->hostFlags &= ~RESETDONE;
1762         } else {
1763             /* reset succeeded, we're done */
1764             hp->hostFlags |= RESETDONE;
1765         }
1766     }
1767     if (!locked) {
1768         h_Unlock_r(hp);
1769     }
1770     if (!held)
1771         h_Release_r(hp);
1772
1773     return 0;
1774 }
1775 #endif /* INTERPRET_DUMP */
1776
1777
1778 int
1779 PrintCallBackStats(void)
1780 {
1781     fprintf(stderr,
1782             "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1783             cbstuff.AddCallBacks, cbstuff.BreakCallBacks,
1784             cbstuff.DeleteCallBacks, cbstuff.DeleteFiles, cbstuff.CBsTimedOut,
1785             cbstuff.GotSomeSpaces, cbstuff.DeleteAllCallBacks);
1786     fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1787             cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs + cbstuff.nFEs,
1788             cbstuff.nblks);
1789
1790     return 0;
1791 }
1792
1793 #define MAGIC 0x12345678        /* To check byte ordering of dump when it is read in */
1794
1795 #ifndef INTERPRET_DUMP
1796
1797 int
1798 DumpCallBackState(void)
1799 {
1800     int fd;
1801     afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1802
1803     fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY | O_CREAT | O_TRUNC,
1804               0666);
1805     if (fd < 0) {
1806         ViceLog(0,
1807                 ("Couldn't create callback dump file %s\n",
1808                  AFSDIR_SERVER_CBKDUMP_FILEPATH));
1809         return 0;
1810     }
1811     (void)write(fd, &magic, sizeof(magic));
1812     (void)write(fd, &now, sizeof(now));
1813     (void)write(fd, &cbstuff, sizeof(cbstuff));
1814     (void)write(fd, TimeOuts, sizeof(TimeOuts));
1815     (void)write(fd, timeout, sizeof(timeout));
1816     (void)write(fd, &tfirst, sizeof(tfirst));
1817     freelisthead = cbtoi((struct CallBack *)CBfree);
1818     (void)write(fd, &freelisthead, sizeof(freelisthead));       /* This is a pointer */
1819     freelisthead = fetoi((struct FileEntry *)FEfree);
1820     (void)write(fd, &freelisthead, sizeof(freelisthead));       /* This is a pointer */
1821     (void)write(fd, HashTable, sizeof(HashTable));
1822     (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks);     /* CB stuff */
1823     (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks);     /* FE stuff */
1824     close(fd);
1825
1826     return 0;
1827 }
1828
1829 #endif
1830
1831 #ifdef INTERPRET_DUMP
1832
1833 /* This is only compiled in for the callback analyzer program */
1834 /* Returns the time of the dump */
1835 time_t
1836 ReadDump(char *file)
1837 {
1838     int fd;
1839     afs_uint32 magic, freelisthead;
1840     time_t now;
1841
1842     fd = open(file, O_RDONLY);
1843     if (fd < 0) {
1844         fprintf(stderr, "Couldn't read dump file %s\n", file);
1845         exit(1);
1846     }
1847     read(fd, &magic, sizeof(magic));
1848     if (magic != MAGIC) {
1849         fprintf(stderr,
1850                 "Magic number of %s is invalid.  You might be trying to\n",
1851                 file);
1852         fprintf(stderr,
1853                 "run this program on a machine type with a different byte ordering.\n");
1854         exit(1);
1855     }
1856     read(fd, &now, sizeof(now));
1857     read(fd, &cbstuff, sizeof(cbstuff));
1858     read(fd, TimeOuts, sizeof(TimeOuts));
1859     read(fd, timeout, sizeof(timeout));
1860     read(fd, &tfirst, sizeof(tfirst));
1861     read(fd, &freelisthead, sizeof(freelisthead));
1862     CB = ((struct CallBack
1863            *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1864     FE = ((struct FileEntry
1865            *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1866     CBfree = (struct CallBack *)itocb(freelisthead);
1867     read(fd, &freelisthead, sizeof(freelisthead));
1868     FEfree = (struct FileEntry *)itofe(freelisthead);
1869     read(fd, HashTable, sizeof(HashTable));
1870     read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks);    /* CB stuff */
1871     read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks);    /* FE stuff */
1872     if (close(fd)) {
1873         perror("Error reading dumpfile");
1874         exit(1);
1875     }
1876     return now;
1877 }
1878
1879 #include "AFS_component_version_number.c"
1880
1881 int
1882 main(int argc, char **argv)
1883 {
1884     int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1885     static AFSFid fid;
1886     register struct FileEntry *fe;
1887     register struct CallBack *cb;
1888     time_t now;
1889
1890     memset(&fid, 0, sizeof(fid));
1891     argc--;
1892     argv++;
1893     while (argc && **argv == '-') {
1894         noptions++;
1895         argc--;
1896         if (!strcmp(*argv, "-host")) {
1897             if (argc < 1) {
1898                 err++;
1899                 break;
1900             }
1901             argc--;
1902             cbi = atoi(*++argv);
1903         } else if (!strcmp(*argv, "-fid")) {
1904             if (argc < 2) {
1905                 err++;
1906                 break;
1907             }
1908             argc -= 3;
1909             fid.Volume = atoi(*++argv);
1910             fid.Vnode = atoi(*++argv);
1911             fid.Unique = atoi(*++argv);
1912         } else if (!strcmp(*argv, "-time")) {
1913             fprintf(stderr, "-time not supported\n");
1914             exit(1);
1915         } else if (!strcmp(*argv, "-stats")) {
1916             stats = 1;
1917         } else if (!strcmp(*argv, "-all")) {
1918             all = 1;
1919         } else if (!strcmp(*argv, "-raw")) {
1920             raw = 1;
1921         } else if (!strcmp(*argv, "-volume")) {
1922             if (argc < 1) {
1923                 err++;
1924                 break;
1925             }
1926             argc--;
1927             vol = atoi(*++argv);
1928         } else
1929             err++;
1930         argv++;
1931     }
1932     if (err || argc != 1) {
1933         fprintf(stderr,
1934                 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
1935         fprintf(stderr,
1936                 "[cbid is shown for each host in the hosts.dump file]\n");
1937         exit(1);
1938     }
1939     now = ReadDump(*argv);
1940     if (stats || noptions == 0) {
1941         time_t uxtfirst = UXtime(tfirst);
1942         printf("The time of the dump was %u %s", now, ctime(&now));
1943         printf("The last time cleanup ran was %u %s", uxtfirst,
1944                ctime(&uxtfirst));
1945         PrintCallBackStats();
1946     }
1947     if (all || vol) {
1948         register hash;
1949         register afs_uint32 *feip;
1950         register struct CallBack *cb;
1951         register struct FileEntry *fe;
1952
1953         for (hash = 0; hash < VHASH; hash++) {
1954             for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1955                 if (!vol || (fe->volid == vol)) {
1956                     register struct CallBack *cbnext;
1957                     for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1958                         PrintCB(cb, now);
1959                         cbnext = itocb(cb->cnext);
1960                     }
1961                     *feip = fe->fnext;
1962                 } else {
1963                     feip = &fe->fnext;
1964                 }
1965             }
1966         }
1967     }
1968     if (cbi) {
1969         afs_uint32 cfirst = cbi;
1970         do {
1971             cb = itocb(cbi);
1972             PrintCB(cb, now);
1973             cbi = cb->hnext;
1974         } while (cbi != cfirst);
1975     }
1976     if (fid.Volume) {
1977         fe = FindFE(&fid);
1978         if (!fe) {
1979             printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1980             exit(1);
1981         }
1982         cb = itocb(fe->firstcb);
1983         while (cb) {
1984             PrintCB(cb, now);
1985             cb = itocb(cb->cnext);
1986         }
1987     }
1988     if (raw) {
1989         struct FileEntry *fe;
1990         afs_int32 *p, i;
1991         for (i = 1; i < cbstuff.nblks; i++) {
1992             p = (afs_int32 *) & FE[i];
1993             printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1994         }
1995     }
1996 }
1997
1998 int
1999 PrintCB(register struct CallBack *cb, afs_uint32 now)
2000 {
2001     struct FileEntry *fe = itofe(cb->fhead);
2002     time_t expires = TIndexToTime(cb->thead);
2003
2004     if (fe == NULL)
2005         return;
2006
2007     printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
2008            fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
2009            expires - now, ctime(&expires));
2010 }
2011
2012 #endif
2013
2014 #if     !defined(INTERPRET_DUMP)
2015 /*
2016 ** try breaking calbacks on afidp from host. Use multi_rx.
2017 ** return 0 on success, non-zero on failure
2018 */
2019 int
2020 MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
2021 {
2022     int retVal;
2023     H_LOCK;
2024     retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
2025     H_UNLOCK;
2026     return retVal;
2027 }
2028
2029 int
2030 MultiBreakCallBackAlternateAddress_r(struct host *host,
2031                                      struct AFSCBFids *afidp)
2032 {
2033     int i, j;
2034     struct rx_connection **conns;
2035     struct rx_connection *connSuccess = 0;
2036     struct AddrPort *interfaces;
2037     static struct rx_securityClass *sc = 0;
2038     static struct AFSCBs tc = { 0, 0 };
2039     char hoststr[16];
2040
2041     /* nothing more can be done */
2042     if (!host->interface)
2043         return 1;               /* failure */
2044
2045     assert(host->interface->numberOfInterfaces > 0);
2046
2047     /* the only address is the primary interface */
2048     if (host->interface->numberOfInterfaces == 1)
2049         return 1;               /* failure */
2050
2051     /* initialise a security object only once */
2052     if (!sc)
2053         sc = rxnull_NewClientSecurityObject();
2054
2055     i = host->interface->numberOfInterfaces;
2056     interfaces = calloc(i, sizeof(struct AddrPort));
2057     conns = calloc(i, sizeof(struct rx_connection *));
2058     if (!interfaces || !conns) {
2059         ViceLog(0,
2060                 ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
2061         assert(0);
2062     }
2063
2064     /* initialize alternate rx connections */
2065     for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2066         /* this is the current primary address */
2067         if (host->host == host->interface->interface[i].addr &&
2068             host->port == host->interface->interface[i].port)
2069             continue;
2070
2071         interfaces[j] = host->interface->interface[i];
2072         conns[j] =
2073             rx_NewConnection(interfaces[j].addr, 
2074                              interfaces[j].port, 1, sc, 0);
2075         rx_SetConnDeadTime(conns[j], 2);
2076         rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2077         j++;
2078     }
2079
2080     assert(j);                  /* at least one alternate address */
2081     ViceLog(125,
2082             ("Starting multibreakcall back on all addr for host %s\n",
2083              afs_inet_ntoa_r(host->host, hoststr)));
2084     H_UNLOCK;
2085     multi_Rx(conns, j) {
2086         multi_RXAFSCB_CallBack(afidp, &tc);
2087         if (!multi_error) {
2088             /* first success */
2089             H_LOCK;
2090             if (host->callback_rxcon)
2091                 rx_DestroyConnection(host->callback_rxcon);
2092             host->callback_rxcon = conns[multi_i];
2093             host->host = interfaces[multi_i].addr;
2094             host->port = interfaces[multi_i].port;
2095             connSuccess = conns[multi_i];
2096             rx_SetConnDeadTime(host->callback_rxcon, 50);
2097             rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2098             ViceLog(125,
2099                     ("multibreakcall success with addr %s\n",
2100                      afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
2101             H_UNLOCK;
2102             multi_Abort;
2103         }
2104     }
2105     multi_End_Ignore;
2106     H_LOCK;
2107     /* Destroy all connections except the one on which we succeeded */
2108     for (i = 0; i < j; i++)
2109         if (conns[i] != connSuccess)
2110             rx_DestroyConnection(conns[i]);
2111
2112     free(interfaces);
2113     free(conns);
2114
2115     if (connSuccess)
2116         return 0;               /* success */
2117     else
2118         return 1;               /* failure */
2119 }
2120
2121
2122 /*
2123 ** try multi_RX probes to host. 
2124 ** return 0 on success, non-0 on failure
2125 */
2126 int
2127 MultiProbeAlternateAddress_r(struct host *host)
2128 {
2129     int i, j;
2130     struct rx_connection **conns;
2131     struct rx_connection *connSuccess = 0;
2132     struct AddrPort *interfaces;
2133     static struct rx_securityClass *sc = 0;
2134     char hoststr[16];
2135
2136     /* nothing more can be done */
2137     if (!host->interface)
2138         return 1;               /* failure */
2139
2140     assert(host->interface->numberOfInterfaces > 0);
2141
2142     /* the only address is the primary interface */
2143     if (host->interface->numberOfInterfaces == 1)
2144         return 1;               /* failure */
2145
2146     /* initialise a security object only once */
2147     if (!sc)
2148         sc = rxnull_NewClientSecurityObject();
2149
2150     i = host->interface->numberOfInterfaces;
2151     interfaces = calloc(i, sizeof(struct AddrPort));
2152     conns = calloc(i, sizeof(struct rx_connection *));
2153     if (!interfaces || !conns) {
2154         ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
2155         assert(0);
2156     }
2157
2158     /* initialize alternate rx connections */
2159     for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2160         /* this is the current primary address */
2161         if (host->host == host->interface->interface[i].addr &&
2162             host->port == host->interface->interface[i].port)
2163             continue;
2164
2165         interfaces[j] = host->interface->interface[i];
2166         conns[j] =
2167             rx_NewConnection(interfaces[i].addr, 
2168                              interfaces[i].port, 1, sc, 0);
2169         rx_SetConnDeadTime(conns[j], 2);
2170         rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2171         j++;
2172     }
2173
2174     assert(j);                  /* at least one alternate address */
2175     ViceLog(125,
2176             ("Starting multiprobe on all addr for host %s\n",
2177              afs_inet_ntoa_r(host->host, hoststr)));
2178     H_UNLOCK;
2179     multi_Rx(conns, j) {
2180         multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2181         if (!multi_error) {
2182             /* first success */
2183             H_LOCK;
2184             if (host->callback_rxcon)
2185                 rx_DestroyConnection(host->callback_rxcon);
2186             host->callback_rxcon = conns[multi_i];
2187             host->host = interfaces[multi_i].addr;
2188             host->port = interfaces[multi_i].port;
2189             connSuccess = conns[multi_i];
2190             rx_SetConnDeadTime(host->callback_rxcon, 50);
2191             rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2192             ViceLog(125,
2193                     ("multiprobe success with addr %s\n",
2194                      afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
2195             H_UNLOCK;
2196             multi_Abort;
2197         } else {
2198             ViceLog(125,
2199                     ("multiprobe failure with addr %s\n",
2200                      afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
2201             
2202             /* This is less than desirable but its the best we can do.
2203              * The AFS Cache Manager will return either 0 for a Uuid  
2204              * match and a 1 for a non-match.   If the error is 1 we 
2205              * therefore know that our mapping of IP address to Uuid 
2206              * is wrong.   We should attempt to find the correct
2207              * Uuid and fix the host tables.
2208              */
2209             if (multi_error == 1) {
2210                 struct host * newhost;
2211
2212                 /* remove the current alternate address from this host */
2213                 H_LOCK;
2214                 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2215                     if (interfaces[multi_i].addr != host->interface->interface[i].addr &&
2216                         interfaces[multi_i].port != host->interface->interface[i].port) {
2217                         host->interface->interface[j] = host->interface->interface[i];
2218                         j++;
2219                     }
2220                 }
2221                 host->interface->numberOfInterfaces--;
2222                 H_UNLOCK;
2223             }
2224         }
2225     }
2226     multi_End_Ignore;
2227     H_LOCK;
2228     /* Destroy all connections except the one on which we succeeded */
2229     for (i = 0; i < j; i++)
2230         if (conns[i] != connSuccess)
2231             rx_DestroyConnection(conns[i]);
2232
2233     free(interfaces);
2234     free(conns);
2235
2236     if (connSuccess)
2237         return 0;               /* success */
2238     else
2239         return 1;               /* failure */
2240 }
2241
2242 #endif /* !defined(INTERPRET_DUMP) */