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