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