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