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