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