2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * NEW callback package callback.c (replaces vicecb.c)
12 * Updated call back routines, NOW with:
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
22 * Strict limit on number of call backs.
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
30 * time = AddCallBack(host, fid)
32 * Returns the expiration time at the workstation.
34 * BreakCallBack(host, fid)
35 * Break all call backs for fid, except for the specified host.
38 * BreakVolumeCallBacks(volume)
39 * Break all call backs on volume, using single call to each host
40 * Delete all the call backs.
42 * DeleteCallBack(host,fid)
43 * Delete (do not break) single call back for fid.
45 * DeleteFileCallBacks(fid)
46 * Delete (do not break) all call backs for fid.
48 * DeleteAllCallBacks(host)
49 * Delete (do not break) all call backs for host.
51 * CleanupTimedOutCallBacks()
52 * Delete all timed out call back entries
53 * Must be called periodically by file server.
55 * BreakDelayedCallBacks(host)
56 * Break all delayed call backs for host.
57 * Returns 1: one or more failed, 0: success.
59 * PrintCallBackStats()
60 * Print statistics about call backs to stdout.
62 * DumpCallBacks() ---wishful thinking---
63 * Dump call back state to /tmp/callback.state.
64 * This is separately interpretable by the program pcb.
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.
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).
78 * CleanupCallBacks MUST be called periodically by the file server for
79 * this package to work correctly. Every 5 minutes is suggested.
82 #include <afsconfig.h>
83 #include <afs/param.h>
88 #include <stdlib.h> /* for malloc() */
89 #include <time.h> /* ANSI standard location for time stuff */
100 #ifdef HAVE_STRINGS_H
104 #include <afs/assert.h>
106 #include <afs/stds.h>
108 #include <afs/nfs.h> /* yuck. This is an abomination. */
111 #include <afscbint.h>
112 #include <afs/afsutil.h>
114 #include <afs/ihandle.h>
115 #include <afs/vnode.h>
116 #include <afs/volume.h>
117 #include "viced_prototypes.h"
120 #include <afs/ptclient.h> /* need definition of prlist for host.h */
123 extern afsUUID FS_HostUUID;
124 extern int hostCount;
125 int ShowProblems = 1;
127 /* Maximum number of call backs to break at once, single fid */
128 /* There is some debate as to just how large this value should be */
129 /* Ideally, it would be very very large, but I am afraid that the */
130 /* cache managers will all send in their responses simultaneously, */
131 /* thereby swamping the file server. As a result, something like */
132 /* 10 or 15 might be a better bet. */
133 #define MAX_CB_HOSTS 10
135 /* max time to break a callback, otherwise client is dead or net is hosed */
138 #define u_byte unsigned char
140 struct cbcounters cbstuff;
156 } *FE; /* Don't use FE[0] */
160 afs_uint32 cnext; /* Next call back entry */
161 afs_uint32 fhead; /* Head of this call back chain */
162 u_byte thead; /* Head of timeout chain */
163 u_byte status; /* Call back status; see definitions, below */
164 afs_uint32 hhead; /* Head of host table chain */
165 afs_uint32 tprev, tnext; /* Timeout chain */
166 afs_uint32 hprev, hnext; /* Chain from host table */
167 unsigned short spare; /* make it a multiple of 32 bits. */
168 } *CB; /* Don't use CB[0] */
170 /* status values for status field of CallBack structure */
171 #define CB_NORMAL 1 /* Normal call back */
172 #define CB_DELAYED 2 /* Delayed call back due to rpc problems.
173 The call back entry will be added back to the
174 host list at the END of the list, so that
175 searching backwards in the list will find all
176 the (consecutive)host. delayed call back entries */
177 #define CB_VOLUME 3 /* Callback for a volume */
178 #define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
180 /* call back indices to pointers, and vice-versa */
181 #define itocb(i) ((i)?CB+(i):0)
182 #define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
184 /* file entry indices to pointers, and vice-versa */
185 #define itofe(i) ((i)?FE+(i):0)
186 #define fetoi(fep) (!(fep)?0:(fep)-FE)
188 /* Timeouts: there are 128 possible timeout values in effect at any
189 * given time. Each timeout represents timeouts in an interval of 128
190 * seconds. So the maximum timeout for a call back is 128*128=16384
191 * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
192 * if space runs out or by the file server every 5 minutes. This 5
193 * minute slack should be allowed for--so a maximum time of 4 hours
196 * Timeouts must be chosen to correspond to an exact multiple
197 * of 128, because all times are truncated to a 128 multiple, and
198 * timed out if the current truncated time is <= to the truncated time
199 * corresponding to the timeout queue.
202 /* Unix time to Call Back time, and vice-versa. Call back time is
203 in units of 128 seconds, corresponding to time queues. */
204 #define CBtime(uxtime) ((uxtime)>>7)
205 #define UXtime(cbtime) ((cbtime)<<7)
207 /* Given a Unix time, compute the closest Unix time that corresponds to
208 a time queue, rounding up */
209 #define TimeCeiling(uxtime) (((uxtime)+127)&~127)
211 /* Time to live for call backs depends upon number of users of the file.
212 * TimeOuts is indexed by this number/8 (using TimeOut macro). Times
213 * in this table are for the workstation; server timeouts, add
216 static int TimeOuts[] = {
217 /* Note: don't make the first entry larger than 4 hours (see above) */
218 4*60*60, /* 0-7 users */
219 1*60*60, /* 8-15 users */
220 30*60, /* 16-23 users */
221 15*60, /* 24-31 users */
222 15*60, /* 32-39 users */
223 10*60, /* 40-47 users */
224 10*60, /* 48-55 users */
225 10*60, /* 56-63 users */
226 }; /* Anything more: MinTimeOut */
228 /* minimum time given for a call back */
229 static int MinTimeOut = (7*60);
231 #define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
232 #define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
234 /* time out at server is 3 minutes more than ws */
235 #define ServerBias (3*60)
237 /* Heads of CB queues; a timeout index is 1+index into this array */
238 static afs_uint32 timeout[128];
240 /* Convert cbtime to timeout queue index */
241 #define TIndex(cbtime) (((cbtime)&127)+1)
243 /* Convert cbtime to pointer to timeout queue head */
244 #define THead(cbtime) (&timeout[TIndex(cbtime)-1])
246 static afs_int32 tfirst; /* cbtime of oldest unexpired call back time queue */
248 /* Normalize index into timeout array so that two such indices will be
249 ordered correctly, so that they can be compared to see which times
250 sooner, or so that the difference in time out times between them
252 #define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
254 /* This converts a timeout index into the actual time it will expire */
255 #define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
258 /* Convert pointer to timeout queue head to index, and vice versa */
259 #define ttoi(t) ((t-timeout)+1)
260 #define itot(i) ((timeout)+(i-1))
262 /* 16 byte object get/free routines */
268 struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
270 afs_uint32 thead; /* head of timeout queue for youngest callback */
274 struct CallBack *CBfree = 0;
275 struct FileEntry *FEfree = 0;
277 /* Prototypes for static routines */
278 static struct FileEntry *FindFE (register AFSFid *fid);
279 static struct CallBack *iGetCB(register int *nused);
280 static int iFreeCB(register struct CallBack *cb, register int *nused);
281 static struct FileEntry *iGetFE(register int *nused);
282 static int iFreeFE(register struct FileEntry *fe, register int *nused);
283 static int TAdd(register struct CallBack *cb, register afs_uint32 *thead);
284 static int TDel(register struct CallBack *cb);
285 static int HAdd(register struct CallBack *cb, register struct host *host);
286 static int HDel(register struct CallBack *cb);
287 static int CDel(struct CallBack *cb, int deletefe);
288 static int CDelPtr(register struct FileEntry *fe, register afs_uint32 *cbp, int deletefe);
289 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host);
290 static int FDel(register struct FileEntry *fe);
291 static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead, int type, int locked);
292 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas, struct AFSCBFids *afidp, struct host *xhost);
293 static int MultiBreakVolumeCallBack_r(struct host *host, int isheld, struct VCBParams *parms, int deletefe);
294 static int MultiBreakVolumeCallBack(struct host *host, int isheld, struct VCBParams *parms);
295 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld, struct VCBParams *parms);
296 static int lih_r(register struct host *host, register int held, register struct host *hostp);
297 static int GetSomeSpace_r(struct host *hostp, int locked);
298 static int ClearHostCallbacks_r(struct host *hp, int locked);
300 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
301 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
302 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
303 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
305 /* Other protos - move out sometime */
306 extern void ShutDown();
308 #define VHASH 512 /* Power of 2 */
309 static afs_uint32 HashTable[VHASH]; /* File entry hash table */
310 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
312 static struct FileEntry *FindFE (register AFSFid *fid)
316 register struct FileEntry *fe;
318 hash = VHash(fid->Volume, fid->Unique);
319 for (fei=HashTable[hash]; fei; fei = fe->fnext) {
321 if (fe->volid == fid->Volume && fe->unique == fid->Unique &&
322 fe->vnode == fid->Vnode)
328 #ifndef INTERPRET_DUMP
330 static struct CallBack *iGetCB(register int *nused)
332 register struct CallBack *ret;
334 if ((ret = CBfree)) {
335 CBfree = (struct CallBack *)(((struct object *)ret)->next);
341 static int iFreeCB(register struct CallBack *cb, register int *nused)
343 ((struct object *)cb)->next = (struct object *)CBfree;
349 static struct FileEntry *iGetFE(register int *nused)
351 register struct FileEntry *ret;
353 if ((ret = FEfree)) {
354 FEfree = (struct FileEntry *)(((struct object *)ret)->next);
360 static int iFreeFE(register struct FileEntry *fe, register int *nused)
362 ((struct object *)fe)->next = (struct object *)FEfree;
368 /* Add cb to end of specified timeout list */
369 static int TAdd(register struct CallBack *cb, register afs_uint32 *thead)
372 (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
374 register struct CallBack *thp = itocb(*thead);
376 cb->tprev = thp->tprev;
380 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
382 thp->tprev = cbtoi(cb);
385 cb->thead = ttoi(thead);
389 /* Delete call back entry from timeout list */
390 static int TDel(register struct CallBack *cb)
392 register afs_uint32 *thead = itot(cb->thead);
394 if (*thead == cbtoi(cb))
395 *thead = (*thead == cb->tnext? 0: cb->tnext);
396 if (itocb(cb->tprev))
397 itocb(cb->tprev)->tnext = cb->tnext;
398 if (itocb(cb->tnext))
399 itocb(cb->tnext)->tprev = cb->tprev;
403 /* Add cb to end of specified host list */
404 static int HAdd(register struct CallBack *cb, register struct host *host)
406 cb->hhead = h_htoi(host);
408 host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
411 register struct CallBack *hhp = itocb(host->cblist);
413 cb->hprev = hhp->hprev;
414 cb->hnext = host->cblist;
415 hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
420 /* Delete call back entry from host list */
421 static int HDel(register struct CallBack *cb)
423 register afs_uint32 *hhead = &h_itoh(cb->hhead)->cblist;
425 if (*hhead == cbtoi(cb))
426 *hhead = (*hhead == cb->hnext? 0: cb->hnext);
427 itocb(cb->hprev)->hnext = cb->hnext;
428 itocb(cb->hnext)->hprev = cb->hprev;
432 /* Delete call back entry from fid's chain of cb's */
433 /* N.B. This one also deletes the CB, and also possibly parent FE, so
434 * make sure that it is not on any other list before calling this
436 static int CDel(struct CallBack *cb, int deletefe)
439 struct FileEntry *fe = itofe(cb->fhead);
440 register afs_uint32 *cbp;
443 for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
444 cbp = &itocb(*cbp)->cnext, safety++) {
445 if (safety > cbstuff.nblks + 10) {
447 ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
449 ShutDownAndCore(PANIC);
452 CDelPtr(fe, cbp, deletefe);
456 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
457 * as well as file entry */
458 /* N.B. This one also deletes the CB, and also possibly parent FE, so
459 * make sure that it is not on any other list before calling this
461 int Ccdelpt=0, CcdelB=0;
463 static int CDelPtr(register struct FileEntry *fe,
464 register afs_uint32 *cbp, int deletefe)
466 register struct CallBack *cb;
476 if (deletefe && (--fe->ncbs == 0))
481 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host)
483 register afs_uint32 hostindex = h_htoi(host);
484 register struct CallBack *cb;
485 register afs_uint32 *cbp;
488 for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
489 if (safety > cbstuff.nblks) {
490 ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
492 ShutDownAndCore(PANIC);
495 if (cb->hhead == hostindex)
501 /* Delete file entry from hash table */
502 static int FDel(register struct FileEntry *fe)
504 register int fei = fetoi(fe);
505 register afs_uint32 *p = &HashTable[VHash(fe->volid, fe->unique)];
507 while (*p && *p != fei)
508 p = &itofe(*p)->fnext;
515 int InitCallBack(int nblks)
518 tfirst = CBtime(FT_ApproxTime());
519 /* N.B. The "-1", below, is because
520 FE[0] and CB[0] are not used--and not allocated */
521 FE = ((struct FileEntry *)(calloc(nblks, sizeof(struct FileEntry))))-1;
523 ViceLog(0, ("Failed malloc in InitCallBack\n"));
526 cbstuff.nFEs = nblks;
528 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
529 CB = ((struct CallBack *)(calloc(nblks, sizeof(struct CallBack))))-1;
531 ViceLog(0, ("Failed malloc in InitCallBack\n"));
534 cbstuff.nCBs = nblks;
536 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
537 cbstuff.nblks = nblks;
538 cbstuff.nbreakers = 0;
543 afs_int32 XCallBackBulk_r(struct host *ahost, struct AFSFid *fids,
546 struct AFSCallBack tcbs[AFSCBMAX];
554 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
555 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
562 for(i=0;i<nfids && i < AFSCBMAX;i++) {
563 tcbs[i].CallBackVersion = CALLBACK_VERSION;
564 tcbs[i].ExpirationTime = 0;
565 tcbs[i].CallBackType = CB_DROPPED;
567 tf.AFSCBFids_len = i;
568 tf.AFSCBFids_val = &(fids[j]);
572 tc.AFSCBs_val = tcbs;
575 code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
582 /* the locked flag tells us if the host entry has already been locked
583 * by our parent. I don't think anybody actually calls us with the
584 * host locked, but here's how to make that work: GetSomeSpace has to
585 * change so that it doesn't attempt to lock any hosts < "host". That
586 * means that it might be unable to free any objects, so it has to
587 * return an exit status. If it fails, then AddCallBack1 might fail,
588 * as well. If so, the host->ResetDone should probably be set to 0,
589 * and we probably don't want to return a callback promise to the
590 * cache manager, either. */
591 int AddCallBack1(struct host *host, AFSFid *fid, afs_uint32 *thead,
592 int type, int locked)
599 retVal = AddCallBack1_r(host, fid, thead, type, 1);
608 static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead,
609 int type, int locked)
611 struct FileEntry *fe;
612 struct CallBack *cb = 0, *lastcb = 0;
613 struct FileEntry *newfe = 0;
615 afs_uint32 *Thead = thead;
616 struct CallBack *newcb = 0;
621 /* allocate these guys first, since we can't call the allocator with
622 the host structure locked -- or we might deadlock. However, we have
623 to avoid races with FindFE... */
624 while (!(newcb = GetCB())) {
625 GetSomeSpace_r(host, locked);
627 while(!(newfe = GetFE())) { /* Get it now, so we don't have to call */
628 /* GetSomeSpace with the host locked, later. This might turn out to */
629 /* have been unneccessary, but that's actually kind of unlikely, since */
630 /* most files are not shared. */
631 GetSomeSpace_r(host, locked);
635 h_Lock_r(host); /* this can yield, so do it before we get any */
640 if (type == CB_NORMAL) {
641 time_out = TimeCeiling(FT_ApproxTime()+TimeOut(fe?fe->ncbs:0)+ServerBias);
642 Thead = THead(CBtime(time_out));
644 else if (type == CB_VOLUME) {
645 time_out = TimeCeiling((60*120+FT_ApproxTime())+ServerBias);
646 Thead = THead(CBtime(time_out));
648 else if (type == CB_BULK) {
649 /* bulk status can get so many callbacks all at once, and most of them
650 * are probably not for things that will be used for long.
652 time_out = TimeCeiling(FT_ApproxTime() + ServerBias
653 + TimeOut(22 + (fe?fe->ncbs:0)));
654 Thead = THead(CBtime(time_out));
660 register afs_uint32 hash;
665 fe->volid = fid->Volume;
666 fe->vnode = fid->Vnode;
667 fe->unique = fid->Unique;
669 hash = VHash(fid->Volume, fid->Unique);
670 fe->fnext = HashTable[hash];
671 HashTable[hash] = fetoi(fe);
673 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
674 lastcb = cb, cb = itocb(cb->cnext), safety++) {
675 if (safety > cbstuff.nblks) {
676 ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
678 ShutDownAndCore(PANIC);
680 if (cb->hhead == h_htoi(host))
683 if (cb) {/* Already have call back: move to new timeout list */
684 /* don't change delayed callbacks back to normal ones */
685 if (cb->status != CB_DELAYED)
687 /* Only move if new timeout is longer */
688 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
695 *(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
698 cb->fhead = fetoi(fe);
704 /* now free any still-unused callback or host entries */
705 if (newcb) FreeCB(newcb);
706 if (newfe) FreeFE(newfe);
708 if (!locked) /* freecb and freefe might(?) yield */
711 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK )
712 return time_out-ServerBias; /* Expires sooner at workstation */
717 /* Take an array full of hosts, all held. Break callbacks to them, and
718 * release the holds once you're done, except don't release xhost. xhost
719 * may be NULL. Currently only works for a single Fid in afidp array.
720 * If you want to make this work with multiple fids, you need to fix
721 * the error handling. One approach would be to force a reset if a
722 * multi-fid call fails, or you could add delayed callbacks for each
723 * fid. You probably also need to sort and remove duplicate hosts.
724 * When this is called from the BreakVolumeCallBacks path, it does NOT
725 * force a reset if the RPC fails, it just marks the host down and tries
726 * to create a delayed callback. */
727 /* N.B. be sure that code works when ncbas == 0 */
728 /* N.B. requires all the cba[*].hp pointers to be valid... */
729 /* This routine does not hold a lock on the host for the duration of
730 * the BreakCallBack RPC, which is a significant deviation from tradition.
731 * It _does_ get a lock on the host before setting VenusDown = 1,
732 * which is sufficient only if VenusDown = 0 only happens when the
733 * lock is held over the RPC and the subsequent VenusDown == 0
734 * wherever that is done. */
735 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
736 struct AFSCBFids *afidp, struct host *xhost)
739 struct rx_connection *conns[MAX_CB_HOSTS];
740 int opt_TO; /* secs, but internal adaptive parms are in ms */
741 static struct AFSCBs tc = {0,0};
743 assert(ncbas <= MAX_CB_HOSTS);
745 /* set up conns for multi-call */
746 for (i=0,j=0; i<ncbas; i++) {
747 struct host *thishost = cba[i].hp;
748 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
751 conns[j++] = thishost->callback_rxcon;
754 rx_SetConnDeadTime (thishost->callback_rxcon, 4);
755 rx_SetConnHardDeadTime (thishost->callback_rxcon, AFS_HARDDEADTIME);
759 if (j) { /* who knows what multi would do with 0 conns? */
763 multi_RXAFSCB_CallBack(afidp, &tc);
770 /* If there's an error, we have to hunt for the right host.
771 * The conns array _should_ correspond one-to-one to the cba
772 * array, except in some rare cases it might be missing one
773 * or more elements. So the optimistic case is almost
774 * always right. At worst, it's the starting point for the
776 for (hp=0,i=multi_i;i<j;i++) {
777 hp = cba[i].hp; /* optimistic, but usually right */
781 if (conns[multi_i] == hp->callback_rxcon) {
788 ViceLog(0, ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n",hp,cba));
792 ** try breaking callbacks on alternate interface addresses
794 if ( MultiBreakCallBackAlternateAddress(hp, afidp) )
798 ("BCB: Failed on file %u.%d.%d, host %s:%d is down\n",
799 afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
800 afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), ntohs(hp->port)));
805 hp->hostFlags |= VENUSDOWN;
807 * We always go into AddCallBack1_r with the host locked
809 AddCallBack1_r(hp,afidp->AFSCBFids_val,itot(idx), CB_DELAYED, 1);
820 for (i=0; i<ncbas; i++) {
823 if (hp && xhost != hp)
831 * Break all call backs for fid, except for the specified host (unless flag
832 * is true, in which case all get a callback message. Assumption: the specified
833 * host is h_Held, by the caller; the others aren't.
834 * Specified host may be bogus, that's ok. This used to check to see if the
835 * host was down in two places, once right after the host was h_held, and
836 * again after it was locked. That race condition is incredibly rare and
837 * relatively harmless even when it does occur, so we don't check for it now.
839 /* if flag is true, send a break callback msg to "host", too */
840 int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
842 struct FileEntry *fe;
843 struct CallBack *cb, *nextcb;
844 struct cbstruct cba[MAX_CB_HOSTS];
846 struct rx_connection *conns[MAX_CB_HOSTS];
851 ViceLog(7,("BCB: BreakCallBack(all but %s:%d, (%u,%d,%d))\n",
852 afs_inet_ntoa_r(xhost->host,hoststr), ntohs(xhost->port), fid->Volume, fid->Vnode,
857 cbstuff.BreakCallBacks++;
862 hostindex = h_htoi(xhost);
863 cb = itocb(fe->firstcb);
864 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
865 /* the most common case is what follows the || */
868 tf.AFSCBFids_len = 1;
869 tf.AFSCBFids_val = fid;
872 for (ncbas=0; cb && ncbas<MAX_CB_HOSTS; cb=nextcb) {
873 nextcb = itocb(cb->cnext);
874 if ((cb->hhead != hostindex || flag)
875 && (cb->status == CB_BULK || cb->status == CB_NORMAL
876 || cb->status == CB_VOLUME) ) {
877 struct host *thishost = h_itoh(cb->hhead);
879 ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
881 else if (thishost->hostFlags & VENUSDOWN) {
882 ViceLog(7,("BCB: %s:%d is down; delaying break call back\n",
883 afs_inet_ntoa_r(thishost->host,hoststr), ntohs(thishost->port)));
884 cb->status = CB_DELAYED;
888 cba[ncbas].hp = thishost;
889 cba[ncbas].thead = cb->thead;
893 CDel(cb, 1); /* Usually first; so this delete
894 is reasonably inexpensive */
900 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
902 /* we need to to all these initializations again because MultiBreakCallBack may block */
907 cb = itocb(fe->firstcb);
908 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
909 /* the most common case is what follows the || */
920 /* Delete (do not break) single call back for fid */
921 int DeleteCallBack(struct host *host, AFSFid *fid)
923 register struct FileEntry *fe;
924 register afs_uint32 *pcb;
927 cbstuff.DeleteCallBacks++;
935 ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
936 fid->Volume, fid->Vnode, fid->Unique));
939 pcb = FindCBPtr(fe, host);
941 ViceLog(8,("DCB: No call back for host %s:%d, (%u, %d, %d)\n",
942 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port), fid->Volume, fid->Vnode, fid->Unique));
956 * Delete (do not break) all call backs for fid. This call doesn't
957 * set all of the various host locks, but it shouldn't really matter
958 * since we're not adding callbacks, but deleting them. I'm not sure
959 * why it doesn't set the lock, however; perhaps it should.
961 int DeleteFileCallBacks(AFSFid *fid)
963 register struct FileEntry *fe;
964 register struct CallBack *cb;
965 register afs_uint32 cbi;
969 cbstuff.DeleteFiles++;
973 ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
974 fid->Volume, fid->Vnode, fid->Unique));
977 for (n=0,cbi = fe->firstcb; cbi; n++) {
989 /* Delete (do not break) all call backs for host. The host should be
991 int DeleteAllCallBacks_r(struct host *host, int deletefe)
993 register struct CallBack *cb;
994 register int cbi, first;
996 cbstuff.DeleteAllCallBacks++;
997 cbi = first = host->cblist;
999 ViceLog(8,("DV: no call backs\n"));
1007 } while (cbi != first);
1013 * Break all delayed call backs for host. Returns 1 if all call backs
1014 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1015 * Must be called with VenusDown set for this host
1017 int BreakDelayedCallBacks(struct host *host)
1021 retVal = BreakDelayedCallBacks_r(host);
1026 int BreakDelayedCallBacks_r(struct host *host)
1028 struct AFSFid fids[AFSCBMAX];
1029 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1030 int cbi, first, nfids;
1031 struct CallBack *cb;
1032 struct interfaceAddr interf;
1036 cbstuff.nbreakers++;
1037 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1038 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1039 if ( host->interface ) {
1041 code = RXAFSCB_InitCallBackState3(host->callback_rxcon,
1046 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1049 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1053 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1054 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
1056 host->hostFlags |= VENUSDOWN;
1059 ViceLog(25,("InitCallBackState success on %s\n",afs_inet_ntoa_r(host->host,hoststr)));
1060 /* reset was done successfully */
1061 host->hostFlags |= RESETDONE;
1062 host->hostFlags &= ~VENUSDOWN;
1065 else while (!(host->hostFlags & HOSTDELETED)) {
1067 host->hostFlags &= ~VENUSDOWN; /* presume up */
1068 cbi = first = host->cblist;
1072 first = host->cblist;
1075 if (cb->status == CB_DELAYED) {
1076 register struct FileEntry *fe = itofe(cb->fhead);
1077 thead[nfids] = cb->thead;
1078 fids[nfids].Volume = fe->volid;
1079 fids[nfids].Vnode = fe->vnode;
1080 fids[nfids].Unique = fe->unique;
1086 } while (cbi && cbi != first && nfids < AFSCBMAX);
1092 if (XCallBackBulk_r(host, fids, nfids)) {
1093 /* Failed, again: put them back, probably with old
1098 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1099 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
1101 for (i = 0; i<nfids; i++) {
1104 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1105 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port),
1106 fids[i].Volume, fids[i].Vnode, fids[i].Unique));
1109 AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1110 * but it turns out to cause too many tricky locking problems.
1111 * now, if break delayed fails, screw it. */
1113 host->hostFlags |= VENUSDOWN; /* Failed */
1114 ClearHostCallbacks_r(host, 1/* locked */);
1118 if (nfids < AFSCBMAX)
1122 cbstuff.nbreakers--;
1123 /* If we succeeded it's always ok to unset HFE_LATER */
1124 if (!host->hostFlags & VENUSDOWN)
1125 host->hostFlags &= ~HFE_LATER;
1126 return (host->hostFlags & VENUSDOWN);
1130 ** isheld is 0 if the host is held in h_Enumerate
1131 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1133 static int MultiBreakVolumeCallBack_r(struct host *host,
1134 int isheld, struct VCBParams *parms, int deletefe)
1139 return isheld; /* host is held only by h_Enumerate, do nothing */
1140 if ( host->hostFlags & HOSTDELETED )
1141 return 0; /* host is deleted, release hold */
1143 if (host->hostFlags & VENUSDOWN) {
1145 if (host->hostFlags & HOSTDELETED) {
1147 return 0; /* Release hold */
1149 ViceLog(8,("BVCB: volume call back for host %s:%d failed\n",
1150 afs_inet_ntoa_r(host->host,hoststr),ntohs(host->port)));
1152 ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
1153 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
1155 DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state
1156 rather than attempting to
1157 selectively remember to
1158 delete the volume callbacks
1160 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1162 return 0; /* release hold */
1164 assert(parms->ncbas <= MAX_CB_HOSTS);
1166 /* Do not call MultiBreakCallBack on the current host structure
1167 ** because it would prematurely release the hold on the host
1169 if ( parms->ncbas == MAX_CB_HOSTS ) {
1170 struct AFSCBFids tf;
1172 tf.AFSCBFids_len = 1;
1173 tf.AFSCBFids_val = parms->fid;
1175 /* this releases all the hosts */
1176 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */);
1180 parms->cba[parms->ncbas].hp = host;
1181 parms->cba[(parms->ncbas)++].thead = parms->thead;
1182 return 1; /* DON'T release hold, because we still need it. */
1186 ** isheld is 0 if the host is held in h_Enumerate
1187 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1189 static int MultiBreakVolumeCallBack(struct host *host, int isheld,
1190 struct VCBParams *parms)
1194 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1200 ** isheld is 0 if the host is held in h_Enumerate
1201 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1203 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1204 struct VCBParams *parms)
1208 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1214 * Break all call backs on a single volume. Don't call this with any
1215 * hosts h_held. Note that this routine clears the callbacks before
1216 * actually breaking them, and that the vnode isn't locked during this
1217 * operation, so that people might see temporary callback loss while
1218 * this function is executing. It is just a temporary state, however,
1219 * since the callback will be broken later by this same function.
1221 * Now uses multi-RX for CallBack RPC. Note that the
1222 * multiBreakCallBacks routine does not force a reset if the RPC
1223 * fails, unlike the previous version of this routine, but does create
1224 * a delayed callback. Resets will be forced if the host is
1225 * determined to be down before the RPC is executed.
1227 int BreakVolumeCallBacks(afs_uint32 volume)
1232 struct CallBack *cb;
1233 struct FileEntry *fe;
1235 struct VCBParams henumParms;
1236 afs_uint32 tthead = 0; /* zero is illegal value */
1239 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1240 for (hash=0; hash<VHASH; hash++) {
1241 for (feip = &HashTable[hash]; (fe = itofe(*feip)); ) {
1242 if (fe->volid == volume) {
1243 register struct CallBack *cbnext;
1244 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1245 host = h_itoh(cb->hhead);
1247 cbnext = itocb(cb->cnext);
1248 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1254 /* leave hold for MultiBreakVolumeCallBack to clear */
1265 /* didn't find any callbacks, so return right away. */
1269 henumParms.ncbas = 0;
1270 henumParms.fid = &fid;
1271 henumParms.thead = tthead;
1273 h_Enumerate(MultiBreakVolumeCallBack, (char *) &henumParms);
1276 if (henumParms.ncbas) { /* do left-overs */
1277 struct AFSCBFids tf;
1278 tf.AFSCBFids_len = 1;
1279 tf.AFSCBFids_val = &fid;
1281 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1283 henumParms.ncbas = 0;
1290 #ifdef AFS_PTHREAD_ENV
1291 extern pthread_cond_t fsync_cond;
1293 extern char fsync_wait[];
1296 int BreakVolumeCallBacksLater(afs_uint32 volume)
1300 struct FileEntry *fe;
1301 struct CallBack *cb;
1305 ViceLog(25, ("Setting later on volume %d\n", volume));
1307 for (hash=0; hash<VHASH; hash++) {
1308 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1309 if (fe->volid == volume) {
1310 register struct CallBack *cbnext;
1311 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1312 host = h_itoh(cb->hhead);
1313 host->hostFlags |= HFE_LATER;
1314 cb->status = CB_DELAYED;
1315 cbnext = itocb(cb->cnext);
1318 fe->status |= FE_LATER;
1328 /* didn't find any callbacks, so return right away. */
1332 ViceLog(25, ("Fsync thread wakeup\n"));
1333 #ifdef AFS_PTHREAD_ENV
1334 assert(pthread_cond_broadcast(&fsync_cond) == 0);
1336 LWP_NoYieldSignal(&fsync_wait);
1341 int BreakLaterCallBacks(void)
1346 struct CallBack *cb;
1347 struct FileEntry *fe = NULL;
1348 struct FileEntry *myfe = NULL;
1350 struct VCBParams henumParms;
1351 unsigned short tthead = 0; /* zero is illegal value */
1354 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1357 /* Pick the first volume we see to clean up */
1358 fid.Volume = fid.Vnode = fid.Unique = 0;
1360 for (hash=0; hash<VHASH; hash++) {
1361 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1362 if (fe && (fe->status & FE_LATER) &&
1363 (fid.Volume == 0 || fid.Volume == fe->volid)) {
1364 ViceLog(125, ("Unchaining for %d:%d:%d\n", fe->vnode,
1365 fe->unique, fe->volid));
1366 fid.Volume = fe->volid;
1368 /* Works since volid is deeper than the largest pointer */
1369 ((struct object *)fe)->next = (struct object *)myfe;
1381 /* loop over FEs from myfe and free/break */
1384 for (fe = myfe; fe; ) {
1385 register struct CallBack *cbnext;
1386 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1387 host = h_itoh(cb->hhead);
1389 cbnext = itocb(cb->cnext);
1390 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1395 CDel(cb, 0); /* Don't let CDel clean up the fe */
1396 /* leave hold for MultiBreakVolumeCallBack to clear */
1399 fe = (struct FileEntry *)((struct object *)fe)->next;
1404 ViceLog(125, ("Breaking volume %d\n", fid.Volume));
1405 henumParms.ncbas = 0;
1406 henumParms.fid = &fid;
1407 henumParms.thead = tthead;
1409 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *) &henumParms);
1412 if (henumParms.ncbas) { /* do left-overs */
1413 struct AFSCBFids tf;
1414 tf.AFSCBFids_len = 1;
1415 tf.AFSCBFids_val = &fid;
1417 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1418 henumParms.ncbas = 0;
1424 /* Arrange to be called again */
1429 * Delete all timed-out call back entries (to be called periodically by file
1432 int CleanupTimedOutCallBacks(void)
1435 CleanupTimedOutCallBacks_r();
1439 int CleanupTimedOutCallBacks_r(void)
1441 afs_uint32 now = CBtime(FT_ApproxTime());
1442 register afs_uint32 *thead;
1443 register struct CallBack *cb;
1444 register int ntimedout = 0;
1447 while (tfirst <= now) {
1449 cbi = *(thead = THead(tfirst));
1454 ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1455 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port,
1456 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1457 itofe(cb->fhead)->unique));
1461 if (ntimedout > cbstuff.nblks) {
1462 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1463 DumpCallBackState();
1464 ShutDownAndCore(PANIC);
1466 } while (cbi != *thead);
1471 cbstuff.CBsTimedOut += ntimedout;
1472 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1473 return (ntimedout > 0);
1476 static struct host *lih_host;
1478 static int lih_r(register struct host *host, register int held,
1479 register struct host *hostp)
1482 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1483 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1489 /* This could be upgraded to get more space each time */
1490 /* first pass: find the oldest host which isn't held by anyone */
1491 /* second pass: find the oldest host who isn't "me" */
1492 /* always called with hostp unlocked */
1493 extern struct host *hostList;
1494 static int GetSomeSpace_r(struct host *hostp, int locked)
1496 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1499 cbstuff.GotSomeSpaces++;
1500 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1501 if (CleanupTimedOutCallBacks_r()) {
1507 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1511 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1518 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1520 * Next time try getting callbacks from any host even if
1521 * it's deleted (that's actually great since we can freely
1522 * remove its callbacks) or it's held since the only other
1523 * option is starvation for the file server (i.e. until the
1524 * callback timeout arrives).
1530 * No choice to clear this host's callback state
1532 /* third pass: we still haven't gotten any space, so we free what we had
1533 * previously passed over. */
1538 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1545 /* locked - set if caller has already locked the host */
1546 static int ClearHostCallbacks_r(struct host *hp, int locked)
1548 struct interfaceAddr interf;
1553 ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
1554 if ( !(held = h_Held_r(hp)) )
1557 /** Try a non-blocking lock. If the lock is already held return
1558 * after releasing hold on hp
1561 if ( h_NBLock_r(hp) ) {
1567 if (hp->Console & 2) {
1569 * If the special console field is set it means that a thread
1570 * is waiting in AddCallBack1 after it set pointers to the
1571 * file entry and/or callback entry. Because of the bogus
1572 * usage of h_hold it won't prevent from another thread, this
1573 * one, to remove all the callbacks so just to be safe we keep
1574 * a reference. NOTE, on the last phase we'll free the calling
1575 * host's callbacks but that's ok...
1579 DeleteAllCallBacks_r(hp, 1);
1580 if (hp->hostFlags & VENUSDOWN) {
1581 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1583 /* host is up, try a call */
1584 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1585 if (hp->interface) {
1587 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1591 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1594 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1597 /* failed, mark host down and need reset */
1598 hp->hostFlags |= VENUSDOWN;
1599 hp->hostFlags &= ~RESETDONE;
1601 /* reset succeeded, we're done */
1602 hp->hostFlags |= RESETDONE;
1613 #endif /* INTERPRET_DUMP */
1616 int PrintCallBackStats(void)
1618 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",
1619 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1620 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1621 cbstuff.DeleteAllCallBacks);
1622 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1623 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1628 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1630 #ifndef INTERPRET_DUMP
1632 int DumpCallBackState(void)
1635 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1637 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1639 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1642 (void) write(fd, &magic, sizeof(magic));
1643 (void) write(fd, &now, sizeof(now));
1644 (void) write(fd, &cbstuff, sizeof(cbstuff));
1645 (void) write(fd, TimeOuts, sizeof(TimeOuts));
1646 (void) write(fd, timeout, sizeof(timeout));
1647 (void) write(fd, &tfirst, sizeof(tfirst));
1648 freelisthead = cbtoi((struct CallBack *) CBfree);
1649 (void) write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1650 freelisthead = fetoi((struct FileEntry *) FEfree);
1651 (void) write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1652 (void) write(fd, HashTable, sizeof(HashTable));
1653 (void) write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1654 (void) write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1662 #ifdef INTERPRET_DUMP
1664 /* This is only compiled in for the callback analyzer program */
1665 /* Returns the time of the dump */
1666 time_t ReadDump(char *file)
1669 afs_uint32 magic, freelisthead;
1672 fd = open(file, O_RDONLY);
1674 fprintf(stderr, "Couldn't read dump file %s\n", file);
1677 read(fd, &magic, sizeof(magic));
1678 if (magic != MAGIC) {
1679 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1682 "run this program on a machine type with a different byte ordering.\n");
1685 read(fd, &now, sizeof(now));
1686 read(fd, &cbstuff, sizeof(cbstuff));
1687 read(fd, TimeOuts, sizeof(TimeOuts));
1688 read(fd, timeout, sizeof(timeout));
1689 read(fd, &tfirst, sizeof(tfirst));
1690 read(fd, &freelisthead, sizeof(freelisthead));
1691 CB = ((struct CallBack *)(calloc(cbstuff.nblks,sizeof(struct FileEntry))))-1;
1692 FE = ((struct FileEntry *)(calloc(cbstuff.nblks,sizeof(struct FileEntry))))-1;
1693 CBfree = (struct CallBack *) itocb(freelisthead);
1694 read(fd, &freelisthead, sizeof(freelisthead));
1695 FEfree = (struct FileEntry *) itofe(freelisthead);
1696 read(fd, HashTable, sizeof(HashTable));
1697 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1698 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1700 perror("Error reading dumpfile");
1706 #include "AFS_component_version_number.c"
1708 int main(int argc, char **argv)
1710 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1712 register struct FileEntry *fe;
1713 register struct CallBack *cb;
1716 memset(&fid, 0, sizeof(fid));
1718 while (argc && **argv == '-') {
1721 if (!strcmp(*argv, "-host")) {
1727 cbi = atoi(*++argv);
1729 else if (!strcmp(*argv, "-fid")) {
1735 fid.Volume = atoi(*++argv);
1736 fid.Vnode = atoi(*++argv);
1737 fid.Unique = atoi(*++argv);
1739 else if (!strcmp(*argv, "-time")) {
1740 fprintf(stderr, "-time not supported\n");
1743 else if (!strcmp(*argv, "-stats")) {
1746 else if (!strcmp(*argv, "-all")) {
1749 else if (!strcmp(*argv, "-raw")) {
1752 else if (!strcmp(*argv, "-volume")) {
1758 vol = atoi(*++argv);
1763 if (err || argc != 1) {
1765 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
1766 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1769 now = ReadDump(*argv);
1770 if (stats || noptions == 0) {
1771 time_t uxtfirst = UXtime(tfirst);
1772 printf("The time of the dump was %u %s", now, ctime(&now));
1773 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1774 PrintCallBackStats();
1778 register afs_uint32 *feip;
1779 register struct CallBack *cb;
1780 register struct FileEntry *fe;
1782 for (hash=0; hash<VHASH; hash++) {
1783 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1784 if (!vol || (fe->volid == vol)) {
1785 register struct CallBack *cbnext;
1786 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1788 cbnext = itocb(cb->cnext);
1798 afs_uint32 cfirst = cbi;
1803 } while (cbi != cfirst);
1808 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1811 cb = itocb(fe->firstcb);
1814 cb = itocb(cb->cnext);
1818 struct FileEntry *fe;
1820 for (i=1; i < cbstuff.nblks; i++) {
1821 p = (afs_int32 *) &FE[i];
1822 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1827 int PrintCB(register struct CallBack *cb, afs_uint32 now)
1829 struct FileEntry *fe = itofe(cb->fhead);
1830 time_t expires = TIndexToTime(cb->thead);
1832 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1833 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1834 fe->status, expires - now, ctime(&expires));
1839 #if !defined(INTERPRET_DUMP)
1841 ** try breaking calbacks on afidp from host. Use multi_rx.
1842 ** return 0 on success, non-zero on failure
1844 int MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1848 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1853 int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *afidp)
1856 struct rx_connection** conns;
1857 struct rx_connection* connSuccess = 0;
1859 static struct rx_securityClass *sc = 0;
1860 static struct AFSCBs tc = {0,0};
1863 /* nothing more can be done */
1864 if ( !host->interface ) return 1; /* failure */
1866 assert(host->interface->numberOfInterfaces > 0 );
1868 /* the only address is the primary interface */
1869 if ( host->interface->numberOfInterfaces == 1 )
1870 return 1; /* failure */
1872 /* initialise a security object only once */
1874 sc = rxnull_NewClientSecurityObject();
1876 i = host->interface->numberOfInterfaces;
1877 addr = calloc(i, sizeof(afs_int32));
1878 conns = calloc(i, sizeof(struct rx_connection *));
1879 if (!addr || !conns) {
1880 ViceLog(0, ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
1884 /* initialize alternate rx connections */
1885 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1887 /* this is the current primary address */
1888 if ( host->host == host->interface->addr[i] )
1891 addr[j] = host->interface->addr[i];
1892 conns[j] = rx_NewConnection (host->interface->addr[i],
1893 host->port, 1, sc, 0);
1894 rx_SetConnDeadTime(conns[j], 2);
1895 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1899 assert(j); /* at least one alternate address */
1900 ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
1901 afs_inet_ntoa_r(host->host,hoststr)));
1905 multi_RXAFSCB_CallBack(afidp, &tc);
1910 if ( host->callback_rxcon )
1911 rx_DestroyConnection(host->callback_rxcon);
1912 host->callback_rxcon = conns[multi_i];
1913 host->host = addr[multi_i];
1914 connSuccess = conns[multi_i];
1915 rx_SetConnDeadTime(host->callback_rxcon, 50);
1916 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1917 ViceLog(125,("multibreakcall success with addr %s\n",
1918 afs_inet_ntoa_r(addr[multi_i],hoststr)));
1925 /* Destroy all connections except the one on which we succeeded */
1926 for ( i=0; i < j; i++)
1927 if ( conns[i] != connSuccess )
1928 rx_DestroyConnection(conns[i] );
1933 if ( connSuccess ) return 0; /* success */
1934 else return 1; /* failure */
1939 ** try multiRX probes to host.
1940 ** return 0 on success, non-zero on failure
1942 int MultiProbeAlternateAddress_r(struct host *host)
1945 struct rx_connection** conns;
1946 struct rx_connection* connSuccess = 0;
1948 static struct rx_securityClass *sc = 0;
1951 /* nothing more can be done */
1952 if ( !host->interface ) return 1; /* failure */
1954 assert(host->interface->numberOfInterfaces > 0 );
1956 /* the only address is the primary interface */
1957 if ( host->interface->numberOfInterfaces == 1 )
1958 return 1; /* failure */
1960 /* initialise a security object only once */
1962 sc = rxnull_NewClientSecurityObject();
1964 i = host->interface->numberOfInterfaces;
1965 addr = calloc(i, sizeof(afs_int32));
1966 conns = calloc(i, sizeof(struct rx_connection *));
1967 if (!addr || !conns) {
1968 ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
1972 /* initialize alternate rx connections */
1973 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1975 /* this is the current primary address */
1976 if ( host->host == host->interface->addr[i] )
1979 addr[j] = host->interface->addr[i];
1980 conns[j] = rx_NewConnection (host->interface->addr[i],
1981 host->port, 1, sc, 0);
1982 rx_SetConnDeadTime(conns[j], 2);
1983 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1987 assert(j); /* at least one alternate address */
1988 ViceLog(125,("Starting multiprobe on all addr for host %s\n",
1989 afs_inet_ntoa_r(host->host,hoststr)));
1993 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
1998 if ( host->callback_rxcon )
1999 rx_DestroyConnection(host->callback_rxcon);
2000 host->callback_rxcon = conns[multi_i];
2001 host->host = addr[multi_i];
2002 connSuccess = conns[multi_i];
2003 rx_SetConnDeadTime(host->callback_rxcon, 50);
2004 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2005 ViceLog(125,("multiprobe success with addr %s\n",
2006 afs_inet_ntoa_r(addr[multi_i],hoststr)));
2013 /* Destroy all connections except the one on which we succeeded */
2014 for ( i=0; i < j; i++)
2015 if ( conns[i] != connSuccess )
2016 rx_DestroyConnection(conns[i] );
2021 if ( connSuccess ) return 0; /* success */
2022 else return 1; /* failure */
2025 #endif /* !defined(INTERPRET_DUMP) */