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