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