callback-interfaces-check-malloc-result-for-error-20030208
[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     afs_int32 *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     afs_int32 *feip;
1337     struct CallBack *cb;
1338     struct FileEntry *fe = NULL;
1339     struct FileEntry *myfe = NULL;
1340     struct FileEntry **fepp;
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 (fepp = &myfe; fe = *fepp; ) {
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                 /* relink chain */
1395                 (struct object *) *fepp = ((struct object *)fe)->next;
1396                 FreeFE(fe);
1397             } else {
1398                 (struct object **) fepp = &(((struct object *)fe)->next);
1399             }
1400         }
1401
1402         if (tthead) {
1403             ViceLog(125, ("Breaking volume %d\n", fid.Volume));
1404             henumParms.ncbas = 0;
1405             henumParms.fid = &fid;
1406             henumParms.thead = tthead;
1407             H_UNLOCK
1408             h_Enumerate(MultiBreakVolumeLaterCallBack, (char *) &henumParms);
1409             H_LOCK
1410
1411             if (henumParms.ncbas) {    /* do left-overs */
1412                 struct AFSCBFids tf;
1413                 tf.AFSCBFids_len = 1;
1414                 tf.AFSCBFids_val = &fid;
1415                 
1416                 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1417                 henumParms.ncbas = 0;
1418             }
1419         }  
1420     }
1421     FSYNC_LOCK
1422
1423     if (tthead) goto restart;
1424     H_UNLOCK
1425
1426     return 1;
1427 }
1428
1429 /*
1430  * Delete all timed-out call back entries (to be called periodically by file
1431  * server)
1432  */
1433 int CleanupTimedOutCallBacks(void)
1434 {
1435     H_LOCK
1436     CleanupTimedOutCallBacks_r();
1437     H_UNLOCK
1438 }
1439
1440 int CleanupTimedOutCallBacks_r(void)
1441 {
1442     afs_uint32 now = CBtime(FT_ApproxTime());
1443     register afs_uint32 *thead;
1444     register struct CallBack *cb;
1445     register int ntimedout = 0;
1446     char hoststr[16];
1447
1448     while (tfirst <= now) {
1449         register int cbi;
1450         cbi = *(thead = THead(tfirst));
1451         if (cbi) {
1452             do {
1453                 cb = itocb(cbi);
1454                 cbi = cb->tnext;
1455                 ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1456                         afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port, 
1457                         itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1458                         itofe(cb->fhead)->unique));
1459                 HDel(cb);
1460                 CDel(cb, 1);
1461                 ntimedout++;
1462                 if (ntimedout > cbstuff.nblks) {
1463                   ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1464                   DumpCallBackState();
1465                   ShutDown();
1466                 }
1467             } while (cbi != *thead);
1468             *thead = 0;
1469         }
1470         tfirst++;
1471     }
1472     cbstuff.CBsTimedOut += ntimedout;
1473     ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1474     return (ntimedout > 0);
1475 }
1476
1477 static struct host *lih_host;
1478
1479 static int lih_r(register struct host *host, register int held, 
1480         register struct host *hostp)
1481 {
1482     if (host->cblist
1483            && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1484            && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1485         lih_host = host;
1486     }
1487     return held;
1488 }
1489
1490 /* This could be upgraded to get more space each time */
1491 /* first pass: find the oldest host which isn't held by anyone */
1492 /* second pass: find the oldest host who isn't "me" */
1493 /* always called with hostp unlocked */
1494 extern struct host *hostList;
1495 static int GetSomeSpace_r(struct host *hostp, int locked)
1496 {
1497     register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1498     int i=0;
1499
1500     cbstuff.GotSomeSpaces++;
1501     ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1502     if (CleanupTimedOutCallBacks_r()) {
1503         cbstuff.GSS3++;
1504         return 0;
1505     }
1506     do {
1507         lih_host = 0;
1508         h_Enumerate_r(lih_r, hp2, (char *)hp1);
1509         hp = lih_host;
1510         if (hp) {
1511             cbstuff.GSS4++;
1512             if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1513                 return 0;
1514             hp2 = hp->next;
1515         } else {
1516             hp2 = hostList;
1517             hp1 = hostp;
1518             cbstuff.GSS1++;
1519             ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1520             /*
1521              * Next time try getting callbacks from any host even if
1522              * it's deleted (that's actually great since we can freely
1523              * remove its callbacks) or it's held since the only other
1524              * option is starvation for the file server (i.e. until the
1525              * callback timeout arrives).
1526              */
1527             i++;
1528         }
1529     } while (i < 2);
1530     /*
1531      * No choice to clear this host's callback state
1532      */
1533     /* third pass: we still haven't gotten any space, so we free what we had
1534      * previously passed over. */
1535     cbstuff.GSS2++;
1536     if (!locked) {
1537       h_Lock_r(hostp);
1538     }
1539     ClearHostCallbacks_r(hostp, 1/*already locked*/);
1540     if (!locked) {
1541       h_Unlock_r(hostp);
1542     }
1543     return 0;
1544 }
1545
1546 /* locked - set if caller has already locked the host */
1547 int ClearHostCallbacks(struct host *hp, int locked)
1548 {
1549     int retVal;
1550     H_LOCK
1551     retVal = ClearHostCallbacks_r(hp, locked);
1552     H_UNLOCK
1553     return retVal;
1554 }
1555
1556 /* locked - set if caller has already locked the host */
1557 int ClearHostCallbacks_r(struct host *hp, int locked)
1558 {
1559     struct interfaceAddr interf;
1560     int code;
1561     int held = 0;
1562     char hoststr[16];
1563
1564     ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
1565     if ( !(held = h_Held_r(hp)) )
1566         h_Hold_r(hp);
1567
1568     /** Try a non-blocking lock. If the lock is already held return
1569       * after releasing hold on hp
1570       */
1571     if (!locked) {
1572        if ( h_NBLock_r(hp) ) {
1573            if ( !held )
1574                h_Release_r(hp);
1575            return 1;
1576        }
1577     }
1578     if (hp->Console & 2) {
1579         /*
1580          * If the special console field is set it means that a thread
1581          * is waiting in AddCallBack1 after it set pointers to the
1582          * file entry and/or callback entry. Because of the bogus
1583          * usage of h_hold it won't prevent from another thread, this
1584          * one, to remove all the callbacks so just to be safe we keep
1585          * a reference. NOTE, on the last phase we'll free the calling
1586          * host's callbacks but that's ok...
1587          */
1588         cbstuff.GSS5++;
1589     }
1590     DeleteAllCallBacks_r(hp, 1);
1591     if (hp->hostFlags & VENUSDOWN) {
1592         hp->hostFlags &= ~RESETDONE;    /* remember that we must do a reset */
1593     } else {
1594         /* host is up, try a call */
1595         hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1596         if (hp->interface) {
1597             H_UNLOCK
1598             code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1599             H_LOCK
1600         } else {
1601             H_UNLOCK
1602             code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1603             H_LOCK
1604         }
1605         hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1606         if (code)
1607         {
1608             /* failed, mark host down and need reset */
1609             hp->hostFlags |= VENUSDOWN;
1610             hp->hostFlags &= ~RESETDONE;
1611         } else {
1612             /* reset succeeded, we're done */
1613             hp->hostFlags |= RESETDONE;
1614         }
1615     }
1616     if (!locked) {
1617        h_Unlock_r(hp);
1618     }
1619     if ( !held )
1620         h_Release_r(hp);
1621
1622     return 0;
1623 }
1624 #endif /* INTERPRET_DUMP */
1625
1626
1627 int PrintCallBackStats(void)
1628 {
1629     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",
1630             cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1631             cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1632             cbstuff.DeleteAllCallBacks);
1633     fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1634             cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1635
1636     return 0;
1637 }
1638
1639 #define MAGIC 0x12345678    /* To check byte ordering of dump when it is read in */
1640
1641 #ifndef INTERPRET_DUMP
1642
1643 int DumpCallBackState(void)
1644 {
1645     int fd;
1646     afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1647
1648     fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1649     if (fd < 0) {
1650         ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1651         return 0;
1652     }
1653     write(fd, &magic, sizeof(magic));
1654     write(fd, &now, sizeof(now));
1655     write(fd, &cbstuff, sizeof(cbstuff));
1656     write(fd, TimeOuts, sizeof(TimeOuts));
1657     write(fd, timeout, sizeof(timeout));
1658     write(fd, &tfirst, sizeof(tfirst));
1659     freelisthead = cbtoi((struct CallBack *) CBfree);
1660     write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1661     freelisthead = fetoi((struct FileEntry *) FEfree);
1662     write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1663     write(fd, HashTable, sizeof(HashTable));
1664     write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1665     write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1666     close(fd);
1667
1668     return 0;
1669 }
1670
1671 #endif
1672
1673 #ifdef INTERPRET_DUMP
1674
1675 /* This is only compiled in for the callback analyzer program */
1676 /* Returns the time of the dump */
1677 time_t ReadDump(char *file)
1678 {
1679     int fd;
1680     afs_uint32 magic, freelisthead;
1681     time_t now;
1682
1683     fd = open(file, O_RDONLY);
1684     if (fd < 0) {
1685         fprintf(stderr, "Couldn't read dump file %s\n", file);
1686         exit(1);
1687     }
1688     read(fd, &magic, sizeof(magic));
1689     if (magic != MAGIC) {
1690         fprintf(stderr, "Magic number of %s is invalid.  You might be trying to\n",
1691                 file);
1692         fprintf(stderr,
1693                 "run this program on a machine type with a different byte ordering.\n");
1694         exit(1);
1695     }
1696     read(fd, &now, sizeof(now));
1697     read(fd, &cbstuff, sizeof(cbstuff));
1698     read(fd, TimeOuts, sizeof(TimeOuts));
1699     read(fd, timeout, sizeof(timeout));
1700     read(fd, &tfirst, sizeof(tfirst));
1701     read(fd, &freelisthead, sizeof(freelisthead));
1702     CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1703     FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1704     CBfree = (struct CallBack *) itocb(freelisthead);
1705     read(fd, &freelisthead, sizeof(freelisthead));
1706     FEfree = (struct FileEntry *) itofe(freelisthead);
1707     read(fd, HashTable, sizeof(HashTable));
1708     read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1709     read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1710     if (close(fd)) {
1711         perror("Error reading dumpfile");
1712         exit(1);
1713     }
1714     return now;
1715 }
1716
1717 #include "AFS_component_version_number.c"
1718
1719 int main(int argc, char **argv)
1720 {
1721     int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1722     static AFSFid fid;
1723     register struct FileEntry *fe;
1724     register struct CallBack *cb;
1725     time_t now;
1726
1727     memset(&fid, 0, sizeof(fid));
1728     argc--; argv++;
1729     while (argc && **argv == '-') {
1730         noptions++;
1731         argc--;
1732         if (!strcmp(*argv, "-host")) {
1733             if (argc < 1) {
1734                 err++;
1735                 break;
1736             }
1737             argc--;
1738             cbi = atoi(*++argv);
1739         }
1740         else if (!strcmp(*argv, "-fid")) {
1741             if (argc < 2) {
1742                 err++;
1743                 break;
1744             }
1745             argc -= 3;
1746             fid.Volume = atoi(*++argv);
1747             fid.Vnode = atoi(*++argv);
1748             fid.Unique = atoi(*++argv);
1749         }
1750         else if (!strcmp(*argv, "-time")) {
1751             fprintf(stderr, "-time not supported\n");
1752             exit(1);
1753         }
1754         else if (!strcmp(*argv, "-stats")) {
1755             stats = 1;
1756         }
1757         else if (!strcmp(*argv, "-all")) {
1758             all = 1;
1759         }
1760         else if (!strcmp(*argv, "-raw")) {
1761             raw = 1;
1762         }
1763         else if (!strcmp(*argv, "-volume")) {
1764             if (argc < 1) {
1765                 err++;
1766                 break;
1767             }
1768             argc--;
1769             vol = atoi(*++argv);
1770         }
1771         else err++;
1772         argv++;
1773     }
1774     if (err || argc != 1) {
1775         fprintf(stderr,
1776                 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1777         fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1778         exit(1);
1779     }
1780     now = ReadDump(*argv);
1781     if (stats || noptions == 0) {
1782         time_t uxtfirst = UXtime(tfirst);
1783         printf("The time of the dump was %u %s", now, ctime(&now));
1784         printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1785         PrintCallBackStats();
1786     }
1787     if (all || vol) {
1788         register hash;
1789         register afs_uint32 *feip;
1790         register struct CallBack *cb;
1791         register struct FileEntry *fe;
1792
1793         for (hash=0; hash<VHASH; hash++) {
1794             for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1795                 if (!vol || (fe->volid == vol)) {
1796                     register struct CallBack *cbnext;
1797                     for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1798                         PrintCB(cb,now);
1799                         cbnext = itocb(cb->cnext);
1800                     }
1801                     *feip = fe->fnext;
1802                 } else {
1803                     feip = &fe->fnext;
1804                 }
1805             }
1806         }
1807     }
1808     if (cbi) {
1809         afs_uint32 cfirst = cbi;
1810         do {
1811             cb = itocb(cbi);
1812             PrintCB(cb,now);
1813             cbi = cb->hnext;
1814         } while (cbi != cfirst);
1815     }
1816     if (fid.Volume) {
1817         fe = FindFE(&fid);
1818         if (!fe) {
1819             printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1820             exit(1);
1821         }
1822         cb = itocb(fe->firstcb);
1823         while (cb) {
1824             PrintCB(cb, now);
1825             cb = itocb(cb->cnext);
1826         }
1827     }
1828     if (raw) {
1829         struct FileEntry *fe;
1830         afs_int32 *p, i;
1831         for (i=1; i < cbstuff.nblks; i++) {
1832             p = (afs_int32 *) &FE[i];
1833             printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1834         }
1835     }
1836 }
1837
1838 int PrintCB(register struct CallBack *cb, afs_uint32 now)
1839 {
1840     struct FileEntry *fe = itofe(cb->fhead);
1841     time_t expires = TIndexToTime(cb->thead);
1842
1843     printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s", 
1844            fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1845            fe->status, expires - now, ctime(&expires));
1846 }
1847
1848 #endif
1849
1850 #if     !defined(INTERPRET_DUMP)
1851 /*
1852 ** try breaking calbacks on afidp from host. Use multi_rx.
1853 ** return 0 on success, non-zero on failure
1854 */
1855 int MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1856 {
1857     int retVal;
1858     H_LOCK
1859     retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1860     H_UNLOCK
1861     return retVal;
1862 }
1863
1864 int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *afidp)
1865 {
1866         int i,j;
1867         struct rx_connection**  conns;
1868         struct rx_connection*   connSuccess = 0;
1869         afs_int32               *addr;
1870         static struct rx_securityClass *sc = 0;
1871         static struct AFSCBs tc = {0,0};
1872         char hoststr[16];
1873
1874         /* nothing more can be done */
1875         if ( !host->interface ) return 1;       /* failure */
1876
1877         assert(host->interface->numberOfInterfaces > 0 );
1878
1879         /* the only address is the primary interface */
1880         if ( host->interface->numberOfInterfaces == 1 )
1881                 return 1;                       /* failure */
1882
1883         /* initialise a security object only once */
1884         if ( !sc )
1885             sc = rxnull_NewClientSecurityObject();
1886
1887         i = host->interface->numberOfInterfaces;
1888         addr = malloc(i * sizeof(afs_int32));
1889         if (!addr) return 1;
1890         conns = malloc(i * sizeof(struct rx_connection *));
1891         if (!conns) { free(addr); return 1; }
1892
1893         /* initialize alternate rx connections */
1894         for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1895         {
1896                 /* this is the current primary address */
1897                 if ( host->host == host->interface->addr[i] )
1898                         continue;       
1899
1900                 addr[j]    = host->interface->addr[i];
1901                 conns[j] =  rx_NewConnection (host->interface->addr[i],
1902                                 host->port, 1, sc, 0);
1903                 rx_SetConnDeadTime(conns[j], 2); 
1904                 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME); 
1905                 j++;
1906         }
1907
1908         assert(j);  /* at least one alternate address */
1909         ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
1910                         afs_inet_ntoa_r(host->host,hoststr)));
1911         H_UNLOCK
1912         multi_Rx(conns, j)
1913         {
1914                 multi_RXAFSCB_CallBack(afidp, &tc);     
1915                 if ( !multi_error )
1916                 {
1917                         /* first success */
1918                         H_LOCK
1919                         if ( host->callback_rxcon )
1920                                 rx_DestroyConnection(host->callback_rxcon);
1921                         host->callback_rxcon = conns[multi_i];
1922                         host->host           = addr[multi_i];
1923                         connSuccess          = conns[multi_i];
1924                         rx_SetConnDeadTime(host->callback_rxcon, 50);
1925                         rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1926                         ViceLog(125,("multibreakcall success with addr %s\n",
1927                                         afs_inet_ntoa_r(addr[multi_i],hoststr)));
1928                         H_UNLOCK
1929                         multi_Abort; 
1930                 }
1931         } multi_End_Ignore;
1932         H_LOCK
1933
1934         /* Destroy all connections except the one on which we succeeded */
1935         for ( i=0; i < j; i++)
1936                 if ( conns[i] != connSuccess )
1937                         rx_DestroyConnection(conns[i] );
1938
1939         free(addr);
1940         free(conns);
1941
1942         if ( connSuccess ) return 0;    /* success */
1943                 else return 1;          /* failure */
1944 }
1945
1946
1947 /*
1948 ** try multiRX probes to host. 
1949 ** return 0 on success, non-zero on failure
1950 */
1951 int MultiProbeAlternateAddress_r(struct host *host)
1952 {
1953         int i,j;
1954         struct rx_connection**  conns;
1955         struct rx_connection*   connSuccess = 0;
1956         afs_int32               *addr;
1957         static struct rx_securityClass *sc = 0;
1958         char hoststr[16];
1959
1960         /* nothing more can be done */
1961         if ( !host->interface ) return 1;       /* failure */
1962
1963         assert(host->interface->numberOfInterfaces > 0 );
1964
1965         /* the only address is the primary interface */
1966         if ( host->interface->numberOfInterfaces == 1 )
1967                 return 1;                       /* failure */
1968
1969         /* initialise a security object only once */
1970         if ( !sc )
1971             sc = rxnull_NewClientSecurityObject();
1972
1973         i = host->interface->numberOfInterfaces;
1974         addr = malloc(i * sizeof(afs_int32));
1975         if (!addr) return 1;
1976         conns = malloc(i * sizeof(struct rx_connection *));
1977         if (!conns) { free(addr); return 1; }
1978
1979         /* initialize alternate rx connections */
1980         for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1981         {
1982                 /* this is the current primary address */
1983                 if ( host->host == host->interface->addr[i] )
1984                         continue;       
1985
1986                 addr[j]    = host->interface->addr[i];
1987                 conns[j] =  rx_NewConnection (host->interface->addr[i],
1988                                 host->port, 1, sc, 0);
1989                 rx_SetConnDeadTime(conns[j], 2); 
1990                 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME); 
1991                 j++;
1992         }
1993
1994         assert(j);  /* at least one alternate address */
1995         ViceLog(125,("Starting multiprobe on all addr for host %s\n",
1996                         afs_inet_ntoa_r(host->host,hoststr)));
1997         H_UNLOCK
1998         multi_Rx(conns, j)
1999         {
2000                 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);        
2001                 if ( !multi_error )
2002                 {
2003                         /* first success */
2004                         H_LOCK
2005                         if ( host->callback_rxcon )
2006                                 rx_DestroyConnection(host->callback_rxcon);
2007                         host->callback_rxcon = conns[multi_i];
2008                         host->host           = addr[multi_i];
2009                         connSuccess          = conns[multi_i];
2010                         rx_SetConnDeadTime(host->callback_rxcon, 50);
2011                         rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2012                         ViceLog(125,("multiprobe success with addr %s\n",
2013                                         afs_inet_ntoa_r(addr[multi_i],hoststr)));
2014                         H_UNLOCK
2015                         multi_Abort; 
2016                 }
2017         } multi_End_Ignore;
2018         H_LOCK
2019
2020         /* Destroy all connections except the one on which we succeeded */
2021         for ( i=0; i < j; i++)
2022                 if ( conns[i] != connSuccess )
2023                         rx_DestroyConnection(conns[i] );
2024
2025         free(addr);
2026         free(conns);
2027
2028         if ( connSuccess ) return 0;    /* success */
2029                 else return 1;          /* failure */
2030 }
2031
2032 #endif /* !defined(INTERPRET_DUMP) */