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