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