fc45bb3796f6e5e6a8f1ca6f62601ea9ff5dacad
[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         rx_GetConnection(thishost->callback_rxcon);
780         conns[j++] = thishost->callback_rxcon;
781
782 #ifdef  ADAPT_MTU
783         rx_SetConnDeadTime(thishost->callback_rxcon, 4);
784         rx_SetConnHardDeadTime(thishost->callback_rxcon, AFS_HARDDEADTIME);
785 #endif
786     }
787
788     if (j) {                    /* who knows what multi would do with 0 conns? */
789         cbstuff.nbreakers++;
790         H_UNLOCK;
791         multi_Rx(conns, j) {
792             multi_RXAFSCB_CallBack(afidp, &tc);
793             if (multi_error) {
794                 afs_uint32 idx;
795                 struct host *hp;
796                 char hoststr[16];
797
798                 idx = 0;
799                 /* If there's an error, we have to hunt for the right host. 
800                  * The conns array _should_ correspond one-to-one to the cba
801                  * array, except in some rare cases it might be missing one 
802                  * or more elements.  So the optimistic case is almost 
803                  * always right.  At worst, it's the starting point for the 
804                  * hunt. */
805                 for (hp = 0, i = multi_i; i < j; i++) {
806                     hp = cba[i].hp;     /* optimistic, but usually right */
807                     if (!hp) {
808                         break;
809                     }
810                     if (conns[multi_i] == hp->callback_rxcon) {
811                         idx = cba[i].thead;
812                         break;
813                     }
814                 }
815
816                 if (!hp) {
817                     ViceLog(0,
818                             ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n", hp,
819                              cba));
820                 } else {
821                     /* 
822                      ** try breaking callbacks on alternate interface addresses
823                      */
824                     if (MultiBreakCallBackAlternateAddress(hp, afidp)) {
825                         if (ShowProblems) {
826                             ViceLog(7,
827                                     ("BCB: Failed on file %u.%u.%u, host %s:%d is down\n",
828                                      afidp->AFSCBFids_val->Volume,
829                                      afidp->AFSCBFids_val->Vnode,
830                                      afidp->AFSCBFids_val->Unique,
831                                      afs_inet_ntoa_r(hp->host, hoststr),
832                                      ntohs(hp->port)));
833                         }
834
835                         H_LOCK;
836                         h_Lock_r(hp); 
837                         hp->hostFlags |= VENUSDOWN;
838                 /**
839                   * We always go into AddCallBack1_r with the host locked
840                   */
841                         AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
842                                        CB_DELAYED, 1);
843                         h_Unlock_r(hp); 
844                         H_UNLOCK;
845                     }
846                 }
847             }
848         }
849         multi_End;
850         H_LOCK;
851         cbstuff.nbreakers--;
852     }
853
854     for (i = 0; i < ncbas; i++) {
855         struct host *hp;
856         hp = cba[i].hp;
857         if (hp && xhost != hp) {
858             h_Release_r(hp);
859         }
860     }
861
862     /* H_UNLOCK around this so h_FreeConnection does not deadlock.
863        h_FreeConnection should *never* be called on a callback connection,
864        but on 10/27/04 a deadlock occurred where it was, when we know why,
865        this should be reverted. -- shadow */
866     H_UNLOCK;
867     for (i = 0; i < j; i++) {
868         rx_PutConnection(conns[i]);
869     }
870     H_LOCK;
871
872     return;
873 }
874
875 /*
876  * Break all call backs for fid, except for the specified host (unless flag
877  * is true, in which case all get a callback message. Assumption: the specified
878  * host is h_Held, by the caller; the others aren't.
879  * Specified host may be bogus, that's ok.  This used to check to see if the 
880  * host was down in two places, once right after the host was h_held, and 
881  * again after it was locked.  That race condition is incredibly rare and
882  * relatively harmless even when it does occur, so we don't check for it now. 
883  */
884 /* if flag is true, send a break callback msg to "host", too */
885 int
886 BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
887 {
888     struct FileEntry *fe;
889     struct CallBack *cb, *nextcb;
890     struct cbstruct cba[MAX_CB_HOSTS];
891     int ncbas;
892     struct AFSCBFids tf;
893     int hostindex;
894     char hoststr[16];
895
896     ViceLog(7,
897             ("BCB: BreakCallBack(all but %s:%d, (%u,%u,%u))\n",
898              afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
899              fid->Volume, fid->Vnode, fid->Unique));
900
901     H_LOCK;
902     cbstuff.BreakCallBacks++;
903     fe = FindFE(fid);
904     if (!fe) {
905         goto done;
906     }
907     hostindex = h_htoi(xhost);
908     cb = itocb(fe->firstcb);
909     if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
910         /* the most common case is what follows the || */
911         goto done;
912     }
913     tf.AFSCBFids_len = 1;
914     tf.AFSCBFids_val = fid;
915
916     for (; cb;) {
917         for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
918             nextcb = itocb(cb->cnext);
919             if ((cb->hhead != hostindex || flag)
920                 && (cb->status == CB_BULK || cb->status == CB_NORMAL
921                     || cb->status == CB_VOLUME)) {
922                 struct host *thishost = h_itoh(cb->hhead);
923                 if (!thishost) {
924                     ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
925                 } else if (thishost->hostFlags & VENUSDOWN) {
926                     ViceLog(7,
927                             ("BCB: %s:%d is down; delaying break call back\n",
928                              afs_inet_ntoa_r(thishost->host, hoststr),
929                              ntohs(thishost->port)));
930                     cb->status = CB_DELAYED;
931                 } else {
932                     h_Hold_r(thishost);
933                     cba[ncbas].hp = thishost;
934                     cba[ncbas].thead = cb->thead;
935                     ncbas++;
936                     TDel(cb);
937                     HDel(cb);
938                     CDel(cb, 1);        /* Usually first; so this delete 
939                                          * is reasonably inexpensive */
940                 }
941             }
942         }
943
944         if (ncbas) {
945             MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
946
947             /* we need to to all these initializations again because MultiBreakCallBack may block */
948             fe = FindFE(fid);
949             if (!fe) {
950                 goto done;
951             }
952             cb = itocb(fe->firstcb);
953             if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
954                 /* the most common case is what follows the || */
955                 goto done;
956             }
957         }
958     }
959
960   done:
961     H_UNLOCK;
962     return 0;
963 }
964
965 /* Delete (do not break) single call back for fid */
966 int
967 DeleteCallBack(struct host *host, AFSFid * fid)
968 {
969     register struct FileEntry *fe;
970     register afs_uint32 *pcb;
971     char hoststr[16];
972
973     cbstuff.DeleteCallBacks++;
974
975     H_LOCK;
976     h_Lock_r(host);
977     fe = FindFE(fid);
978     if (!fe) {
979         h_Unlock_r(host);
980         H_UNLOCK;
981         ViceLog(8,
982                 ("DCB: No call backs for fid (%u, %u, %u)\n", fid->Volume,
983                  fid->Vnode, fid->Unique));
984         return 0;
985     }
986     pcb = FindCBPtr(fe, host);
987     if (!*pcb) {
988         ViceLog(8,
989                 ("DCB: No call back for host %s:%d, (%u, %u, %u)\n",
990                  afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
991                  fid->Volume, fid->Vnode, fid->Unique));
992         h_Unlock_r(host);
993         H_UNLOCK;
994         return 0;
995     }
996     HDel(itocb(*pcb));
997     TDel(itocb(*pcb));
998     CDelPtr(fe, pcb, 1);
999     h_Unlock_r(host);
1000     H_UNLOCK;
1001     return 0;
1002 }
1003
1004 /*
1005  * Delete (do not break) all call backs for fid.  This call doesn't
1006  * set all of the various host locks, but it shouldn't really matter
1007  * since we're not adding callbacks, but deleting them.  I'm not sure
1008  * why it doesn't set the lock, however; perhaps it should.
1009  */
1010 int
1011 DeleteFileCallBacks(AFSFid * fid)
1012 {
1013     register struct FileEntry *fe;
1014     register struct CallBack *cb;
1015     register afs_uint32 cbi;
1016     register int n;
1017
1018     H_LOCK;
1019     cbstuff.DeleteFiles++;
1020     fe = FindFE(fid);
1021     if (!fe) {
1022         H_UNLOCK;
1023         ViceLog(8,
1024                 ("DF: No fid (%u,%u,%u) to delete\n", fid->Volume, fid->Vnode,
1025                  fid->Unique));
1026         return 0;
1027     }
1028     for (n = 0, cbi = fe->firstcb; cbi; n++) {
1029         cb = itocb(cbi);
1030         cbi = cb->cnext;
1031         TDel(cb);
1032         HDel(cb);
1033         FreeCB(cb);
1034     }
1035     FDel(fe);
1036     H_UNLOCK;
1037     return 0;
1038 }
1039
1040 /* Delete (do not break) all call backs for host.  The host should be
1041  * locked. */
1042 int
1043 DeleteAllCallBacks_r(struct host *host, int deletefe)
1044 {
1045     register struct CallBack *cb;
1046     register int cbi, first;
1047
1048     cbstuff.DeleteAllCallBacks++;
1049     cbi = first = host->cblist;
1050     if (!cbi) {
1051         ViceLog(8, ("DV: no call backs\n"));
1052         return 0;
1053     }
1054     do {
1055         cb = itocb(cbi);
1056         cbi = cb->hnext;
1057         TDel(cb);
1058         CDel(cb, deletefe);
1059     } while (cbi != first);
1060     host->cblist = 0;
1061     return 0;
1062 }
1063
1064 /*
1065  * Break all delayed call backs for host.  Returns 1 if all call backs
1066  * successfully broken; 0 otherwise.  Assumes host is h_Held and h_Locked.
1067  * Must be called with VenusDown set for this host
1068  */
1069 int
1070 BreakDelayedCallBacks(struct host *host)
1071 {
1072     int retVal;
1073     H_LOCK;
1074     retVal = BreakDelayedCallBacks_r(host);
1075     H_UNLOCK;
1076     return retVal;
1077 }
1078
1079 int
1080 BreakDelayedCallBacks_r(struct host *host)
1081 {
1082     struct AFSFid fids[AFSCBMAX];
1083     u_byte thead[AFSCBMAX];     /* This should match thead in struct Callback */
1084     int cbi, first, nfids;
1085     struct CallBack *cb;
1086     int code;
1087     char hoststr[16];
1088
1089     cbstuff.nbreakers++;
1090     if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1091         host->hostFlags &= ~ALTADDR;    /* alterrnate addresses are invalid */
1092         if (host->interface) {
1093             H_UNLOCK;
1094             code =
1095                 RXAFSCB_InitCallBackState3(host->callback_rxcon,
1096                                            &FS_HostUUID);
1097             H_LOCK;
1098         } else {
1099             H_UNLOCK;
1100             code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1101             H_LOCK;
1102         }
1103         host->hostFlags |= ALTADDR;     /* alternate addresses are valid */
1104         if (code) {
1105             if (ShowProblems) {
1106                 ViceLog(0,
1107                         ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1108                          afs_inet_ntoa_r(host->host, hoststr),
1109                          ntohs(host->port)));
1110             }
1111             host->hostFlags |= VENUSDOWN;
1112         } else {
1113             ViceLog(25,
1114                     ("InitCallBackState success on %s\n",
1115                      afs_inet_ntoa_r(host->host, hoststr)));
1116             /* reset was done successfully */
1117             host->hostFlags |= RESETDONE;
1118             host->hostFlags &= ~VENUSDOWN;
1119         }
1120     } else
1121         while (!(host->hostFlags & HOSTDELETED)) {
1122             nfids = 0;
1123             host->hostFlags &= ~VENUSDOWN;      /* presume up */
1124             cbi = first = host->cblist;
1125             if (!cbi)
1126                 break;
1127             do {
1128                 first = host->cblist;
1129                 cb = itocb(cbi);
1130                 cbi = cb->hnext;
1131                 if (cb->status == CB_DELAYED) {
1132                     register struct FileEntry *fe = itofe(cb->fhead);
1133                     thead[nfids] = cb->thead;
1134                     fids[nfids].Volume = fe->volid;
1135                     fids[nfids].Vnode = fe->vnode;
1136                     fids[nfids].Unique = fe->unique;
1137                     nfids++;
1138                     HDel(cb);
1139                     TDel(cb);
1140                     CDel(cb, 1);
1141                 }
1142             } while (cbi && cbi != first && nfids < AFSCBMAX);
1143
1144             if (nfids == 0) {
1145                 break;
1146             }
1147
1148             if (XCallBackBulk_r(host, fids, nfids)) {
1149                 /* Failed, again:  put them back, probably with old
1150                  * timeout values */
1151                 int i;
1152                 if (ShowProblems) {
1153                     ViceLog(0,
1154                             ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1155                              afs_inet_ntoa_r(host->host, hoststr),
1156                              ntohs(host->port)));
1157                 }
1158                 for (i = 0; i < nfids; i++) {
1159                     if (ShowProblems) {
1160                         ViceLog(0,
1161                                 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1162                                  afs_inet_ntoa_r(host->host, hoststr),
1163                                  ntohs(host->port), fids[i].Volume,
1164                                  fids[i].Vnode, fids[i].Unique));
1165                     }
1166                     /* used to do this:
1167                      * AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1168                      * * but it turns out to cause too many tricky locking problems.
1169                      * * now, if break delayed fails, screw it. */
1170                 }
1171                 host->hostFlags |= VENUSDOWN;   /* Failed */
1172                 ClearHostCallbacks_r(host, 1 /* locked */ );
1173                 nfids = 0;
1174                 break;
1175             }
1176             if (nfids < AFSCBMAX)
1177                 break;
1178         }
1179
1180     cbstuff.nbreakers--;
1181     /* If we succeeded it's always ok to unset HFE_LATER */
1182     if (!host->hostFlags & VENUSDOWN)
1183         host->hostFlags &= ~HFE_LATER;
1184     return (host->hostFlags & VENUSDOWN);
1185 }
1186
1187 /*
1188 ** isheld is 0 if the host is held in h_Enumerate
1189 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1190 */
1191 static int
1192 MultiBreakVolumeCallBack_r(struct host *host, int isheld,
1193                            struct VCBParams *parms, int deletefe)
1194 {
1195     char hoststr[16];
1196
1197     if (!isheld)
1198         return isheld;          /* host is held only by h_Enumerate, do nothing */
1199     if (host->hostFlags & HOSTDELETED)
1200         return 0;               /* host is deleted, release hold */
1201
1202     if (host->hostFlags & VENUSDOWN) {
1203         h_Lock_r(host);
1204         if (host->hostFlags & HOSTDELETED) {
1205             h_Unlock_r(host);
1206             return 0;           /* Release hold */
1207         }
1208         ViceLog(8,
1209                 ("BVCB: volume call back for host %s:%d failed\n",
1210                  afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1211         if (ShowProblems) {
1212             ViceLog(0,
1213                     ("CB: volume callback for host %s:%d failed\n",
1214                      afs_inet_ntoa_r(host->host, hoststr),
1215                      ntohs(host->port)));
1216         }
1217         DeleteAllCallBacks_r(host, deletefe);   /* Delete all callback state 
1218                                                  * rather than attempting to 
1219                                                  * selectively remember to
1220                                                  * delete the volume callbacks
1221                                                  * later */
1222         host->hostFlags &= ~RESETDONE;  /* Do InitCallBackState when host returns */
1223         h_Unlock_r(host);
1224         return 0;               /* release hold */
1225     }
1226     assert(parms->ncbas <= MAX_CB_HOSTS);
1227
1228     /* Do not call MultiBreakCallBack on the current host structure
1229      ** because it would prematurely release the hold on the host
1230      */
1231     if (parms->ncbas == MAX_CB_HOSTS) {
1232         struct AFSCBFids tf;
1233
1234         tf.AFSCBFids_len = 1;
1235         tf.AFSCBFids_val = parms->fid;
1236
1237         /* this releases all the hosts */
1238         MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */ );
1239
1240         parms->ncbas = 0;
1241     }
1242     parms->cba[parms->ncbas].hp = host;
1243     parms->cba[(parms->ncbas)++].thead = parms->thead;
1244     return 1;                   /* DON'T release hold, because we still need it. */
1245 }
1246
1247 /*
1248 ** isheld is 0 if the host is held in h_Enumerate
1249 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1250 */
1251 static int
1252 MultiBreakVolumeCallBack(struct host *host, int isheld,
1253                          struct VCBParams *parms)
1254 {
1255     int retval;
1256     H_LOCK;
1257     retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1258     H_UNLOCK;
1259     return retval;
1260 }
1261
1262 /*
1263 ** isheld is 0 if the host is held in h_Enumerate
1264 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1265 */
1266 static int
1267 MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1268                               struct VCBParams *parms)
1269 {
1270     int retval;
1271     H_LOCK;
1272     retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1273     H_UNLOCK;
1274     return retval;
1275 }
1276
1277 /*
1278  * Break all call backs on a single volume.  Don't call this with any
1279  * hosts h_held.  Note that this routine clears the callbacks before
1280  * actually breaking them, and that the vnode isn't locked during this
1281  * operation, so that people might see temporary callback loss while
1282  * this function is executing.  It is just a temporary state, however,
1283  * since the callback will be broken later by this same function.
1284  *
1285  * Now uses multi-RX for CallBack RPC.  Note that the
1286  * multiBreakCallBacks routine does not force a reset if the RPC
1287  * fails, unlike the previous version of this routine, but does create
1288  * a delayed callback.  Resets will be forced if the host is
1289  * determined to be down before the RPC is executed.
1290  */
1291 int
1292 BreakVolumeCallBacks(afs_uint32 volume)
1293 {
1294     struct AFSFid fid;
1295     int hash;
1296     afs_uint32 *feip;
1297     struct CallBack *cb;
1298     struct FileEntry *fe;
1299     struct host *host;
1300     struct VCBParams henumParms;
1301     afs_uint32 tthead = 0;      /* zero is illegal value */
1302
1303     H_LOCK;
1304     fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1305     for (hash = 0; hash < VHASH; hash++) {
1306         for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
1307             if (fe->volid == volume) {
1308                 register struct CallBack *cbnext;
1309                 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1310                     host = h_itoh(cb->hhead);
1311                     h_Hold_r(host);
1312                     cbnext = itocb(cb->cnext);
1313                     if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1314                         tthead = cb->thead;
1315                     }
1316                     TDel(cb);
1317                     HDel(cb);
1318                     FreeCB(cb);
1319                     /* leave hold for MultiBreakVolumeCallBack to clear */
1320                 }
1321                 *feip = fe->fnext;
1322                 FreeFE(fe);
1323             } else {
1324                 feip = &fe->fnext;
1325             }
1326         }
1327     }
1328
1329     if (!tthead) {
1330         /* didn't find any callbacks, so return right away. */
1331         H_UNLOCK;
1332         return 0;
1333     }
1334     henumParms.ncbas = 0;
1335     henumParms.fid = &fid;
1336     henumParms.thead = tthead;
1337     H_UNLOCK;
1338     h_Enumerate(MultiBreakVolumeCallBack, (char *)&henumParms);
1339     H_LOCK;
1340     if (henumParms.ncbas) {     /* do left-overs */
1341         struct AFSCBFids tf;
1342         tf.AFSCBFids_len = 1;
1343         tf.AFSCBFids_val = &fid;
1344
1345         MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1346
1347         henumParms.ncbas = 0;
1348     }
1349     H_UNLOCK;
1350     return 0;
1351 }
1352
1353 #ifdef AFS_PTHREAD_ENV
1354 extern pthread_cond_t fsync_cond;
1355 #else
1356 extern char fsync_wait[];
1357 #endif
1358
1359 int
1360 BreakVolumeCallBacksLater(afs_uint32 volume)
1361 {
1362     int hash;
1363     afs_int32 *feip;
1364     struct FileEntry *fe;
1365     struct CallBack *cb;
1366     struct host *host;
1367     int found = 0;
1368
1369     ViceLog(25, ("Setting later on volume %u\n", volume));
1370     H_LOCK;
1371     for (hash = 0; hash < VHASH; hash++) {
1372         for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1373             if (fe->volid == volume) {
1374                 register struct CallBack *cbnext;
1375                 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1376                     host = h_itoh(cb->hhead);
1377                     host->hostFlags |= HFE_LATER;
1378                     cb->status = CB_DELAYED;
1379                     cbnext = itocb(cb->cnext);
1380                 }
1381                 FSYNC_LOCK;
1382                 fe->status |= FE_LATER;
1383                 FSYNC_UNLOCK;
1384                 found++;
1385             }
1386             feip = &fe->fnext;
1387         }
1388     }
1389     H_UNLOCK;
1390     if (!found) {
1391         /* didn't find any callbacks, so return right away. */
1392         return 0;
1393     }
1394
1395     ViceLog(25, ("Fsync thread wakeup\n"));
1396 #ifdef AFS_PTHREAD_ENV
1397     assert(pthread_cond_broadcast(&fsync_cond) == 0);
1398 #else
1399     LWP_NoYieldSignal(fsync_wait);
1400 #endif
1401     return 0;
1402 }
1403
1404 int
1405 BreakLaterCallBacks(void)
1406 {
1407     struct AFSFid fid;
1408     int hash;
1409     afs_int32 *feip;
1410     struct CallBack *cb;
1411     struct FileEntry *fe = NULL;
1412     struct FileEntry *myfe = NULL;
1413     struct host *host;
1414     struct VCBParams henumParms;
1415     unsigned short tthead = 0;  /* zero is illegal value */
1416
1417     /* Unchain first */
1418     ViceLog(25, ("Looking for FileEntries to unchain\n"));
1419     H_LOCK;
1420     FSYNC_LOCK;
1421     /* Pick the first volume we see to clean up */
1422     fid.Volume = fid.Vnode = fid.Unique = 0;
1423
1424     for (hash = 0; hash < VHASH; hash++) {
1425         for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1426             if (fe && (fe->status & FE_LATER)
1427                 && (fid.Volume == 0 || fid.Volume == fe->volid)) {
1428                 /* Ugly, but used to avoid left side casting */
1429                 struct object *tmpfe;
1430                 ViceLog(125,
1431                         ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
1432                          fe->volid));
1433                 fid.Volume = fe->volid;
1434                 *feip = fe->fnext;
1435                 /* Works since volid is deeper than the largest pointer */
1436                 tmpfe = (struct object *)fe;
1437                 tmpfe->next = (struct object *)myfe;
1438                 myfe = fe;
1439             } else
1440                 feip = &fe->fnext;
1441         }
1442     }
1443     FSYNC_UNLOCK;
1444
1445     if (!myfe) {
1446         H_UNLOCK;
1447         return 0;
1448     }
1449
1450     /* loop over FEs from myfe and free/break */
1451     tthead = 0;
1452     for (fe = myfe; fe;) {
1453         register struct CallBack *cbnext;
1454         for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1455             host = h_itoh(cb->hhead);
1456             h_Hold_r(host);
1457             cbnext = itocb(cb->cnext);
1458             if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1459                 tthead = cb->thead;
1460             }
1461             TDel(cb);
1462             HDel(cb);
1463             CDel(cb, 0);        /* Don't let CDel clean up the fe */
1464             /* leave hold for MultiBreakVolumeCallBack to clear */
1465         }
1466         myfe = fe;
1467         fe = (struct FileEntry *)((struct object *)fe)->next;
1468         FreeFE(myfe);
1469     }
1470
1471     if (tthead) {
1472         ViceLog(125, ("Breaking volume %u\n", fid.Volume));
1473         henumParms.ncbas = 0;
1474         henumParms.fid = &fid;
1475         henumParms.thead = tthead;
1476         H_UNLOCK;
1477         h_Enumerate(MultiBreakVolumeLaterCallBack, (char *)&henumParms);
1478         H_LOCK;
1479         if (henumParms.ncbas) { /* do left-overs */
1480             struct AFSCBFids tf;
1481             tf.AFSCBFids_len = 1;
1482             tf.AFSCBFids_val = &fid;
1483
1484             MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1485             henumParms.ncbas = 0;
1486         }
1487     }
1488     H_UNLOCK;
1489
1490     /* Arrange to be called again */
1491     return 1;
1492 }
1493
1494 /*
1495  * Delete all timed-out call back entries (to be called periodically by file
1496  * server)
1497  */
1498 int
1499 CleanupTimedOutCallBacks(void)
1500 {
1501     H_LOCK;
1502     CleanupTimedOutCallBacks_r();
1503     H_UNLOCK;
1504     return 0;
1505 }
1506
1507 int
1508 CleanupTimedOutCallBacks_r(void)
1509 {
1510     afs_uint32 now = CBtime(FT_ApproxTime());
1511     register afs_uint32 *thead;
1512     register struct CallBack *cb;
1513     register int ntimedout = 0;
1514     char hoststr[16];
1515
1516     while (tfirst <= now) {
1517         register int cbi;
1518         cbi = *(thead = THead(tfirst));
1519         if (cbi) {
1520             do {
1521                 cb = itocb(cbi);
1522                 cbi = cb->tnext;
1523                 ViceLog(8,
1524                         ("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1525                          afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
1526                          h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
1527                          itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
1528                 HDel(cb);
1529                 CDel(cb, 1);
1530                 ntimedout++;
1531                 if (ntimedout > cbstuff.nblks) {
1532                     ViceLog(0, ("CCB: Internal Error -- shutting down...\n"));
1533                     DumpCallBackState();
1534                     ShutDownAndCore(PANIC);
1535                 }
1536             } while (cbi != *thead);
1537             *thead = 0;
1538         }
1539         tfirst++;
1540     }
1541     cbstuff.CBsTimedOut += ntimedout;
1542     ViceLog(7, ("CCB: deleted %d timed out callbacks\n", ntimedout));
1543     return (ntimedout > 0);
1544 }
1545
1546 static struct host *lih_host;
1547 static int lih_host_held = 0;
1548
1549 static int
1550 lih_r(register struct host *host, register int held,
1551       register struct host *hostp)
1552 {
1553     lih_host_held = 0;
1554     if (host->cblist
1555         && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1556         && (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
1557         lih_host = host;
1558     }
1559     if (!held) {
1560         held = 1;
1561         lih_host_held = 1;
1562     }
1563     return held;
1564 }
1565
1566 /* This could be upgraded to get more space each time */
1567 /* first pass: find the oldest host which isn't held by anyone */
1568 /* second pass: find the oldest host who isn't "me" */
1569 /* always called with hostp unlocked */
1570 extern struct host *hostList;
1571 static int
1572 GetSomeSpace_r(struct host *hostp, int locked)
1573 {
1574     register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1575     int i = 0;
1576
1577     cbstuff.GotSomeSpaces++;
1578     ViceLog(5,
1579             ("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1580     if (CleanupTimedOutCallBacks_r()) {
1581         cbstuff.GSS3++;
1582         return 0;
1583     }
1584     do {
1585         lih_host = 0;
1586         h_Enumerate_r(lih_r, hp2, (char *)hp1);
1587         hp = lih_host;
1588         if (hp) {
1589             cbstuff.GSS4++;
1590             if (!ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
1591                 if (lih_host_held) 
1592                     h_Release_r(hp);
1593                 return 0;
1594             }
1595             if (lih_host_held) 
1596                 h_Release_r(hp);
1597             hp2 = hp->next;
1598         } else {
1599             hp2 = hostList;
1600             hp1 = hostp;
1601             cbstuff.GSS1++;
1602             ViceLog(5,
1603                     ("GSS: Try harder for longest inactive host cnt= %d\n",
1604                      i));
1605             /*
1606              * Next time try getting callbacks from any host even if
1607              * it's deleted (that's actually great since we can freely
1608              * remove its callbacks) or it's held since the only other
1609              * option is starvation for the file server (i.e. until the
1610              * callback timeout arrives).
1611              */
1612             i++;
1613         }
1614     } while (i < 2);
1615     /*
1616      * No choice to clear this host's callback state
1617      */
1618     /* third pass: we still haven't gotten any space, so we free what we had
1619      * previously passed over. */
1620     cbstuff.GSS2++;
1621     if (!locked) {
1622         h_Lock_r(hostp);
1623     }
1624     ClearHostCallbacks_r(hostp, 1 /*already locked */ );
1625     if (!locked) {
1626         h_Unlock_r(hostp);
1627     }
1628     return 0;
1629 }
1630
1631 /* locked - set if caller has already locked the host */
1632 static int
1633 ClearHostCallbacks_r(struct host *hp, int locked)
1634 {
1635     int code;
1636     int held = 0;
1637     char hoststr[16];
1638
1639     ViceLog(5,
1640             ("GSS: Delete longest inactive host %s\n",
1641              afs_inet_ntoa_r(hp->host, hoststr)));
1642     if (!(held = h_Held_r(hp)))
1643         h_Hold_r(hp);
1644
1645     /** Try a non-blocking lock. If the lock is already held return
1646       * after releasing hold on hp
1647       */
1648     if (!locked) {
1649         if (h_NBLock_r(hp)) {
1650             if (!held)
1651                 h_Release_r(hp);
1652             return 1;
1653         }
1654     }
1655     if (hp->Console & 2) {
1656         /*
1657          * If the special console field is set it means that a thread
1658          * is waiting in AddCallBack1 after it set pointers to the
1659          * file entry and/or callback entry. Because of the bogus
1660          * usage of h_hold it won't prevent from another thread, this
1661          * one, to remove all the callbacks so just to be safe we keep
1662          * a reference. NOTE, on the last phase we'll free the calling
1663          * host's callbacks but that's ok...
1664          */
1665         cbstuff.GSS5++;
1666     }
1667     DeleteAllCallBacks_r(hp, 1);
1668     if (hp->hostFlags & VENUSDOWN) {
1669         hp->hostFlags &= ~RESETDONE;    /* remember that we must do a reset */
1670     } else {
1671         /* host is up, try a call */
1672         hp->hostFlags &= ~ALTADDR;      /* alternate addresses are invalid */
1673         if (hp->interface) {
1674             H_UNLOCK;
1675             code =
1676                 RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1677             H_LOCK;
1678         } else {
1679             H_UNLOCK;
1680             code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1681             H_LOCK;
1682         }
1683         hp->hostFlags |= ALTADDR;       /* alternate addresses are valid */
1684         if (code) {
1685             /* failed, mark host down and need reset */
1686             hp->hostFlags |= VENUSDOWN;
1687             hp->hostFlags &= ~RESETDONE;
1688         } else {
1689             /* reset succeeded, we're done */
1690             hp->hostFlags |= RESETDONE;
1691         }
1692     }
1693     if (!locked) {
1694         h_Unlock_r(hp);
1695     }
1696     if (!held)
1697         h_Release_r(hp);
1698
1699     return 0;
1700 }
1701 #endif /* INTERPRET_DUMP */
1702
1703
1704 int
1705 PrintCallBackStats(void)
1706 {
1707     fprintf(stderr,
1708             "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1709             cbstuff.AddCallBacks, cbstuff.BreakCallBacks,
1710             cbstuff.DeleteCallBacks, cbstuff.DeleteFiles, cbstuff.CBsTimedOut,
1711             cbstuff.GotSomeSpaces, cbstuff.DeleteAllCallBacks);
1712     fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1713             cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs + cbstuff.nFEs,
1714             cbstuff.nblks);
1715
1716     return 0;
1717 }
1718
1719 #define MAGIC 0x12345678        /* To check byte ordering of dump when it is read in */
1720
1721 #ifndef INTERPRET_DUMP
1722
1723 int
1724 DumpCallBackState(void)
1725 {
1726     int fd;
1727     afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1728
1729     fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY | O_CREAT | O_TRUNC,
1730               0666);
1731     if (fd < 0) {
1732         ViceLog(0,
1733                 ("Couldn't create callback dump file %s\n",
1734                  AFSDIR_SERVER_CBKDUMP_FILEPATH));
1735         return 0;
1736     }
1737     (void)write(fd, &magic, sizeof(magic));
1738     (void)write(fd, &now, sizeof(now));
1739     (void)write(fd, &cbstuff, sizeof(cbstuff));
1740     (void)write(fd, TimeOuts, sizeof(TimeOuts));
1741     (void)write(fd, timeout, sizeof(timeout));
1742     (void)write(fd, &tfirst, sizeof(tfirst));
1743     freelisthead = cbtoi((struct CallBack *)CBfree);
1744     (void)write(fd, &freelisthead, sizeof(freelisthead));       /* This is a pointer */
1745     freelisthead = fetoi((struct FileEntry *)FEfree);
1746     (void)write(fd, &freelisthead, sizeof(freelisthead));       /* This is a pointer */
1747     (void)write(fd, HashTable, sizeof(HashTable));
1748     (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks);     /* CB stuff */
1749     (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks);     /* FE stuff */
1750     close(fd);
1751
1752     return 0;
1753 }
1754
1755 #endif
1756
1757 #ifdef INTERPRET_DUMP
1758
1759 /* This is only compiled in for the callback analyzer program */
1760 /* Returns the time of the dump */
1761 time_t
1762 ReadDump(char *file)
1763 {
1764     int fd;
1765     afs_uint32 magic, freelisthead;
1766     time_t now;
1767
1768     fd = open(file, O_RDONLY);
1769     if (fd < 0) {
1770         fprintf(stderr, "Couldn't read dump file %s\n", file);
1771         exit(1);
1772     }
1773     read(fd, &magic, sizeof(magic));
1774     if (magic != MAGIC) {
1775         fprintf(stderr,
1776                 "Magic number of %s is invalid.  You might be trying to\n",
1777                 file);
1778         fprintf(stderr,
1779                 "run this program on a machine type with a different byte ordering.\n");
1780         exit(1);
1781     }
1782     read(fd, &now, sizeof(now));
1783     read(fd, &cbstuff, sizeof(cbstuff));
1784     read(fd, TimeOuts, sizeof(TimeOuts));
1785     read(fd, timeout, sizeof(timeout));
1786     read(fd, &tfirst, sizeof(tfirst));
1787     read(fd, &freelisthead, sizeof(freelisthead));
1788     CB = ((struct CallBack
1789            *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1790     FE = ((struct FileEntry
1791            *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1792     CBfree = (struct CallBack *)itocb(freelisthead);
1793     read(fd, &freelisthead, sizeof(freelisthead));
1794     FEfree = (struct FileEntry *)itofe(freelisthead);
1795     read(fd, HashTable, sizeof(HashTable));
1796     read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks);    /* CB stuff */
1797     read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks);    /* FE stuff */
1798     if (close(fd)) {
1799         perror("Error reading dumpfile");
1800         exit(1);
1801     }
1802     return now;
1803 }
1804
1805 #include "AFS_component_version_number.c"
1806
1807 int
1808 main(int argc, char **argv)
1809 {
1810     int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1811     static AFSFid fid;
1812     register struct FileEntry *fe;
1813     register struct CallBack *cb;
1814     time_t now;
1815
1816     memset(&fid, 0, sizeof(fid));
1817     argc--;
1818     argv++;
1819     while (argc && **argv == '-') {
1820         noptions++;
1821         argc--;
1822         if (!strcmp(*argv, "-host")) {
1823             if (argc < 1) {
1824                 err++;
1825                 break;
1826             }
1827             argc--;
1828             cbi = atoi(*++argv);
1829         } else if (!strcmp(*argv, "-fid")) {
1830             if (argc < 2) {
1831                 err++;
1832                 break;
1833             }
1834             argc -= 3;
1835             fid.Volume = atoi(*++argv);
1836             fid.Vnode = atoi(*++argv);
1837             fid.Unique = atoi(*++argv);
1838         } else if (!strcmp(*argv, "-time")) {
1839             fprintf(stderr, "-time not supported\n");
1840             exit(1);
1841         } else if (!strcmp(*argv, "-stats")) {
1842             stats = 1;
1843         } else if (!strcmp(*argv, "-all")) {
1844             all = 1;
1845         } else if (!strcmp(*argv, "-raw")) {
1846             raw = 1;
1847         } else if (!strcmp(*argv, "-volume")) {
1848             if (argc < 1) {
1849                 err++;
1850                 break;
1851             }
1852             argc--;
1853             vol = atoi(*++argv);
1854         } else
1855             err++;
1856         argv++;
1857     }
1858     if (err || argc != 1) {
1859         fprintf(stderr,
1860                 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
1861         fprintf(stderr,
1862                 "[cbid is shown for each host in the hosts.dump file]\n");
1863         exit(1);
1864     }
1865     now = ReadDump(*argv);
1866     if (stats || noptions == 0) {
1867         time_t uxtfirst = UXtime(tfirst);
1868         printf("The time of the dump was %u %s", now, ctime(&now));
1869         printf("The last time cleanup ran was %u %s", uxtfirst,
1870                ctime(&uxtfirst));
1871         PrintCallBackStats();
1872     }
1873     if (all || vol) {
1874         register hash;
1875         register afs_uint32 *feip;
1876         register struct CallBack *cb;
1877         register struct FileEntry *fe;
1878
1879         for (hash = 0; hash < VHASH; hash++) {
1880             for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1881                 if (!vol || (fe->volid == vol)) {
1882                     register struct CallBack *cbnext;
1883                     for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1884                         PrintCB(cb, now);
1885                         cbnext = itocb(cb->cnext);
1886                     }
1887                     *feip = fe->fnext;
1888                 } else {
1889                     feip = &fe->fnext;
1890                 }
1891             }
1892         }
1893     }
1894     if (cbi) {
1895         afs_uint32 cfirst = cbi;
1896         do {
1897             cb = itocb(cbi);
1898             PrintCB(cb, now);
1899             cbi = cb->hnext;
1900         } while (cbi != cfirst);
1901     }
1902     if (fid.Volume) {
1903         fe = FindFE(&fid);
1904         if (!fe) {
1905             printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1906             exit(1);
1907         }
1908         cb = itocb(fe->firstcb);
1909         while (cb) {
1910             PrintCB(cb, now);
1911             cb = itocb(cb->cnext);
1912         }
1913     }
1914     if (raw) {
1915         struct FileEntry *fe;
1916         afs_int32 *p, i;
1917         for (i = 1; i < cbstuff.nblks; i++) {
1918             p = (afs_int32 *) & FE[i];
1919             printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1920         }
1921     }
1922 }
1923
1924 int
1925 PrintCB(register struct CallBack *cb, afs_uint32 now)
1926 {
1927     struct FileEntry *fe = itofe(cb->fhead);
1928     time_t expires = TIndexToTime(cb->thead);
1929
1930     printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1931            fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
1932            expires - now, ctime(&expires));
1933 }
1934
1935 #endif
1936
1937 #if     !defined(INTERPRET_DUMP)
1938 /*
1939 ** try breaking calbacks on afidp from host. Use multi_rx.
1940 ** return 0 on success, non-zero on failure
1941 */
1942 int
1943 MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1944 {
1945     int retVal;
1946     H_LOCK;
1947     retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1948     H_UNLOCK;
1949     return retVal;
1950 }
1951
1952 int
1953 MultiBreakCallBackAlternateAddress_r(struct host *host,
1954                                      struct AFSCBFids *afidp)
1955 {
1956     int i, j;
1957     struct rx_connection **conns;
1958     struct rx_connection *connSuccess = 0;
1959     afs_int32 *addr;
1960     static struct rx_securityClass *sc = 0;
1961     static struct AFSCBs tc = { 0, 0 };
1962     char hoststr[16];
1963
1964     /* nothing more can be done */
1965     if (!host->interface)
1966         return 1;               /* failure */
1967
1968     assert(host->interface->numberOfInterfaces > 0);
1969
1970     /* the only address is the primary interface */
1971     if (host->interface->numberOfInterfaces == 1)
1972         return 1;               /* failure */
1973
1974     /* initialise a security object only once */
1975     if (!sc)
1976         sc = rxnull_NewClientSecurityObject();
1977
1978     i = host->interface->numberOfInterfaces;
1979     addr = calloc(i, sizeof(afs_int32));
1980     conns = calloc(i, sizeof(struct rx_connection *));
1981     if (!addr || !conns) {
1982         ViceLog(0,
1983                 ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
1984         assert(0);
1985     }
1986
1987     /* initialize alternate rx connections */
1988     for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
1989         /* this is the current primary address */
1990         if (host->host == host->interface->addr[i])
1991             continue;
1992
1993         addr[j] = host->interface->addr[i];
1994         conns[j] =
1995             rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
1996         rx_SetConnDeadTime(conns[j], 2);
1997         rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1998         j++;
1999     }
2000
2001     assert(j);                  /* at least one alternate address */
2002     ViceLog(125,
2003             ("Starting multibreakcall back on all addr for host %s\n",
2004              afs_inet_ntoa_r(host->host, hoststr)));
2005     H_UNLOCK;
2006     multi_Rx(conns, j) {
2007         multi_RXAFSCB_CallBack(afidp, &tc);
2008         if (!multi_error) {
2009             /* first success */
2010             H_LOCK;
2011             if (host->callback_rxcon)
2012                 rx_DestroyConnection(host->callback_rxcon);
2013             host->callback_rxcon = conns[multi_i];
2014             host->host = addr[multi_i];
2015             connSuccess = conns[multi_i];
2016             rx_SetConnDeadTime(host->callback_rxcon, 50);
2017             rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2018             ViceLog(125,
2019                     ("multibreakcall success with addr %s\n",
2020                      afs_inet_ntoa_r(addr[multi_i], hoststr)));
2021             H_UNLOCK;
2022             multi_Abort;
2023         }
2024     }
2025     multi_End_Ignore;
2026     H_LOCK;
2027     /* Destroy all connections except the one on which we succeeded */
2028     for (i = 0; i < j; i++)
2029         if (conns[i] != connSuccess)
2030             rx_DestroyConnection(conns[i]);
2031
2032     free(addr);
2033     free(conns);
2034
2035     if (connSuccess)
2036         return 0;               /* success */
2037     else
2038         return 1;               /* failure */
2039 }
2040
2041
2042 /*
2043 ** try multiRX probes to host. 
2044 ** return 0 on success, non-zero on failure
2045 */
2046 int
2047 MultiProbeAlternateAddress_r(struct host *host)
2048 {
2049     int i, j;
2050     struct rx_connection **conns;
2051     struct rx_connection *connSuccess = 0;
2052     afs_int32 *addr;
2053     static struct rx_securityClass *sc = 0;
2054     char hoststr[16];
2055
2056     /* nothing more can be done */
2057     if (!host->interface)
2058         return 1;               /* failure */
2059
2060     assert(host->interface->numberOfInterfaces > 0);
2061
2062     /* the only address is the primary interface */
2063     if (host->interface->numberOfInterfaces == 1)
2064         return 1;               /* failure */
2065
2066     /* initialise a security object only once */
2067     if (!sc)
2068         sc = rxnull_NewClientSecurityObject();
2069
2070     i = host->interface->numberOfInterfaces;
2071     addr = calloc(i, sizeof(afs_int32));
2072     conns = calloc(i, sizeof(struct rx_connection *));
2073     if (!addr || !conns) {
2074         ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
2075         assert(0);
2076     }
2077
2078     /* initialize alternate rx connections */
2079     for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2080         /* this is the current primary address */
2081         if (host->host == host->interface->addr[i])
2082             continue;
2083
2084         addr[j] = host->interface->addr[i];
2085         conns[j] =
2086             rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
2087         rx_SetConnDeadTime(conns[j], 2);
2088         rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2089         j++;
2090     }
2091
2092     assert(j);                  /* at least one alternate address */
2093     ViceLog(125,
2094             ("Starting multiprobe on all addr for host %s\n",
2095              afs_inet_ntoa_r(host->host, hoststr)));
2096     H_UNLOCK;
2097     multi_Rx(conns, j) {
2098         multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2099         if (!multi_error) {
2100             /* first success */
2101             H_LOCK;
2102             if (host->callback_rxcon)
2103                 rx_DestroyConnection(host->callback_rxcon);
2104             host->callback_rxcon = conns[multi_i];
2105             host->host = addr[multi_i];
2106             connSuccess = conns[multi_i];
2107             rx_SetConnDeadTime(host->callback_rxcon, 50);
2108             rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2109             ViceLog(125,
2110                     ("multiprobe success with addr %s\n",
2111                      afs_inet_ntoa_r(addr[multi_i], hoststr)));
2112             H_UNLOCK;
2113             multi_Abort;
2114         }
2115     }
2116     multi_End_Ignore;
2117     H_LOCK;
2118     /* Destroy all connections except the one on which we succeeded */
2119     for (i = 0; i < j; i++)
2120         if (conns[i] != connSuccess)
2121             rx_DestroyConnection(conns[i]);
2122
2123     free(addr);
2124     free(conns);
2125
2126     if (connSuccess)
2127         return 0;               /* success */
2128     else
2129         return 1;               /* failure */
2130 }
2131
2132 #endif /* !defined(INTERPRET_DUMP) */