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