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