pull-prototypes-to-head-20020821
[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("$Header$");
86
87 #include <stdio.h> 
88 #include <stdlib.h>      /* for malloc() */
89 #include <time.h>        /* ANSI standard location for time stuff */
90 #ifdef AFS_NT40_ENV
91 #include <fcntl.h>
92 #include <io.h>
93 #else
94 #include <sys/time.h>
95 #include <sys/file.h>
96 #endif
97 #ifdef HAVE_STRING_H
98 #include <string.h>
99 #else
100 #ifdef HAVE_STRINGS_H
101 #include <strings.h>
102 #endif
103 #endif
104 #include <afs/assert.h>
105
106 #include <afs/stds.h>
107
108 #include <afs/nfs.h>   /* yuck.  This is an abomination. */
109 #include <lwp.h>
110 #include <rx/rx.h>
111 #include <afs/afscbint.h>
112 #include <afs/afsutil.h>
113 #include <lock.h>
114 #include <afs/ihandle.h>
115 #include <afs/vnode.h>
116 #include <afs/volume.h>
117 #include "viced.h"
118
119 #include <afs/ptclient.h>  /* need definition of prlist for host.h */
120 #include "host.h"
121
122
123 extern int hostCount;
124 int ShowProblems = 1;
125
126 /* Maximum number of call backs to break at once, single fid */
127 /* There is some debate as to just how large this value should be */
128 /* Ideally, it would be very very large, but I am afraid that the */
129 /* cache managers will all send in their responses simultaneously, */
130 /* thereby swamping the file server.  As a result, something like */
131 /* 10 or 15 might be a better bet. */
132 #define MAX_CB_HOSTS    10
133
134 /* max time to break a callback, otherwise client is dead or net is hosed */
135 #define MAXCBT 25  
136
137 #define u_short unsigned short
138 #define u_byte  unsigned char
139
140 struct cbcounters cbstuff;
141
142 struct cbstruct {
143   struct host * hp;
144   u_short thead;
145 } ;
146
147 struct FileEntry {
148     afs_uint32      vnode;      /* XXX This was u_short XXX */
149     afs_uint32         unique;
150     afs_uint32      volid;
151     u_short         fnext;
152     u_short         ncbs;
153     u_short         firstcb;
154     u_short         spare;
155 #if defined(AFS_ALPHA_ENV) || defined(AFS_ALPHA_LINUX20_ENV)
156     u_short         spare1;
157     u_short         spare2;
158 #endif
159 } *FE;  /* Don't use FE[0] */
160
161 struct CallBack {
162     u_short         cnext;              /* Next call back entry */
163     u_short         fhead;              /* Head of this call back chain */
164     u_byte          thead;              /* Head of timeout chain */
165     u_byte          status;             /* Call back status; see definitions, below */
166     u_short         hhead;              /* Head of host table chain */
167     u_short         tprev, tnext;       /* Timeout chain */
168     u_short         hprev, hnext;       /* Chain from host table */
169 } *CB;  /* Don't use CB[0] */
170
171 /* status bits 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 u_short 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 CallBack *CBfree = 0;
269 struct FileEntry *FEfree = 0;
270
271 static struct CallBack *iGetCB(register int *nused);
272 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
273 static struct FileEntry *iGetFE(register int *nused);
274 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
275 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
276 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
277
278 #define VHASH 512       /* Power of 2 */
279 static u_short HashTable[VHASH]; /* File entry hash table */
280 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
281
282 static struct FileEntry *FindFE (fid)
283     register AFSFid *fid;
284
285 {
286     int hash;
287     register fei;
288     register struct FileEntry *fe;
289
290     hash = VHash(fid->Volume, fid->Unique);
291     for (fei=HashTable[hash]; fei; fei = fe->fnext) {
292         fe = itofe(fei);
293         if (fe->volid == fid->Volume && fe->unique == fid->Unique &&
294             fe->vnode == fid->Vnode) 
295             return fe;
296     }
297     return 0;
298
299 } /*FindFE*/
300
301
302 #ifndef INTERPRET_DUMP
303
304 extern void ShutDown();
305 static CDelPtr(), FDel(), AddCallback1(), GetSomeSpace_r(); 
306
307 static struct CallBack *iGetCB(register int *nused)
308 {
309     register struct CallBack *ret;
310
311     if ((ret = CBfree)) {
312         CBfree = (struct CallBack *)(((struct object *)ret)->next);
313         (*nused)++;
314     }
315     return ret;
316
317 } /*cb_GetCB*/
318
319
320 static iFreeCB(cb, nused)
321     register struct CallBack *cb;
322     register int *nused;
323
324 {
325     ((struct object *)cb)->next = (struct object *)CBfree;
326     CBfree = cb;
327     (*nused)--;
328 } /*FreeCB*/
329
330
331 static struct FileEntry *iGetFE(register int *nused)
332 {
333     register struct FileEntry *ret;
334
335     if ((ret = FEfree)) {
336         FEfree = (struct FileEntry *)(((struct object *)ret)->next);
337         (*nused)++;
338     }
339     return ret;
340
341 } /*cb_GetFE*/
342
343
344 static iFreeFE(fe, nused)
345     register struct FileEntry *fe;
346     register int *nused;
347
348 {
349     ((struct object *)fe)->next = (struct object *)FEfree;
350     FEfree = fe;
351     (*nused)--;
352 } /*FreeFE*/
353
354
355 /* Add cb to end of specified timeout list */
356 static TAdd(cb, thead)
357     register struct CallBack *cb;
358     register u_short *thead;
359
360 {
361     if (!*thead) {
362         (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
363     } else {
364         register struct CallBack *thp = itocb(*thead);
365
366         cb->tprev = thp->tprev;
367         cb->tnext = *thead;
368         if (thp) {
369           if (thp->tprev) 
370             thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
371           else 
372             thp->tprev = cbtoi(cb);
373         }
374     }
375     cb->thead = ttoi(thead);
376
377 } /*TAdd*/
378
379
380 /* Delete call back entry from timeout list */
381 static TDel(cb)
382     register struct CallBack *cb;
383
384 {
385     register u_short *thead = itot(cb->thead);
386
387     if (*thead == cbtoi(cb))
388         *thead = (*thead == cb->tnext? 0: cb->tnext);
389     if (itocb(cb->tprev)) 
390       itocb(cb->tprev)->tnext = cb->tnext;
391     if (itocb(cb->tnext)) 
392       itocb(cb->tnext)->tprev = cb->tprev;
393
394 } /*TDel*/
395
396
397 /* Add cb to end of specified host list */
398 static HAdd(cb, host)
399     register struct CallBack *cb;
400     register struct host *host;
401
402 {
403     cb->hhead = h_htoi(host);
404     if (!host->cblist) {
405         host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
406     }
407     else {
408         register struct CallBack *hhp = itocb(host->cblist);
409
410         cb->hprev = hhp->hprev;
411         cb->hnext = host->cblist;
412         hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
413     }
414
415 } /*HAdd*/
416
417
418 /* Delete call back entry from host list */
419 static HDel(cb)
420     register struct CallBack *cb;
421
422 {
423     register u_short *hhead = &h_itoh(cb->hhead)->cblist;
424
425     if (*hhead == cbtoi(cb))
426         *hhead = (*hhead == cb->hnext? 0: cb->hnext);
427     itocb(cb->hprev)->hnext = cb->hnext;
428     itocb(cb->hnext)->hprev = cb->hprev;
429
430 } /*HDel*/
431
432
433 /* Delete call back entry from fid's chain of cb's */
434 /* N.B.  This one also deletes the CB, and also possibly parent FE, so
435  * make sure that it is not on any other list before calling this
436  * routine */
437 static CDel(cb)
438     struct CallBack *cb;
439
440 {
441     int cbi = cbtoi(cb);
442     struct FileEntry *fe = itofe(cb->fhead);
443     register u_short *cbp;
444     register int safety;
445
446     for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi; 
447          cbp = &itocb(*cbp)->cnext, safety++) {
448       if (safety > cbstuff.nblks + 10) {
449         assert(0);
450         ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
451         DumpCallBackState();
452         ShutDown();
453       }
454     }
455     CDelPtr(fe, cbp);
456
457 } /*CDel*/
458
459
460 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
461  * as well as file entry */
462 /* N.B.  This one also deletes the CB, and also possibly parent FE, so
463  * make sure that it is not on any other list before calling this
464  * routine */
465 int Ccdelpt=0, CcdelB=0;
466
467 static CDelPtr(fe, cbp)
468     register struct FileEntry *fe;
469     register u_short *cbp;
470
471 {
472     register struct CallBack *cb;
473
474     if (!*cbp)
475         return;
476     Ccdelpt++;
477     cb = itocb(*cbp);
478     if (cb != &CB[*cbp]) 
479         CcdelB++;
480     *cbp = cb->cnext;
481     FreeCB(cb);
482     if (--fe->ncbs == 0)
483         FDel(fe);
484
485 } /*CDelPtr*/
486
487
488 static u_short *FindCBPtr(fe, host)
489     struct FileEntry *fe;
490     struct host *host;
491
492 {
493     register afs_uint32 hostindex = h_htoi(host);
494     register struct CallBack *cb;
495     register u_short *cbp;
496     register int safety;
497
498     for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
499         if (safety > cbstuff.nblks) {
500           ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
501           DumpCallBackState();
502           ShutDown();
503         }
504         cb = itocb(*cbp);
505         if (cb->hhead == hostindex)
506             break;
507     }
508     return cbp;
509
510 } /*FindCBPtr*/
511
512
513
514 /* Delete file entry from hash table */
515 static FDel(fe)
516     register struct FileEntry *fe;
517
518 {
519     register int fei = fetoi(fe);
520     register unsigned short *p = &HashTable[VHash(fe->volid, fe->unique)];
521
522     while (*p && *p != fei)
523         p = &itofe(*p)->fnext;
524     assert(*p);
525     *p = fe->fnext;
526     FreeFE(fe);
527
528 } /*FDel*/
529
530
531
532 InitCallBack(nblks)
533     int nblks;
534 {
535
536     H_LOCK
537     tfirst = CBtime(FT_ApproxTime());
538     /* N.B. FE's, CB's share same free list.  If the sizes of either change,
539       FE and CB will have to be separated.  The "-1", below, is because
540       FE[0] and CB[0] are not used--and not allocated */
541     FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*nblks)))-1;
542     cbstuff.nFEs = nblks;
543     while (cbstuff.nFEs)
544         FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
545     CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
546     cbstuff.nCBs = nblks;
547     while (cbstuff.nCBs)
548         FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
549     cbstuff.nblks = nblks;
550     cbstuff.nbreakers = 0;
551     H_UNLOCK
552
553 } /*InitCallBack*/
554
555
556 afs_int32 XCallBackBulk_r(ahost, fids, nfids)
557     struct host *ahost;
558     struct AFSFid *fids;
559     afs_int32 nfids;
560
561 {
562     struct AFSCallBack tcbs[AFSCBMAX];
563     register int i;
564     struct AFSCBFids tf;
565     struct AFSCBs tc;
566     int code;
567     int j;
568
569 #ifdef  ADAPT_MTU
570     rx_SetConnDeadTime(ahost->callback_rxcon, 4); 
571     rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
572 #endif
573
574     code = 0;
575     j = 0;
576     while (nfids > 0) {
577
578       for(i=0;i<nfids && i < AFSCBMAX;i++) {
579         tcbs[i].CallBackVersion = CALLBACK_VERSION;
580         tcbs[i].ExpirationTime = 0;
581         tcbs[i].CallBackType = CB_DROPPED;
582       }
583       tf.AFSCBFids_len = i;
584       tf.AFSCBFids_val = &(fids[j]);
585       nfids -= i;
586       j += i;
587       tc.AFSCBs_len = i;
588       tc.AFSCBs_val = tcbs;
589
590       H_UNLOCK
591       code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
592       H_LOCK
593     }
594
595     return code;
596 } /*XCallBackBulk*/
597
598
599 /* the locked flag tells us if the host entry has already been locked 
600  * by our parent.  I don't think anybody actually calls us with the
601  * host locked, but here's how to make that work:  GetSomeSpace has to
602  * change so that it doesn't attempt to lock any hosts < "host".  That
603  * means that it might be unable to free any objects, so it has to
604  * return an exit status.  If it fails, then AddCallBack1 might fail,
605  * as well. If so, the host->ResetDone should probably be set to 0,
606  * and we probably don't want to return a callback promise to the
607  * cache manager, either. */
608 int
609 AddCallBack1(host, fid, thead, type, locked)
610     struct host *host;
611     AFSFid *fid;
612     int locked;
613     int type;
614     u_short *thead;
615 {
616     int retVal;
617     H_LOCK
618     if ( !locked ) {
619         h_Lock_r(host);
620     }
621     retVal = AddCallBack1_r(host, fid, thead, type, 1);
622
623     if ( !locked ) {
624         h_Unlock_r(host);
625     }
626     H_UNLOCK
627     return retVal;
628 }
629
630 static int
631 AddCallBack1_r(host, fid, thead, type, locked)
632     struct host *host;
633     AFSFid *fid;
634     int locked;
635     int type;
636     u_short *thead;
637 {
638     struct FileEntry *fe;
639     struct CallBack *cb = 0, *lastcb = 0;
640     struct FileEntry *newfe = 0;
641     afs_uint32 time_out;
642     u_short *Thead = thead;
643     struct CallBack *newcb = 0;
644     int safety;
645     
646     host->Console |= 2;
647
648     /* allocate these guys first, since we can't call the allocator with
649        the host structure locked -- or we might deadlock. However, we have 
650        to avoid races with FindFE... */
651     while (!(newcb = GetCB())) {
652         GetSomeSpace_r(host, locked);
653     }
654     while(!(newfe = GetFE())) {  /* Get it now, so we don't have to call */
655       /* GetSomeSpace with the host locked, later.  This might turn out to */
656       /* have been unneccessary, but that's actually kind of unlikely, since */
657       /* most files are not shared. */
658       GetSomeSpace_r(host, locked);
659     }
660
661     if (!locked) {
662       h_Lock_r(host);  /* this can yield, so do it before we get any */
663                      /* fragile info */
664     }
665
666     fe = FindFE(fid);
667     if (type == CB_NORMAL) {
668         time_out = TimeCeiling(FT_ApproxTime()+TimeOut(fe?fe->ncbs:0)+ServerBias);
669         Thead = THead(CBtime(time_out));
670     }
671     else if (type == CB_VOLUME) {
672         time_out = TimeCeiling((60*120+FT_ApproxTime())+ServerBias);
673         Thead = THead(CBtime(time_out));
674     }
675     else if (type == CB_BULK) {
676       /* bulk status can get so many callbacks all at once, and most of them
677        * are probably not for things that will be used for long.
678        */
679         time_out = TimeCeiling(FT_ApproxTime() + ServerBias 
680                                + TimeOut(22 + (fe?fe->ncbs:0)));
681         Thead = THead(CBtime(time_out));
682     }
683
684     host->Console &= ~2;
685
686     if (!fe) {
687         register afs_uint32 hash;
688
689         fe = newfe;
690         newfe = NULL;
691         fe->firstcb = 0;
692         fe->volid = fid->Volume;
693         fe->vnode = fid->Vnode;
694         fe->unique = fid->Unique;
695         fe->ncbs = 0;
696         hash = VHash(fid->Volume, fid->Unique);
697         fe->fnext = HashTable[hash];
698         HashTable[hash] = fetoi(fe);
699     }
700     for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
701          lastcb = cb, cb = itocb(cb->cnext), safety++) {
702         if (safety > cbstuff.nblks) {
703           ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
704           DumpCallBackState();
705           ShutDown();
706         }
707         if (cb->hhead == h_htoi(host))
708             break;
709     }
710     if (cb) {/* Already have call back:  move to new timeout list */
711         /* don't change delayed callbacks back to normal ones */
712         if (cb->status != CB_DELAYED)
713             cb->status = type;
714         /* Only move if new timeout is longer */
715         if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
716             TDel(cb);
717             TAdd(cb, Thead);
718         }
719     } else {
720         cb = newcb;
721         newcb = NULL;
722         *(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
723         fe->ncbs++;
724         cb->cnext = 0;
725         cb->fhead = fetoi(fe);
726         cb->status = type;
727         HAdd(cb, host);
728         TAdd(cb, Thead);
729     }
730
731     /* now free any still-unused callback or host entries */
732     if (newcb) FreeCB(newcb);
733     if (newfe) FreeFE(newfe);
734
735     if (!locked)         /* freecb and freefe might(?) yield */
736         h_Unlock_r(host);
737
738     if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK ) 
739         return time_out-ServerBias; /* Expires sooner at workstation */
740
741 return 0;
742 } /*AddCallBack1*/
743
744
745 /* Take an array full of hosts, all held.  Break callbacks to them, and 
746  * release the holds once you're done, except don't release xhost.  xhost 
747  * may be NULL.  Currently only works for a single Fid in afidp array.
748  * If you want to make this work with multiple fids, you need to fix
749  * the error handling.  One approach would be to force a reset if a
750  * multi-fid call fails, or you could add delayed callbacks for each
751  * fid.   You probably also need to sort and remove duplicate hosts.
752  * When this is called from the BreakVolumeCallBacks path, it does NOT 
753  * force a reset if the RPC fails, it just marks the host down and tries 
754  * to create a delayed callback. */
755 /* N.B.  be sure that code works when ncbas == 0 */
756 /* N.B.  requires all the cba[*].hp pointers to be valid... */
757 /* This routine does not hold a lock on the host for the duration of 
758  * the BreakCallBack RPC, which is a significant deviation from tradition.
759  * It _does_ get a lock on the host before setting VenusDown = 1,
760  * which is sufficient only if VenusDown = 0 only happens when the
761  * lock is held over the RPC and the subsequent VenusDown == 0
762  * wherever that is done. */
763 static void MultiBreakCallBack_r(cba, ncbas, afidp, xhost)
764      struct cbstruct cba[];
765      int ncbas;
766      struct AFSCBFids *afidp;
767      struct host * xhost;
768 {
769   int i,j;
770   struct rx_connection *conns[MAX_CB_HOSTS];
771   int opt_TO;  /* secs, but internal adaptive parms are in ms */
772   static struct AFSCBs tc = {0,0};
773
774   assert(ncbas <= MAX_CB_HOSTS);
775
776   /* set up conns for multi-call */
777   for (i=0,j=0; i<ncbas; i++) {
778     struct host *thishost = cba[i].hp;
779     if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
780       continue;
781     }
782     conns[j++] = thishost->callback_rxcon;
783         
784 #ifdef  ADAPT_MTU
785     rx_SetConnDeadTime (thishost->callback_rxcon, 4); 
786     rx_SetConnHardDeadTime (thishost->callback_rxcon, AFS_HARDDEADTIME); 
787 #endif
788   }
789   
790   if (j) {            /* who knows what multi would do with 0 conns? */
791     cbstuff.nbreakers++;
792   H_UNLOCK
793   multi_Rx(conns, j) {
794     multi_RXAFSCB_CallBack(afidp, &tc);
795     if (multi_error) {
796       unsigned short idx ;
797       struct host *hp;
798       char hoststr[16];
799
800       idx = 0;
801       /* If there's an error, we have to hunt for the right host. 
802        * The conns array _should_ correspond one-to-one to the cba
803        * array, except in some rare cases it might be missing one 
804        * or more elements.  So the optimistic case is almost 
805        * always right.  At worst, it's the starting point for the 
806        * hunt. */
807       for (hp=0,i=multi_i;i<j;i++) { 
808         hp = cba[i].hp;   /* optimistic, but usually right */
809         if (!hp) {
810           break;
811         }
812         if (conns[multi_i] == hp->callback_rxcon) {
813           idx = cba[i].thead;
814           break;
815         }
816       }
817       
818       if (!hp) {
819         ViceLog(0, ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n",hp,cba));
820       }
821       else {
822         /* 
823         ** try breaking callbacks on alternate interface addresses
824         */
825         if ( MultiBreakCallBackAlternateAddress(hp, afidp) )
826         {
827           if (ShowProblems) {
828                 ViceLog(7, 
829                   ("BCB: Failed on file %u.%d.%d, host %s:%d is down\n",
830                    afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
831                    afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), hp->port));
832                 }
833
834                 H_LOCK
835                 h_Lock_r(hp);
836                 hp->hostFlags |= VENUSDOWN;
837                 /**
838                   * We always go into AddCallBack1_r with the host locked
839                   */
840                 AddCallBack1_r(hp,afidp->AFSCBFids_val,itot(idx), CB_DELAYED, 1);
841                 h_Unlock_r(hp);
842                 H_UNLOCK
843         }
844       }
845     }
846   } multi_End;
847   H_LOCK
848   cbstuff.nbreakers--;
849   }
850   
851   for (i=0; i<ncbas; i++) {
852     struct host *hp;
853     hp = cba[i].hp;
854     if (hp && xhost != hp)
855       h_Release_r(hp);
856   }
857
858 return ;
859 }
860
861 /*
862  * Break all call backs for fid, except for the specified host (unless flag
863  * is true, in which case all get a callback message. Assumption: the specified
864  * host is h_Held, by the caller; the others aren't.
865  * Specified host may be bogus, that's ok.  This used to check to see if the 
866  * host was down in two places, once right after the host was h_held, and 
867  * again after it was locked.  That race condition is incredibly rare and
868  * relatively harmless even when it does occur, so we don't check for it now. 
869  */
870 BreakCallBack(xhost, fid, flag)
871     struct host *xhost;
872     int flag;  /* if flag is true, send a break callback msg to "host", too */
873     AFSFid *fid;
874 {
875     struct FileEntry *fe;
876     struct CallBack *cb, *nextcb;
877     struct cbstruct cba[MAX_CB_HOSTS];
878     int ncbas;
879     struct rx_connection *conns[MAX_CB_HOSTS];
880     struct AFSCBFids tf;
881     int hostindex;
882     char hoststr[16];
883
884     ViceLog(7,("BCB: BreakCallBack(all but %s:%d, (%u,%d,%d))\n",
885                afs_inet_ntoa_r(xhost->host,hoststr), xhost->port, fid->Volume, fid->Vnode, 
886                fid->Unique));
887
888     H_LOCK
889
890     cbstuff.BreakCallBacks++; 
891     fe = FindFE(fid);
892     if (!fe) {
893       goto done;
894     }
895     hostindex = h_htoi(xhost);
896     cb = itocb(fe->firstcb);
897     if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
898       /* the most common case is what follows the || */
899       goto done;
900     }
901     tf.AFSCBFids_len = 1;
902     tf.AFSCBFids_val = fid;
903
904     for(;cb;) { 
905       for (ncbas=0; cb && ncbas<MAX_CB_HOSTS; cb=nextcb) {
906         nextcb = itocb(cb->cnext);
907         if ((cb->hhead != hostindex || flag) 
908             && (cb->status == CB_BULK || cb->status == CB_NORMAL
909                 || cb->status == CB_VOLUME) ) {
910           struct host *thishost = h_itoh(cb->hhead);
911           if (!thishost) {
912             ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
913           }
914           else if (thishost->hostFlags & VENUSDOWN) {
915             ViceLog(7,("BCB: %s:%d is down; delaying break call back\n",
916                        afs_inet_ntoa_r(thishost->host,hoststr), thishost->port));
917             cb->status = CB_DELAYED;
918           }
919           else {
920             h_Hold_r(thishost);
921             cba[ncbas].hp = thishost;
922             cba[ncbas].thead = cb->thead;
923             ncbas++;
924             TDel(cb);
925             HDel(cb);
926             CDel(cb); /* Usually first; so this delete */
927                       /* is reasonably inexpensive */
928           }
929         }
930       }
931       
932       if (ncbas) {
933         MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
934
935         /* we need to to all these initializations again because MultiBreakCallBack may block */
936         fe = FindFE(fid); 
937         if (!fe) {
938                 goto done;
939         }
940         cb = itocb(fe->firstcb);
941         if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
942                 /* the most common case is what follows the || */
943                 goto done;
944         }
945       }
946     }
947
948   done:
949     H_UNLOCK
950     return;
951 } /*BreakCallBack*/
952
953
954 /* Delete (do not break) single call back for fid */
955 DeleteCallBack(host, fid)
956     struct host *host;
957     AFSFid *fid;
958
959 {
960     register struct FileEntry *fe;
961     register u_short *pcb;
962     char hoststr[16];
963
964     cbstuff.DeleteCallBacks++;
965     
966     H_LOCK
967     h_Lock_r(host);
968     fe = FindFE(fid);
969     if (!fe) {
970         h_Unlock_r(host);
971         H_UNLOCK
972         ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
973             fid->Volume, fid->Vnode, fid->Unique));
974         return;
975     }
976     pcb = FindCBPtr(fe, host);
977     if (!*pcb) {
978         ViceLog(8,("DCB: No call back for host %s:%d, (%u, %d, %d)\n",
979             afs_inet_ntoa_r(host->host,hoststr), host->port, fid->Volume, fid->Vnode, fid->Unique));
980         h_Unlock_r(host);
981         H_UNLOCK
982         return;
983     }
984     HDel(itocb(*pcb));
985     TDel(itocb(*pcb));
986     CDelPtr(fe, pcb);
987     h_Unlock_r(host);
988     H_UNLOCK
989
990 } /*DeleteCallBack*/
991
992
993 /*
994  * Delete (do not break) all call backs for fid.  This call doesn't
995  * set all of the various host locks, but it shouldn't really matter
996  * since we're not adding callbacks, but deleting them.  I'm not sure
997  * why it doesn't set the lock, however; perhaps it should.
998  */
999 DeleteFileCallBacks(fid)
1000     AFSFid *fid;
1001 {
1002     register struct FileEntry *fe;
1003     register struct CallBack *cb;
1004     register afs_uint32 cbi;
1005     register n;
1006
1007     H_LOCK
1008     cbstuff.DeleteFiles++;
1009     fe = FindFE(fid);
1010     if (!fe) {
1011         H_UNLOCK
1012         ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
1013             fid->Volume, fid->Vnode, fid->Unique));
1014         return;
1015     }
1016     for (n=0,cbi = fe->firstcb; cbi; n++) {
1017         cb = itocb(cbi);
1018         cbi = cb->cnext;
1019         TDel(cb);
1020         HDel(cb);
1021         FreeCB(cb);
1022     }
1023     FDel(fe);
1024     H_UNLOCK
1025
1026 } /*DeleteFileCallBacks*/
1027
1028
1029 /* Delete (do not break) all call backs for host.  The host should be
1030  * locked. */
1031 DeleteAllCallBacks(host)
1032     struct host *host;
1033 {
1034     int retVal;
1035     H_LOCK
1036     retVal = DeleteAllCallBacks_r(host);
1037     H_UNLOCK
1038     return retVal;
1039 }
1040
1041 DeleteAllCallBacks_r(host)
1042     struct host *host;
1043 {
1044     register struct CallBack *cb;
1045     register int cbi, first;
1046
1047     cbstuff.DeleteAllCallBacks++;
1048     cbi = first = host->cblist;
1049     if (!cbi) {
1050         ViceLog(8,("DV: no call backs\n"));
1051         return;
1052     }
1053     do {        
1054         cb = itocb(cbi);
1055         cbi = cb->hnext;
1056         TDel(cb);
1057         CDel(cb);
1058     } while (cbi != first);
1059     host->cblist = 0;
1060
1061 } /*DeleteAllCallBacks*/
1062
1063
1064 /*
1065  * Break all delayed call backs for host.  Returns 1 if all call backs
1066  * successfully broken; 0 otherwise.  Assumes host is h_Held and h_Locked.
1067  * Must be called with VenusDown set for this host
1068  */
1069 int BreakDelayedCallBacks(host)
1070     struct host *host;
1071 {
1072     int retVal;
1073     H_LOCK
1074     retVal = BreakDelayedCallBacks_r(host);
1075     H_UNLOCK
1076     return retVal;
1077 }
1078
1079 extern afsUUID FS_HostUUID;
1080
1081 int BreakDelayedCallBacks_r(host)
1082     struct host *host;
1083 {
1084     struct AFSFid fids[AFSCBMAX];
1085     u_short thead[AFSCBMAX];
1086     int cbi, first, nfids;
1087     struct CallBack *cb;
1088     struct interfaceAddr interf;
1089     int code;
1090     char hoststr[16];
1091
1092     cbstuff.nbreakers++;
1093     if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1094         host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1095         if ( host->interface ) {
1096             H_UNLOCK
1097             code = RXAFSCB_InitCallBackState3(host->callback_rxcon,
1098                                               &FS_HostUUID);
1099             H_LOCK
1100         } else {
1101             H_UNLOCK
1102             code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1103             H_LOCK
1104         }
1105         host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1106         if (code) {
1107             if (ShowProblems) {
1108                 ViceLog(0,
1109            ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1110                         afs_inet_ntoa_r(host->host,hoststr), host->port));
1111               }
1112             host->hostFlags |= VENUSDOWN;
1113         }
1114         else {
1115             ViceLog(25,("InitCallBackState success on %s\n",afs_inet_ntoa_r(host->host,hoststr)));
1116             /* reset was done successfully */
1117             host->hostFlags |= RESETDONE;
1118             host->hostFlags &= ~VENUSDOWN;
1119         }
1120     }
1121     else while (!(host->hostFlags & HOSTDELETED)) {
1122         nfids = 0;
1123         host->hostFlags &= ~VENUSDOWN;  /* presume up */
1124         cbi = first = host->cblist;
1125         if (!cbi) 
1126             break;
1127         do {
1128             first = host->cblist;
1129             cb = itocb(cbi);
1130             cbi = cb->hnext;
1131             if (cb->status == CB_DELAYED) {
1132                 register struct FileEntry *fe = itofe(cb->fhead);
1133                 thead[nfids] = cb->thead;
1134                 fids[nfids].Volume = fe->volid;
1135                 fids[nfids].Vnode =  fe->vnode;
1136                 fids[nfids].Unique = fe->unique;
1137                 nfids++;
1138                 HDel(cb);
1139                 TDel(cb);
1140                 CDel(cb);
1141             }
1142         } while (cbi && cbi != first && nfids < AFSCBMAX);
1143
1144         if (nfids==0) {
1145           break;
1146         }
1147
1148         if (XCallBackBulk_r(host, fids, nfids)) {
1149             /* Failed, again:  put them back, probably with old
1150              timeout values */
1151             int i;
1152             if (ShowProblems) {
1153                 ViceLog(0,
1154              ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1155                     afs_inet_ntoa_r(host->host,hoststr), host->port));
1156             }
1157             for (i = 0; i<nfids; i++) {
1158                 if (ShowProblems) {
1159                     ViceLog(0,
1160                     ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1161                                afs_inet_ntoa_r(host->host,hoststr), host->port, 
1162                                fids[i].Volume, fids[i].Vnode, fids[i].Unique));
1163                 }
1164                 /* used to do this:
1165                    AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1166                  * but it turns out to cause too many tricky locking problems.
1167                  * now, if break delayed fails, screw it. */
1168             }
1169             host->hostFlags |= VENUSDOWN; /* Failed */
1170             ClearHostCallbacks_r(host, 1/* locked */);
1171             nfids = 0;
1172             break;
1173         }
1174         if (nfids < AFSCBMAX)
1175             break;
1176     }
1177
1178     cbstuff.nbreakers--;
1179     return (host->hostFlags & VENUSDOWN);
1180
1181 } /*BreakDelayedCallBacks*/
1182
1183
1184 struct VCBParams {
1185   struct cbstruct cba[MAX_CB_HOSTS];  /* re-entrant storage */
1186   unsigned int ncbas;
1187   unsigned short thead;     /* head of timeout queue for youngest callback */
1188   struct AFSFid *fid;
1189 };
1190
1191 /*
1192 ** isheld is 0 if the host is held in h_Enumerate
1193 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1194 */
1195 static int MultiBreakVolumeCallBack_r (host, isheld, parms)
1196   struct host *host;
1197   int isheld;
1198   struct VCBParams *parms;
1199 {
1200     char hoststr[16];
1201
1202     if ( !isheld )
1203         return isheld; /* host is held only by h_Enumerate, do nothing */
1204     if ( host->hostFlags & HOSTDELETED )
1205         return 0; /* host is deleted, release hold */
1206
1207     if (host->hostFlags & VENUSDOWN) {
1208         h_Lock_r(host);
1209         if (host->hostFlags & HOSTDELETED) {
1210             h_Unlock_r(host);
1211             return 0;      /* Release hold */
1212         }
1213         ViceLog(8,("BVCB: volume call back for host %s:%d failed\n",
1214                  afs_inet_ntoa_r(host->host,hoststr),host->port));
1215         if (ShowProblems) {
1216             ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
1217                     afs_inet_ntoa_r(host->host,hoststr), host->port));
1218         }
1219         DeleteAllCallBacks_r(host); /* Delete all callback state rather than
1220                                      attempting to selectively remember to
1221                                      delete the volume callbacks later */
1222         host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1223         h_Unlock_r(host);
1224         return 0; /* release hold */
1225     }
1226     assert(parms->ncbas <= MAX_CB_HOSTS);
1227
1228     /* Do not call MultiBreakCallBack on the current host structure
1229     ** because it would prematurely release the hold on the host
1230     */
1231     if ( parms->ncbas  == MAX_CB_HOSTS ) {
1232       struct AFSCBFids tf;
1233
1234       tf.AFSCBFids_len = 1;
1235       tf.AFSCBFids_val = parms->fid;
1236       
1237                                 /* this releases all the hosts */
1238       MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */);
1239
1240       parms->ncbas = 0;
1241     }  
1242     parms->cba[parms->ncbas].hp = host;
1243     parms->cba[(parms->ncbas)++].thead = parms->thead;
1244     return 1;   /* DON'T release hold, because we still need it. */
1245 }
1246
1247 /*
1248 ** isheld is 0 if the host is held in h_Enumerate
1249 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1250 */
1251 static int MultiBreakVolumeCallBack (host, isheld, parms)
1252   struct host *host;
1253   int isheld;
1254   struct VCBParams *parms;
1255 {
1256     int retval;
1257     H_LOCK
1258     retval = MultiBreakVolumeCallBack_r(host, isheld, parms);
1259     H_UNLOCK
1260     return retval;
1261 }
1262
1263 /*
1264  * Break all call backs on a single volume.  Don't call this with any
1265  * hosts h_held.  Note that this routine clears the callbacks before
1266  * actually breaking them, and that the vnode isn't locked during this
1267  * operation, so that people might see temporary callback loss while
1268  * this function is executing.  It is just a temporary state, however,
1269  * since the callback will be broken later by this same function.
1270  *
1271  * Now uses multi-RX for CallBack RPC.  Note that the
1272  * multiBreakCallBacks routine does not force a reset if the RPC
1273  * fails, unlike the previous version of this routine, but does create
1274  * a delayed callback.  Resets will be forced if the host is
1275  * determined to be down before the RPC is executed.
1276  */
1277 BreakVolumeCallBacks(volume)
1278     afs_uint32 volume;
1279
1280 {
1281     struct AFSFid fid;
1282     int hash;
1283     u_short *feip;
1284     struct CallBack *cb;
1285     struct FileEntry *fe;
1286     struct host *host;
1287     struct VCBParams henumParms;
1288     unsigned short tthead = 0;  /* zero is illegal value */
1289
1290     H_LOCK
1291     fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1292     for (hash=0; hash<VHASH; hash++) {
1293         for (feip = &HashTable[hash]; (fe = itofe(*feip)); ) {
1294             if (fe->volid == volume) {
1295                 register struct CallBack *cbnext;
1296                 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1297                     host = h_itoh(cb->hhead);
1298                     h_Hold_r(host);
1299                     cbnext = itocb(cb->cnext);
1300                     if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1301                       tthead = cb->thead;
1302                     }
1303                     TDel(cb);
1304                     HDel(cb);
1305                     FreeCB(cb);
1306                     /* leave hold for MultiBreakVolumeCallBack to clear */
1307                 }
1308                 *feip = fe->fnext;
1309                 FreeFE(fe);
1310             } else {
1311                 feip = &fe->fnext;
1312             }
1313         }
1314     }
1315
1316     if (!tthead) {
1317       /* didn't find any callbacks, so return right away. */
1318       H_UNLOCK
1319       return 0;
1320     }
1321     henumParms.ncbas = 0;
1322     henumParms.fid = &fid;
1323     henumParms.thead = tthead;
1324     H_UNLOCK
1325     h_Enumerate(MultiBreakVolumeCallBack, (char *) &henumParms);
1326     H_LOCK
1327         
1328     if (henumParms.ncbas) {    /* do left-overs */
1329       struct AFSCBFids tf;
1330       tf.AFSCBFids_len = 1;
1331       tf.AFSCBFids_val = &fid;
1332       
1333       MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1334
1335       henumParms.ncbas = 0;
1336     }  
1337     H_UNLOCK
1338
1339 return 0;
1340 } /*BreakVolumeCallBacks*/
1341
1342
1343 /*
1344  * Delete all timed-out call back entries (to be called periodically by file
1345  * server)
1346  */
1347 CleanupTimedOutCallBacks()
1348 {
1349     H_LOCK
1350     CleanupTimedOutCallBacks_r();
1351     H_UNLOCK
1352 }
1353
1354 CleanupTimedOutCallBacks_r()
1355 {
1356     afs_uint32 now = CBtime(FT_ApproxTime());
1357     register u_short *thead;
1358     register struct CallBack *cb;
1359     register int ntimedout = 0;
1360     char hoststr[16];
1361
1362     extern void ShutDown();
1363
1364     while (tfirst <= now) {
1365         register int cbi;
1366         cbi = *(thead = THead(tfirst));
1367         if (cbi) {
1368             do {
1369                 cb = itocb(cbi);
1370                 cbi = cb->tnext;
1371                 ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1372                         afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port, 
1373                         itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1374                         itofe(cb->fhead)->unique));
1375                 HDel(cb);
1376                 CDel(cb);
1377                 ntimedout++;
1378                 if (ntimedout > cbstuff.nblks) {
1379                   ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1380                   DumpCallBackState();
1381                   ShutDown();
1382                 }
1383             } while (cbi != *thead);
1384             *thead = 0;
1385         }
1386         tfirst++;
1387     }
1388     cbstuff.CBsTimedOut += ntimedout;
1389     ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1390     return (ntimedout > 0);
1391
1392 } /*CleanupTimedOutCallBacks*/
1393
1394
1395 static struct host *lih_host;
1396
1397 static int lih_r(host, held, hostp)
1398     register struct host *host, *hostp;
1399     register int held;
1400
1401 {
1402     if (host->cblist
1403            && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1404            && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1405         lih_host = host;
1406     }
1407     return held;
1408
1409 } /*lih*/
1410
1411
1412 /* This could be upgraded to get more space each time */
1413 /* first pass: find the oldest host which isn't held by anyone */
1414 /* second pass: find the oldest host who isn't "me" */
1415 /* always called with hostp unlocked */
1416 static int GetSomeSpace_r(hostp, locked)
1417     struct host *hostp;
1418     int locked;
1419 {
1420     register struct host *hp, *hp1 = NULL;
1421     int i=0;
1422
1423     cbstuff.GotSomeSpaces++;
1424     ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1425     if (CleanupTimedOutCallBacks_r()) {
1426         cbstuff.GSS3++;
1427         return;
1428     }
1429     do {
1430         lih_host = 0;
1431         h_Enumerate_r(lih_r, (char *)hp1);
1432         hp = lih_host;
1433         if (hp) {
1434             cbstuff.GSS4++;
1435             if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1436                 return;
1437             hp1 = hp;
1438         } else {
1439             hp1 = hostp;
1440             cbstuff.GSS1++;
1441             ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1442             /*
1443              * Next time try getting callbacks from any host even if
1444              * it's deleted (that's actually great since we can freely
1445              * remove its callbacks) or it's held since the only other
1446              * option is starvation for the file server (i.e. until the
1447              * callback timeout arrives).
1448              */
1449             i++;
1450         }
1451     } while (i < 2);
1452     /*
1453      * No choice to clear this host's callback state
1454      */
1455     /* third pass: we still haven't gotten any space, so we free what we had
1456      * previously passed over. */
1457     cbstuff.GSS2++;
1458     if (!locked) {
1459       h_Lock_r(hostp);
1460     }
1461     ClearHostCallbacks_r(hostp, 1/*already locked*/);
1462     if (!locked) {
1463       h_Unlock_r(hostp);
1464     }
1465 } /*GetSomeSpace*/
1466
1467
1468 ClearHostCallbacks(hp, locked)
1469      struct host *hp;
1470      int locked; /* set if caller has already locked the host */
1471 {
1472     int retVal;
1473     H_LOCK
1474     retVal = ClearHostCallbacks_r(hp, locked);
1475     H_UNLOCK
1476     return retVal;
1477 }
1478
1479 int ClearHostCallbacks_r(hp, locked)
1480      struct host *hp;
1481      int locked; /* set if caller has already locked the host */
1482 {
1483     struct interfaceAddr interf;
1484     int code;
1485     int held = 0;
1486     char hoststr[16];
1487
1488     ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
1489     if ( !(held = h_Held_r(hp)) )
1490         h_Hold_r(hp);
1491
1492     /** Try a non-blocking lock. If the lock is already held return
1493       * after releasing hold on hp
1494       */
1495     if (!locked) {
1496        if ( h_NBLock_r(hp) ) {
1497            if ( !held )
1498                h_Release_r(hp);
1499            return 1;
1500        }
1501     }
1502     if (hp->Console & 2) {
1503         /*
1504          * If the special console field is set it means that a thread
1505          * is waiting in AddCallBack1 after it set pointers to the
1506          * file entry and/or callback entry. Because of the bogus
1507          * usage of h_hold it won't prevent from another thread, this
1508          * one, to remove all the callbacks so just to be safe we keep
1509          * a reference. NOTE, on the last phase we'll free the calling
1510          * host's callbacks but that's ok...
1511          */
1512         cbstuff.GSS5++;
1513     }
1514     DeleteAllCallBacks_r(hp);
1515     if (hp->hostFlags & VENUSDOWN) {
1516         hp->hostFlags &= ~RESETDONE;    /* remember that we must do a reset */
1517     } else {
1518         /* host is up, try a call */
1519         hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1520         if (hp->interface) {
1521             H_UNLOCK
1522             code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1523             H_LOCK
1524         } else {
1525             H_UNLOCK
1526             code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1527             H_LOCK
1528         }
1529         hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1530         if (code)
1531         {
1532             /* failed, mark host down and need reset */
1533             hp->hostFlags |= VENUSDOWN;
1534             hp->hostFlags &= ~RESETDONE;
1535         } else {
1536             /* reset succeeded, we're done */
1537             hp->hostFlags |= RESETDONE;
1538         }
1539     }
1540     if (!locked) {
1541        h_Unlock_r(hp);
1542     }
1543     if ( !held )
1544         h_Release_r(hp);
1545
1546     return 0;
1547 }
1548 #endif /* INTERPRET_DUMP */
1549
1550
1551 PrintCallBackStats()
1552
1553 {
1554     fprintf(stderr, "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1555             cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1556             cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1557             cbstuff.DeleteAllCallBacks);
1558     fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1559             cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1560
1561 } /*PrintCallBackStats*/
1562
1563
1564 #define MAGIC 0x12345678    /* To check byte ordering of dump when it is read in */
1565
1566 #ifndef INTERPRET_DUMP
1567
1568
1569 DumpCallBackState()
1570
1571 {
1572     int fd;
1573     afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1574
1575     fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1576     if (fd < 0) {
1577         ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1578         return;
1579     }
1580     write(fd, &magic, sizeof(magic));
1581     write(fd, &now, sizeof(now));
1582     write(fd, &cbstuff, sizeof(cbstuff));
1583     write(fd, TimeOuts, sizeof(TimeOuts));
1584     write(fd, timeout, sizeof(timeout));
1585     write(fd, &tfirst, sizeof(tfirst));
1586     freelisthead = cbtoi((struct CallBack *) CBfree);
1587     write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1588     freelisthead = fetoi((struct FileEntry *) FEfree);
1589     write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1590     write(fd, HashTable, sizeof(HashTable));
1591     write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1592     write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1593     close(fd);
1594
1595 } /*DumpCallBackState*/
1596
1597 #endif
1598
1599 #ifdef INTERPRET_DUMP
1600
1601 /* This is only compiled in for the callback analyzer program */
1602 /* Returns the time of the dump */
1603 time_t ReadDump(file)
1604     char *file;
1605
1606 {
1607     int fd;
1608     afs_uint32 magic, freelisthead;
1609     time_t now;
1610
1611     fd = open(file, O_RDONLY);
1612     if (fd < 0) {
1613         fprintf(stderr, "Couldn't read dump file %s\n", file);
1614         exit(1);
1615     }
1616     read(fd, &magic, sizeof(magic));
1617     if (magic != MAGIC) {
1618         fprintf(stderr, "Magic number of %s is invalid.  You might be trying to\n",
1619                 file);
1620         fprintf(stderr,
1621                 "run this program on a machine type with a different byte ordering.\n");
1622         exit(1);
1623     }
1624     read(fd, &now, sizeof(now));
1625     read(fd, &cbstuff, sizeof(cbstuff));
1626     read(fd, TimeOuts, sizeof(TimeOuts));
1627     read(fd, timeout, sizeof(timeout));
1628     read(fd, &tfirst, sizeof(tfirst));
1629     read(fd, &freelisthead, sizeof(freelisthead));
1630     CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1631     FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1632     CBfree = (struct CallBack *) itocb(freelisthead);
1633     read(fd, &freelisthead, sizeof(freelisthead));
1634     FEfree = (struct FileEntry *) itofe(freelisthead);
1635     read(fd, HashTable, sizeof(HashTable));
1636     read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1637     read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1638     if (close(fd)) {
1639         perror("Error reading dumpfile");
1640         exit(1);
1641     }
1642     return now;
1643
1644 } /*ReadDump*/
1645
1646
1647 #include "AFS_component_version_number.c"
1648
1649 main(argc, argv)
1650     int argc;
1651     char **argv;
1652
1653 {
1654     int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1655     static AFSFid fid;
1656     register struct FileEntry *fe;
1657     register struct CallBack *cb;
1658     time_t now;
1659
1660     memset(&fid, 0, sizeof(fid));
1661     argc--; argv++;
1662     while (argc && **argv == '-') {
1663         noptions++;
1664         argc--;
1665         if (!strcmp(*argv, "-host")) {
1666             if (argc < 1) {
1667                 err++;
1668                 break;
1669             }
1670             argc--;
1671             cbi = atoi(*++argv);
1672         }
1673         else if (!strcmp(*argv, "-fid")) {
1674             if (argc < 2) {
1675                 err++;
1676                 break;
1677             }
1678             argc -= 3;
1679             fid.Volume = atoi(*++argv);
1680             fid.Vnode = atoi(*++argv);
1681             fid.Unique = atoi(*++argv);
1682         }
1683         else if (!strcmp(*argv, "-time")) {
1684             fprintf(stderr, "-time not supported\n");
1685             exit(1);
1686         }
1687         else if (!strcmp(*argv, "-stats")) {
1688             stats = 1;
1689         }
1690         else if (!strcmp(*argv, "-all")) {
1691             all = 1;
1692         }
1693         else if (!strcmp(*argv, "-raw")) {
1694             raw = 1;
1695         }
1696         else if (!strcmp(*argv, "-volume")) {
1697             if (argc < 1) {
1698                 err++;
1699                 break;
1700             }
1701             argc--;
1702             vol = atoi(*++argv);
1703         }
1704         else err++;
1705         argv++;
1706     }
1707     if (err || argc != 1) {
1708         fprintf(stderr,
1709                 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1710         fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1711         exit(1);
1712     }
1713     now = ReadDump(*argv);
1714     if (stats || noptions == 0) {
1715         time_t uxtfirst = UXtime(tfirst);
1716         printf("The time of the dump was %u %s", now, ctime(&now));
1717         printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1718         PrintCallBackStats();
1719     }
1720     if (all || vol) {
1721         register hash;
1722         register u_short *feip;
1723         register struct CallBack *cb;
1724         register struct FileEntry *fe;
1725
1726         for (hash=0; hash<VHASH; hash++) {
1727             for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1728                 if (!vol || (fe->volid == vol)) {
1729                     register struct CallBack *cbnext;
1730                     for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1731                         PrintCB(cb,now);
1732                         cbnext = itocb(cb->cnext);
1733                     }
1734                     *feip = fe->fnext;
1735                 } else {
1736                     feip = &fe->fnext;
1737                 }
1738             }
1739         }
1740     }
1741     if (cbi) {
1742         u_short cfirst = cbi;
1743         do {
1744             cb = itocb(cbi);
1745             PrintCB(cb,now);
1746             cbi = cb->hnext;
1747         } while (cbi != cfirst);
1748     }
1749     if (fid.Volume) {
1750         fe = FindFE(&fid);
1751         if (!fe) {
1752             printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1753             exit(1);
1754         }
1755         cb = itocb(fe->firstcb);
1756         while (cb) {
1757             PrintCB(cb, now);
1758             cb = itocb(cb->cnext);
1759         }
1760     }
1761     if (raw) {
1762         struct FileEntry *fe;
1763         afs_int32 *p, i;
1764         for (i=1; i < cbstuff.nblks; i++) {
1765             p = (afs_int32 *) &FE[i];
1766             printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1767         }
1768     }
1769 }
1770
1771 PrintCB(cb, now)
1772     register struct CallBack *cb;
1773     afs_uint32 now;
1774
1775 {
1776     struct FileEntry *fe = itofe(cb->fhead);
1777     time_t expires = TIndexToTime(cb->thead);
1778
1779     printf("vol=%u vn=%u cbs=%d hi=%d st=%d, exp in %d secs at %s", 
1780            fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1781            expires - now, ctime(&expires));
1782
1783 } /*PrintCB*/
1784
1785
1786 #endif
1787
1788 #if     !defined(INTERPRET_DUMP)
1789 /*
1790 ** try breaking calbacks on afidp from host. Use multi_rx.
1791 ** return 0 on success, non-zero on failure
1792 */
1793 int
1794 MultiBreakCallBackAlternateAddress(host, afidp)
1795 struct host*            host;
1796 struct AFSCBFids*       afidp;
1797 {
1798     int retVal;
1799     H_LOCK
1800     retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1801     H_UNLOCK
1802     return retVal;
1803 }
1804
1805 int
1806 MultiBreakCallBackAlternateAddress_r(host, afidp)
1807 struct host*            host;
1808 struct AFSCBFids*       afidp;
1809 {
1810         int i,j;
1811         struct rx_connection*   conns[AFS_MAX_INTERFACE_ADDR];
1812         struct rx_connection*   connSuccess = 0;
1813         afs_int32                       addr[AFS_MAX_INTERFACE_ADDR];
1814         static struct rx_securityClass *sc = 0;
1815         static struct AFSCBs tc = {0,0};
1816         char hoststr[16];
1817
1818         /* nothing more can be done */
1819         if ( !host->interface ) return 1;       /* failure */
1820
1821         assert(host->interface->numberOfInterfaces > 0 );
1822
1823         /* the only address is the primary interface */
1824         if ( host->interface->numberOfInterfaces == 1 )
1825                 return 1;                       /* failure */
1826
1827         /* initialise a security object only once */
1828         if ( !sc )
1829             sc = rxnull_NewClientSecurityObject();
1830
1831         /* initialize alternate rx connections */
1832         for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1833         {
1834                 /* this is the current primary address */
1835                 if ( host->host == host->interface->addr[i] )
1836                         continue;       
1837
1838                 addr[j]    = host->interface->addr[i];
1839                 conns[j] =  rx_NewConnection (host->interface->addr[i],
1840                                 host->port, 1, sc, 0);
1841                 rx_SetConnDeadTime(conns[j], 2); 
1842                 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME); 
1843                 j++;
1844         }
1845
1846         assert(j);  /* at least one alternate address */
1847         ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
1848                         afs_inet_ntoa_r(host->host,hoststr)));
1849         H_UNLOCK
1850         multi_Rx(conns, j)
1851         {
1852                 multi_RXAFSCB_CallBack(afidp, &tc);     
1853                 if ( !multi_error )
1854                 {
1855                         /* first success */
1856                         H_LOCK
1857                         if ( host->callback_rxcon )
1858                                 rx_DestroyConnection(host->callback_rxcon);
1859                         host->callback_rxcon = conns[multi_i];
1860                         host->host           = addr[multi_i];
1861                         connSuccess          = conns[multi_i];
1862                         rx_SetConnDeadTime(host->callback_rxcon, 50);
1863                         rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1864                         ViceLog(125,("multibreakcall success with addr %s\n",
1865                                         afs_inet_ntoa_r(addr[multi_i],hoststr)));
1866                         H_UNLOCK
1867                         multi_Abort; 
1868                 }
1869         } multi_End_Ignore;
1870         H_LOCK
1871
1872         /* Destroy all connections except the one on which we succeeded */
1873         for ( i=0; i < j; i++)
1874                 if ( conns[i] != connSuccess )
1875                         rx_DestroyConnection(conns[i] );
1876
1877         if ( connSuccess ) return 0;    /* success */
1878                 else return 1;          /* failure */
1879 }
1880
1881
1882 /*
1883 ** try multiRX probes to host. 
1884 ** return 0 on success, non-zero on failure
1885 */
1886 int
1887 MultiProbeAlternateAddress_r(host)
1888 struct host*            host;
1889 {
1890         int i,j;
1891         struct rx_connection*   conns[AFS_MAX_INTERFACE_ADDR];
1892         struct rx_connection*   connSuccess = 0;
1893         afs_int32                       addr[AFS_MAX_INTERFACE_ADDR];
1894         static struct rx_securityClass *sc = 0;
1895         char hoststr[16];
1896
1897         /* nothing more can be done */
1898         if ( !host->interface ) return 1;       /* failure */
1899
1900         assert(host->interface->numberOfInterfaces > 0 );
1901
1902         /* the only address is the primary interface */
1903         if ( host->interface->numberOfInterfaces == 1 )
1904                 return 1;                       /* failure */
1905
1906         /* initialise a security object only once */
1907         if ( !sc )
1908             sc = rxnull_NewClientSecurityObject();
1909
1910         /* initialize alternate rx connections */
1911         for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1912         {
1913                 /* this is the current primary address */
1914                 if ( host->host == host->interface->addr[i] )
1915                         continue;       
1916
1917                 addr[j]    = host->interface->addr[i];
1918                 conns[j] =  rx_NewConnection (host->interface->addr[i],
1919                                 host->port, 1, sc, 0);
1920                 rx_SetConnDeadTime(conns[j], 2); 
1921                 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME); 
1922                 j++;
1923         }
1924
1925         assert(j);  /* at least one alternate address */
1926         ViceLog(125,("Starting multiprobe on all addr for host %s\n",
1927                         afs_inet_ntoa_r(host->host,hoststr)));
1928         H_UNLOCK
1929         multi_Rx(conns, j)
1930         {
1931                 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);        
1932                 if ( !multi_error )
1933                 {
1934                         /* first success */
1935                         H_LOCK
1936                         if ( host->callback_rxcon )
1937                                 rx_DestroyConnection(host->callback_rxcon);
1938                         host->callback_rxcon = conns[multi_i];
1939                         host->host           = addr[multi_i];
1940                         connSuccess          = conns[multi_i];
1941                         rx_SetConnDeadTime(host->callback_rxcon, 50);
1942                         rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1943                         ViceLog(125,("multiprobe success with addr %s\n",
1944                                         afs_inet_ntoa_r(addr[multi_i],hoststr)));
1945                         H_UNLOCK
1946                         multi_Abort; 
1947                 }
1948         } multi_End_Ignore;
1949         H_LOCK
1950
1951         /* Destroy all connections except the one on which we succeeded */
1952         for ( i=0; i < j; i++)
1953                 if ( conns[i] != connSuccess )
1954                         rx_DestroyConnection(conns[i] );
1955
1956         if ( connSuccess ) return 0;    /* success */
1957                 else return 1;          /* failure */
1958 }
1959
1960 #endif /* !defined(INTERPRET_DUMP) */