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