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