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>
89 #include <stdlib.h> /* for malloc() */
90 #include <time.h> /* ANSI standard location for time stuff */
101 #ifdef HAVE_STRINGS_H
105 #include <afs/assert.h>
107 #include <afs/stds.h>
109 #include <afs/nfs.h> /* yuck. This is an abomination. */
112 #include <afscbint.h>
113 #include <afs/afsutil.h>
115 #include <afs/ihandle.h>
116 #include <afs/vnode.h>
117 #include <afs/volume.h>
118 #include "viced_prototypes.h"
121 #include <afs/ptclient.h> /* need definition of prlist for host.h */
124 extern afsUUID FS_HostUUID;
125 extern int hostCount;
126 int ShowProblems = 1;
128 /* Maximum number of call backs to break at once, single fid */
129 /* There is some debate as to just how large this value should be */
130 /* Ideally, it would be very very large, but I am afraid that the */
131 /* cache managers will all send in their responses simultaneously, */
132 /* thereby swamping the file server. As a result, something like */
133 /* 10 or 15 might be a better bet. */
134 #define MAX_CB_HOSTS 10
136 /* max time to break a callback, otherwise client is dead or net is hosed */
139 #define u_byte unsigned char
141 struct cbcounters cbstuff;
157 } *FE; /* Don't use FE[0] */
161 afs_uint32 cnext; /* Next call back entry */
162 afs_uint32 fhead; /* Head of this call back chain */
163 u_byte thead; /* Head of timeout chain */
164 u_byte status; /* Call back status; see definitions, below */
165 afs_uint32 hhead; /* Head of host table chain */
166 afs_uint32 tprev, tnext; /* Timeout chain */
167 afs_uint32 hprev, hnext; /* Chain from host table */
168 unsigned short spare; /* make it a multiple of 32 bits. */
169 } *CB; /* Don't use CB[0] */
171 /* status values for status field of CallBack structure */
172 #define CB_NORMAL 1 /* Normal call back */
173 #define CB_DELAYED 2 /* Delayed call back due to rpc problems.
174 * The call back entry will be added back to the
175 * host list at the END of the list, so that
176 * searching backwards in the list will find all
177 * the (consecutive)host. delayed call back entries */
178 #define CB_VOLUME 3 /* Callback for a volume */
179 #define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
181 /* call back indices to pointers, and vice-versa */
182 #define itocb(i) ((i)?CB+(i):0)
183 #define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
185 /* file entry indices to pointers, and vice-versa */
186 #define itofe(i) ((i)?FE+(i):0)
187 #define fetoi(fep) (!(fep)?0:(fep)-FE)
189 /* Timeouts: there are 128 possible timeout values in effect at any
190 * given time. Each timeout represents timeouts in an interval of 128
191 * seconds. So the maximum timeout for a call back is 128*128=16384
192 * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
193 * if space runs out or by the file server every 5 minutes. This 5
194 * minute slack should be allowed for--so a maximum time of 4 hours
197 * Timeouts must be chosen to correspond to an exact multiple
198 * of 128, because all times are truncated to a 128 multiple, and
199 * timed out if the current truncated time is <= to the truncated time
200 * corresponding to the timeout queue.
203 /* Unix time to Call Back time, and vice-versa. Call back time is
204 in units of 128 seconds, corresponding to time queues. */
205 #define CBtime(uxtime) ((uxtime)>>7)
206 #define UXtime(cbtime) ((cbtime)<<7)
208 /* Given a Unix time, compute the closest Unix time that corresponds to
209 a time queue, rounding up */
210 #define TimeCeiling(uxtime) (((uxtime)+127)&~127)
212 /* Time to live for call backs depends upon number of users of the file.
213 * TimeOuts is indexed by this number/8 (using TimeOut macro). Times
214 * in this table are for the workstation; server timeouts, add
217 static int TimeOuts[] = {
218 /* Note: don't make the first entry larger than 4 hours (see above) */
219 4 * 60 * 60, /* 0-7 users */
220 1 * 60 * 60, /* 8-15 users */
221 30 * 60, /* 16-23 users */
222 15 * 60, /* 24-31 users */
223 15 * 60, /* 32-39 users */
224 10 * 60, /* 40-47 users */
225 10 * 60, /* 48-55 users */
226 10 * 60, /* 56-63 users */
227 }; /* Anything more: MinTimeOut */
229 /* minimum time given for a call back */
230 static int MinTimeOut = (7 * 60);
232 #define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
233 #define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
235 /* time out at server is 3 minutes more than ws */
236 #define ServerBias (3*60)
238 /* Heads of CB queues; a timeout index is 1+index into this array */
239 static afs_uint32 timeout[128];
241 /* Convert cbtime to timeout queue index */
242 #define TIndex(cbtime) (((cbtime)&127)+1)
244 /* Convert cbtime to pointer to timeout queue head */
245 #define THead(cbtime) (&timeout[TIndex(cbtime)-1])
247 static afs_int32 tfirst; /* cbtime of oldest unexpired call back time queue */
249 /* Normalize index into timeout array so that two such indices will be
250 ordered correctly, so that they can be compared to see which times
251 sooner, or so that the difference in time out times between them
253 #define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
255 /* This converts a timeout index into the actual time it will expire */
256 #define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
259 /* Convert pointer to timeout queue head to index, and vice versa */
260 #define ttoi(t) ((t-timeout)+1)
261 #define itot(i) ((timeout)+(i-1))
263 /* 16 byte object get/free routines */
269 struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
271 afs_uint32 thead; /* head of timeout queue for youngest callback */
275 struct CallBack *CBfree = 0;
276 struct FileEntry *FEfree = 0;
278 /* Prototypes for static routines */
279 static struct FileEntry *FindFE(register AFSFid * fid);
280 static struct CallBack *iGetCB(register int *nused);
281 static int iFreeCB(register struct CallBack *cb, register int *nused);
282 static struct FileEntry *iGetFE(register int *nused);
283 static int iFreeFE(register struct FileEntry *fe, register int *nused);
284 static int TAdd(register struct CallBack *cb, register afs_uint32 * thead);
285 static int TDel(register struct CallBack *cb);
286 static int HAdd(register struct CallBack *cb, register struct host *host);
287 static int HDel(register struct CallBack *cb);
288 static int CDel(struct CallBack *cb, int deletefe);
289 static int CDelPtr(register struct FileEntry *fe, register afs_uint32 * cbp,
291 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host);
292 static int FDel(register struct FileEntry *fe);
293 static int AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead,
294 int type, int locked);
295 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
296 struct AFSCBFids *afidp, struct host *xhost);
297 static int MultiBreakVolumeCallBack_r(struct host *host, int isheld,
298 struct VCBParams *parms, int deletefe);
299 static int MultiBreakVolumeCallBack(struct host *host, int isheld,
300 struct VCBParams *parms);
301 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
302 struct VCBParams *parms);
303 static int lih_r(register struct host *host, register int held,
304 register struct host *hostp);
305 static int GetSomeSpace_r(struct host *hostp, int locked);
306 static int ClearHostCallbacks_r(struct host *hp, int locked);
308 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
309 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
310 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
311 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
313 /* Other protos - move out sometime */
314 extern void ShutDown();
316 #define VHASH 512 /* Power of 2 */
317 static afs_uint32 HashTable[VHASH]; /* File entry hash table */
318 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
320 static struct FileEntry *
321 FindFE(register AFSFid * fid)
325 register struct FileEntry *fe;
327 hash = VHash(fid->Volume, fid->Unique);
328 for (fei = HashTable[hash]; fei; fei = fe->fnext) {
330 if (fe->volid == fid->Volume && fe->unique == fid->Unique
331 && fe->vnode == fid->Vnode)
337 #ifndef INTERPRET_DUMP
339 static struct CallBack *
340 iGetCB(register int *nused)
342 register struct CallBack *ret;
344 if ((ret = CBfree)) {
345 CBfree = (struct CallBack *)(((struct object *)ret)->next);
352 iFreeCB(register struct CallBack *cb, register int *nused)
354 ((struct object *)cb)->next = (struct object *)CBfree;
360 static struct FileEntry *
361 iGetFE(register int *nused)
363 register struct FileEntry *ret;
365 if ((ret = FEfree)) {
366 FEfree = (struct FileEntry *)(((struct object *)ret)->next);
373 iFreeFE(register struct FileEntry *fe, register int *nused)
375 ((struct object *)fe)->next = (struct object *)FEfree;
381 /* Add cb to end of specified timeout list */
383 TAdd(register struct CallBack *cb, register afs_uint32 * thead)
386 (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
388 register struct CallBack *thp = itocb(*thead);
390 cb->tprev = thp->tprev;
394 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
396 thp->tprev = cbtoi(cb);
399 cb->thead = ttoi(thead);
403 /* Delete call back entry from timeout list */
405 TDel(register struct CallBack *cb)
407 register afs_uint32 *thead = itot(cb->thead);
409 if (*thead == cbtoi(cb))
410 *thead = (*thead == cb->tnext ? 0 : cb->tnext);
411 if (itocb(cb->tprev))
412 itocb(cb->tprev)->tnext = cb->tnext;
413 if (itocb(cb->tnext))
414 itocb(cb->tnext)->tprev = cb->tprev;
418 /* Add cb to end of specified host list */
420 HAdd(register struct CallBack *cb, register struct host *host)
422 cb->hhead = h_htoi(host);
424 host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
426 register struct CallBack *hhp = itocb(host->cblist);
428 cb->hprev = hhp->hprev;
429 cb->hnext = host->cblist;
430 hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
435 /* Delete call back entry from host list */
437 HDel(register struct CallBack *cb)
439 register afs_uint32 *hhead = &h_itoh(cb->hhead)->cblist;
441 if (*hhead == cbtoi(cb))
442 *hhead = (*hhead == cb->hnext ? 0 : cb->hnext);
443 itocb(cb->hprev)->hnext = cb->hnext;
444 itocb(cb->hnext)->hprev = cb->hprev;
448 /* Delete call back entry from fid's chain of cb's */
449 /* N.B. This one also deletes the CB, and also possibly parent FE, so
450 * make sure that it is not on any other list before calling this
453 CDel(struct CallBack *cb, int deletefe)
456 struct FileEntry *fe = itofe(cb->fhead);
457 register afs_uint32 *cbp;
460 for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
461 cbp = &itocb(*cbp)->cnext, safety++) {
462 if (safety > cbstuff.nblks + 10) {
465 ("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",
466 cbi, fe->firstcb, *cbp));
468 ShutDownAndCore(PANIC);
471 CDelPtr(fe, cbp, deletefe);
475 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
476 * as well as file entry */
477 /* N.B. This one also deletes the CB, and also possibly parent FE, so
478 * make sure that it is not on any other list before calling this
480 int Ccdelpt = 0, CcdelB = 0;
483 CDelPtr(register struct FileEntry *fe, register afs_uint32 * cbp,
486 register struct CallBack *cb;
496 if (deletefe && (--fe->ncbs == 0))
502 FindCBPtr(struct FileEntry *fe, struct host *host)
504 register afs_uint32 hostindex = h_htoi(host);
505 register struct CallBack *cb;
506 register afs_uint32 *cbp;
509 for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
510 if (safety > cbstuff.nblks) {
511 ViceLog(0, ("FindCBPtr: Internal Error -- shutting down.\n"));
513 ShutDownAndCore(PANIC);
516 if (cb->hhead == hostindex)
522 /* Delete file entry from hash table */
524 FDel(register struct FileEntry *fe)
526 register int fei = fetoi(fe);
527 register afs_uint32 *p = &HashTable[VHash(fe->volid, fe->unique)];
529 while (*p && *p != fei)
530 p = &itofe(*p)->fnext;
538 InitCallBack(int nblks)
541 tfirst = CBtime(FT_ApproxTime());
542 /* N.B. The "-1", below, is because
543 * FE[0] and CB[0] are not used--and not allocated */
544 FE = ((struct FileEntry *)(calloc(nblks, sizeof(struct FileEntry)))) - 1;
546 ViceLog(0, ("Failed malloc in InitCallBack\n"));
549 cbstuff.nFEs = nblks;
551 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
552 CB = ((struct CallBack *)(calloc(nblks, sizeof(struct CallBack)))) - 1;
554 ViceLog(0, ("Failed malloc in InitCallBack\n"));
557 cbstuff.nCBs = nblks;
559 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
560 cbstuff.nblks = nblks;
561 cbstuff.nbreakers = 0;
567 XCallBackBulk_r(struct host * ahost, struct AFSFid * fids, afs_int32 nfids)
569 struct AFSCallBack tcbs[AFSCBMAX];
577 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
578 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
585 for (i = 0; i < nfids && i < AFSCBMAX; i++) {
586 tcbs[i].CallBackVersion = CALLBACK_VERSION;
587 tcbs[i].ExpirationTime = 0;
588 tcbs[i].CallBackType = CB_DROPPED;
590 tf.AFSCBFids_len = i;
591 tf.AFSCBFids_val = &(fids[j]);
595 tc.AFSCBs_val = tcbs;
598 code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
605 /* the locked flag tells us if the host entry has already been locked
606 * by our parent. I don't think anybody actually calls us with the
607 * host locked, but here's how to make that work: GetSomeSpace has to
608 * change so that it doesn't attempt to lock any hosts < "host". That
609 * means that it might be unable to free any objects, so it has to
610 * return an exit status. If it fails, then AddCallBack1 might fail,
611 * as well. If so, the host->ResetDone should probably be set to 0,
612 * and we probably don't want to return a callback promise to the
613 * cache manager, either. */
615 AddCallBack1(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
623 retVal = AddCallBack1_r(host, fid, thead, type, 1);
633 AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
636 struct FileEntry *fe;
637 struct CallBack *cb = 0, *lastcb = 0;
638 struct FileEntry *newfe = 0;
640 afs_uint32 *Thead = thead;
641 struct CallBack *newcb = 0;
646 /* allocate these guys first, since we can't call the allocator with
647 * the host structure locked -- or we might deadlock. However, we have
648 * to avoid races with FindFE... */
649 while (!(newcb = GetCB())) {
650 GetSomeSpace_r(host, locked);
652 while (!(newfe = GetFE())) { /* Get it now, so we don't have to call */
653 /* GetSomeSpace with the host locked, later. This might turn out to */
654 /* have been unneccessary, but that's actually kind of unlikely, since */
655 /* most files are not shared. */
656 GetSomeSpace_r(host, locked);
660 h_Lock_r(host); /* this can yield, so do it before we get any */
665 if (type == CB_NORMAL) {
667 TimeCeiling(FT_ApproxTime() + TimeOut(fe ? fe->ncbs : 0) +
669 Thead = THead(CBtime(time_out));
670 } else if (type == CB_VOLUME) {
671 time_out = TimeCeiling((60 * 120 + FT_ApproxTime()) + ServerBias);
672 Thead = THead(CBtime(time_out));
673 } else if (type == CB_BULK) {
674 /* bulk status can get so many callbacks all at once, and most of them
675 * are probably not for things that will be used for long.
678 TimeCeiling(FT_ApproxTime() + ServerBias +
679 TimeOut(22 + (fe ? fe->ncbs : 0)));
680 Thead = THead(CBtime(time_out));
686 register afs_uint32 hash;
691 fe->volid = fid->Volume;
692 fe->vnode = fid->Vnode;
693 fe->unique = fid->Unique;
695 hash = VHash(fid->Volume, fid->Unique);
696 fe->fnext = HashTable[hash];
697 HashTable[hash] = fetoi(fe);
699 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
700 lastcb = cb, cb = itocb(cb->cnext), safety++) {
701 if (safety > cbstuff.nblks) {
702 ViceLog(0, ("AddCallBack1: Internal Error -- shutting down.\n"));
704 ShutDownAndCore(PANIC);
706 if (cb->hhead == h_htoi(host))
709 if (cb) { /* Already have call back: move to new timeout list */
710 /* don't change delayed callbacks back to normal ones */
711 if (cb->status != CB_DELAYED)
713 /* Only move if new timeout is longer */
714 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
721 *(lastcb ? &lastcb->cnext : &fe->firstcb) = cbtoi(cb);
724 cb->fhead = fetoi(fe);
730 /* now free any still-unused callback or host entries */
736 if (!locked) /* freecb and freefe might(?) yield */
739 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK)
740 return time_out - ServerBias; /* Expires sooner at workstation */
745 /* Take an array full of hosts, all held. Break callbacks to them, and
746 * release the holds once you're done, except don't release xhost. xhost
747 * may be NULL. Currently only works for a single Fid in afidp array.
748 * If you want to make this work with multiple fids, you need to fix
749 * the error handling. One approach would be to force a reset if a
750 * multi-fid call fails, or you could add delayed callbacks for each
751 * fid. You probably also need to sort and remove duplicate hosts.
752 * When this is called from the BreakVolumeCallBacks path, it does NOT
753 * force a reset if the RPC fails, it just marks the host down and tries
754 * to create a delayed callback. */
755 /* N.B. be sure that code works when ncbas == 0 */
756 /* N.B. requires all the cba[*].hp pointers to be valid... */
757 /* This routine does not hold a lock on the host for the duration of
758 * the BreakCallBack RPC, which is a significant deviation from tradition.
759 * It _does_ get a lock on the host before setting VenusDown = 1,
760 * which is sufficient only if VenusDown = 0 only happens when the
761 * lock is held over the RPC and the subsequent VenusDown == 0
762 * wherever that is done. */
764 MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
765 struct AFSCBFids *afidp, struct host *xhost)
768 struct rx_connection *conns[MAX_CB_HOSTS];
769 static struct AFSCBs tc = { 0, 0 };
771 assert(ncbas <= MAX_CB_HOSTS);
773 /* set up conns for multi-call */
774 for (i = 0, j = 0; i < ncbas; i++) {
775 struct host *thishost = cba[i].hp;
776 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
779 conns[j++] = thishost->callback_rxcon;
782 rx_SetConnDeadTime(thishost->callback_rxcon, 4);
783 rx_SetConnHardDeadTime(thishost->callback_rxcon, AFS_HARDDEADTIME);
787 if (j) { /* who knows what multi would do with 0 conns? */
791 multi_RXAFSCB_CallBack(afidp, &tc);
798 /* If there's an error, we have to hunt for the right host.
799 * The conns array _should_ correspond one-to-one to the cba
800 * array, except in some rare cases it might be missing one
801 * or more elements. So the optimistic case is almost
802 * always right. At worst, it's the starting point for the
804 for (hp = 0, i = multi_i; i < j; i++) {
805 hp = cba[i].hp; /* optimistic, but usually right */
809 if (conns[multi_i] == hp->callback_rxcon) {
817 ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n", hp,
821 ** try breaking callbacks on alternate interface addresses
823 if (MultiBreakCallBackAlternateAddress(hp, afidp)) {
826 ("BCB: Failed on file %u.%u.%u, host %s:%d is down\n",
827 afidp->AFSCBFids_val->Volume,
828 afidp->AFSCBFids_val->Vnode,
829 afidp->AFSCBFids_val->Unique,
830 afs_inet_ntoa_r(hp->host, hoststr),
836 hp->hostFlags |= VENUSDOWN;
838 * We always go into AddCallBack1_r with the host locked
840 AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
853 for (i = 0; i < ncbas; i++) {
856 if (hp && xhost != hp)
864 * Break all call backs for fid, except for the specified host (unless flag
865 * is true, in which case all get a callback message. Assumption: the specified
866 * host is h_Held, by the caller; the others aren't.
867 * Specified host may be bogus, that's ok. This used to check to see if the
868 * host was down in two places, once right after the host was h_held, and
869 * again after it was locked. That race condition is incredibly rare and
870 * relatively harmless even when it does occur, so we don't check for it now.
872 /* if flag is true, send a break callback msg to "host", too */
874 BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
876 struct FileEntry *fe;
877 struct CallBack *cb, *nextcb;
878 struct cbstruct cba[MAX_CB_HOSTS];
885 ("BCB: BreakCallBack(all but %s:%d, (%u,%u,%u))\n",
886 afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
887 fid->Volume, fid->Vnode, fid->Unique));
890 cbstuff.BreakCallBacks++;
895 hostindex = h_htoi(xhost);
896 cb = itocb(fe->firstcb);
897 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
898 /* the most common case is what follows the || */
901 tf.AFSCBFids_len = 1;
902 tf.AFSCBFids_val = fid;
905 for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
906 nextcb = itocb(cb->cnext);
907 if ((cb->hhead != hostindex || flag)
908 && (cb->status == CB_BULK || cb->status == CB_NORMAL
909 || cb->status == CB_VOLUME)) {
910 struct host *thishost = h_itoh(cb->hhead);
912 ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
913 } else if (thishost->hostFlags & VENUSDOWN) {
915 ("BCB: %s:%d is down; delaying break call back\n",
916 afs_inet_ntoa_r(thishost->host, hoststr),
917 ntohs(thishost->port)));
918 cb->status = CB_DELAYED;
921 cba[ncbas].hp = thishost;
922 cba[ncbas].thead = cb->thead;
926 CDel(cb, 1); /* Usually first; so this delete
927 * is reasonably inexpensive */
933 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
935 /* we need to to all these initializations again because MultiBreakCallBack may block */
940 cb = itocb(fe->firstcb);
941 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
942 /* the most common case is what follows the || */
953 /* Delete (do not break) single call back for fid */
955 DeleteCallBack(struct host *host, AFSFid * fid)
957 register struct FileEntry *fe;
958 register afs_uint32 *pcb;
961 cbstuff.DeleteCallBacks++;
970 ("DCB: No call backs for fid (%u, %u, %u)\n", fid->Volume,
971 fid->Vnode, fid->Unique));
974 pcb = FindCBPtr(fe, host);
977 ("DCB: No call back for host %s:%d, (%u, %u, %u)\n",
978 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
979 fid->Volume, fid->Vnode, fid->Unique));
993 * Delete (do not break) all call backs for fid. This call doesn't
994 * set all of the various host locks, but it shouldn't really matter
995 * since we're not adding callbacks, but deleting them. I'm not sure
996 * why it doesn't set the lock, however; perhaps it should.
999 DeleteFileCallBacks(AFSFid * fid)
1001 register struct FileEntry *fe;
1002 register struct CallBack *cb;
1003 register afs_uint32 cbi;
1007 cbstuff.DeleteFiles++;
1012 ("DF: No fid (%u,%u,%u) to delete\n", fid->Volume, fid->Vnode,
1016 for (n = 0, cbi = fe->firstcb; cbi; n++) {
1028 /* Delete (do not break) all call backs for host. The host should be
1031 DeleteAllCallBacks_r(struct host *host, int deletefe)
1033 register struct CallBack *cb;
1034 register int cbi, first;
1036 cbstuff.DeleteAllCallBacks++;
1037 cbi = first = host->cblist;
1039 ViceLog(8, ("DV: no call backs\n"));
1047 } while (cbi != first);
1053 * Break all delayed call backs for host. Returns 1 if all call backs
1054 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1055 * Must be called with VenusDown set for this host
1058 BreakDelayedCallBacks(struct host *host)
1062 retVal = BreakDelayedCallBacks_r(host);
1068 BreakDelayedCallBacks_r(struct host *host)
1070 struct AFSFid fids[AFSCBMAX];
1071 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1072 int cbi, first, nfids;
1073 struct CallBack *cb;
1077 cbstuff.nbreakers++;
1078 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1079 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1080 if (host->interface) {
1083 RXAFSCB_InitCallBackState3(host->callback_rxcon,
1088 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1091 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1095 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1096 afs_inet_ntoa_r(host->host, hoststr),
1097 ntohs(host->port)));
1099 host->hostFlags |= VENUSDOWN;
1102 ("InitCallBackState success on %s\n",
1103 afs_inet_ntoa_r(host->host, hoststr)));
1104 /* reset was done successfully */
1105 host->hostFlags |= RESETDONE;
1106 host->hostFlags &= ~VENUSDOWN;
1109 while (!(host->hostFlags & HOSTDELETED)) {
1111 host->hostFlags &= ~VENUSDOWN; /* presume up */
1112 cbi = first = host->cblist;
1116 first = host->cblist;
1119 if (cb->status == CB_DELAYED) {
1120 register struct FileEntry *fe = itofe(cb->fhead);
1121 thead[nfids] = cb->thead;
1122 fids[nfids].Volume = fe->volid;
1123 fids[nfids].Vnode = fe->vnode;
1124 fids[nfids].Unique = fe->unique;
1130 } while (cbi && cbi != first && nfids < AFSCBMAX);
1136 if (XCallBackBulk_r(host, fids, nfids)) {
1137 /* Failed, again: put them back, probably with old
1142 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1143 afs_inet_ntoa_r(host->host, hoststr),
1144 ntohs(host->port)));
1146 for (i = 0; i < nfids; i++) {
1149 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1150 afs_inet_ntoa_r(host->host, hoststr),
1151 ntohs(host->port), fids[i].Volume,
1152 fids[i].Vnode, fids[i].Unique));
1155 * AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1156 * * but it turns out to cause too many tricky locking problems.
1157 * * now, if break delayed fails, screw it. */
1159 host->hostFlags |= VENUSDOWN; /* Failed */
1160 ClearHostCallbacks_r(host, 1 /* locked */ );
1164 if (nfids < AFSCBMAX)
1168 cbstuff.nbreakers--;
1169 /* If we succeeded it's always ok to unset HFE_LATER */
1170 if (!host->hostFlags & VENUSDOWN)
1171 host->hostFlags &= ~HFE_LATER;
1172 return (host->hostFlags & VENUSDOWN);
1176 ** isheld is 0 if the host is held in h_Enumerate
1177 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1180 MultiBreakVolumeCallBack_r(struct host *host, int isheld,
1181 struct VCBParams *parms, int deletefe)
1186 return isheld; /* host is held only by h_Enumerate, do nothing */
1187 if (host->hostFlags & HOSTDELETED)
1188 return 0; /* host is deleted, release hold */
1190 if (host->hostFlags & VENUSDOWN) {
1192 if (host->hostFlags & HOSTDELETED) {
1194 return 0; /* Release hold */
1197 ("BVCB: volume call back for host %s:%d failed\n",
1198 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1201 ("CB: volume callback for host %s:%d failed\n",
1202 afs_inet_ntoa_r(host->host, hoststr),
1203 ntohs(host->port)));
1205 DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state
1206 * rather than attempting to
1207 * selectively remember to
1208 * delete the volume callbacks
1210 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1212 return 0; /* release hold */
1214 assert(parms->ncbas <= MAX_CB_HOSTS);
1216 /* Do not call MultiBreakCallBack on the current host structure
1217 ** because it would prematurely release the hold on the host
1219 if (parms->ncbas == MAX_CB_HOSTS) {
1220 struct AFSCBFids tf;
1222 tf.AFSCBFids_len = 1;
1223 tf.AFSCBFids_val = parms->fid;
1225 /* this releases all the hosts */
1226 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */ );
1230 parms->cba[parms->ncbas].hp = host;
1231 parms->cba[(parms->ncbas)++].thead = parms->thead;
1232 return 1; /* DON'T release hold, because we still need it. */
1236 ** isheld is 0 if the host is held in h_Enumerate
1237 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1240 MultiBreakVolumeCallBack(struct host *host, int isheld,
1241 struct VCBParams *parms)
1245 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1251 ** isheld is 0 if the host is held in h_Enumerate
1252 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1255 MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1256 struct VCBParams *parms)
1260 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1266 * Break all call backs on a single volume. Don't call this with any
1267 * hosts h_held. Note that this routine clears the callbacks before
1268 * actually breaking them, and that the vnode isn't locked during this
1269 * operation, so that people might see temporary callback loss while
1270 * this function is executing. It is just a temporary state, however,
1271 * since the callback will be broken later by this same function.
1273 * Now uses multi-RX for CallBack RPC. Note that the
1274 * multiBreakCallBacks routine does not force a reset if the RPC
1275 * fails, unlike the previous version of this routine, but does create
1276 * a delayed callback. Resets will be forced if the host is
1277 * determined to be down before the RPC is executed.
1280 BreakVolumeCallBacks(afs_uint32 volume)
1285 struct CallBack *cb;
1286 struct FileEntry *fe;
1288 struct VCBParams henumParms;
1289 afs_uint32 tthead = 0; /* zero is illegal value */
1292 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1293 for (hash = 0; hash < VHASH; hash++) {
1294 for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
1295 if (fe->volid == volume) {
1296 register struct CallBack *cbnext;
1297 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1298 host = h_itoh(cb->hhead);
1300 cbnext = itocb(cb->cnext);
1301 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1307 /* leave hold for MultiBreakVolumeCallBack to clear */
1318 /* didn't find any callbacks, so return right away. */
1322 henumParms.ncbas = 0;
1323 henumParms.fid = &fid;
1324 henumParms.thead = tthead;
1326 h_Enumerate(MultiBreakVolumeCallBack, (char *)&henumParms);
1328 if (henumParms.ncbas) { /* do left-overs */
1329 struct AFSCBFids tf;
1330 tf.AFSCBFids_len = 1;
1331 tf.AFSCBFids_val = &fid;
1333 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1335 henumParms.ncbas = 0;
1341 #ifdef AFS_PTHREAD_ENV
1342 extern pthread_cond_t fsync_cond;
1344 extern char fsync_wait[];
1348 BreakVolumeCallBacksLater(afs_uint32 volume)
1352 struct FileEntry *fe;
1353 struct CallBack *cb;
1357 ViceLog(25, ("Setting later on volume %u\n", volume));
1359 for (hash = 0; hash < VHASH; hash++) {
1360 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1361 if (fe->volid == volume) {
1362 register struct CallBack *cbnext;
1363 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1364 host = h_itoh(cb->hhead);
1365 host->hostFlags |= HFE_LATER;
1366 cb->status = CB_DELAYED;
1367 cbnext = itocb(cb->cnext);
1370 fe->status |= FE_LATER;
1379 /* didn't find any callbacks, so return right away. */
1383 ViceLog(25, ("Fsync thread wakeup\n"));
1384 #ifdef AFS_PTHREAD_ENV
1385 assert(pthread_cond_broadcast(&fsync_cond) == 0);
1387 LWP_NoYieldSignal(fsync_wait);
1393 BreakLaterCallBacks(void)
1398 struct CallBack *cb;
1399 struct FileEntry *fe = NULL;
1400 struct FileEntry *myfe = NULL;
1402 struct VCBParams henumParms;
1403 unsigned short tthead = 0; /* zero is illegal value */
1406 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1409 /* Pick the first volume we see to clean up */
1410 fid.Volume = fid.Vnode = fid.Unique = 0;
1412 for (hash = 0; hash < VHASH; hash++) {
1413 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1414 if (fe && (fe->status & FE_LATER)
1415 && (fid.Volume == 0 || fid.Volume == fe->volid)) {
1416 /* Ugly, but used to avoid left side casting */
1417 struct object *tmpfe;
1419 ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
1421 fid.Volume = fe->volid;
1423 /* Works since volid is deeper than the largest pointer */
1424 tmpfe = (struct object *)fe;
1425 tmpfe->next = (struct object *)myfe;
1438 /* loop over FEs from myfe and free/break */
1440 for (fe = myfe; fe;) {
1441 register struct CallBack *cbnext;
1442 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1443 host = h_itoh(cb->hhead);
1445 cbnext = itocb(cb->cnext);
1446 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1451 CDel(cb, 0); /* Don't let CDel clean up the fe */
1452 /* leave hold for MultiBreakVolumeCallBack to clear */
1455 fe = (struct FileEntry *)((struct object *)fe)->next;
1460 ViceLog(125, ("Breaking volume %u\n", fid.Volume));
1461 henumParms.ncbas = 0;
1462 henumParms.fid = &fid;
1463 henumParms.thead = tthead;
1465 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *)&henumParms);
1467 if (henumParms.ncbas) { /* do left-overs */
1468 struct AFSCBFids tf;
1469 tf.AFSCBFids_len = 1;
1470 tf.AFSCBFids_val = &fid;
1472 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1473 henumParms.ncbas = 0;
1478 /* Arrange to be called again */
1483 * Delete all timed-out call back entries (to be called periodically by file
1487 CleanupTimedOutCallBacks(void)
1490 CleanupTimedOutCallBacks_r();
1495 CleanupTimedOutCallBacks_r(void)
1497 afs_uint32 now = CBtime(FT_ApproxTime());
1498 register afs_uint32 *thead;
1499 register struct CallBack *cb;
1500 register int ntimedout = 0;
1503 while (tfirst <= now) {
1505 cbi = *(thead = THead(tfirst));
1511 ("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1512 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
1513 h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
1514 itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
1518 if (ntimedout > cbstuff.nblks) {
1519 ViceLog(0, ("CCB: Internal Error -- shutting down...\n"));
1520 DumpCallBackState();
1521 ShutDownAndCore(PANIC);
1523 } while (cbi != *thead);
1528 cbstuff.CBsTimedOut += ntimedout;
1529 ViceLog(7, ("CCB: deleted %d timed out callbacks\n", ntimedout));
1530 return (ntimedout > 0);
1533 static struct host *lih_host;
1534 static int lih_host_held = 0;
1537 lih_r(register struct host *host, register int held,
1538 register struct host *hostp)
1542 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1543 && (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
1553 /* This could be upgraded to get more space each time */
1554 /* first pass: find the oldest host which isn't held by anyone */
1555 /* second pass: find the oldest host who isn't "me" */
1556 /* always called with hostp unlocked */
1557 extern struct host *hostList;
1559 GetSomeSpace_r(struct host *hostp, int locked)
1561 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1564 cbstuff.GotSomeSpaces++;
1566 ("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1567 if (CleanupTimedOutCallBacks_r()) {
1573 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1577 if (!ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
1590 ("GSS: Try harder for longest inactive host cnt= %d\n",
1593 * Next time try getting callbacks from any host even if
1594 * it's deleted (that's actually great since we can freely
1595 * remove its callbacks) or it's held since the only other
1596 * option is starvation for the file server (i.e. until the
1597 * callback timeout arrives).
1603 * No choice to clear this host's callback state
1605 /* third pass: we still haven't gotten any space, so we free what we had
1606 * previously passed over. */
1611 ClearHostCallbacks_r(hostp, 1 /*already locked */ );
1618 /* locked - set if caller has already locked the host */
1620 ClearHostCallbacks_r(struct host *hp, int locked)
1627 ("GSS: Delete longest inactive host %s\n",
1628 afs_inet_ntoa_r(hp->host, hoststr)));
1629 if (!(held = h_Held_r(hp)))
1632 /** Try a non-blocking lock. If the lock is already held return
1633 * after releasing hold on hp
1636 if (h_NBLock_r(hp)) {
1642 if (hp->Console & 2) {
1644 * If the special console field is set it means that a thread
1645 * is waiting in AddCallBack1 after it set pointers to the
1646 * file entry and/or callback entry. Because of the bogus
1647 * usage of h_hold it won't prevent from another thread, this
1648 * one, to remove all the callbacks so just to be safe we keep
1649 * a reference. NOTE, on the last phase we'll free the calling
1650 * host's callbacks but that's ok...
1654 DeleteAllCallBacks_r(hp, 1);
1655 if (hp->hostFlags & VENUSDOWN) {
1656 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1658 /* host is up, try a call */
1659 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1660 if (hp->interface) {
1663 RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1667 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1670 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1672 /* failed, mark host down and need reset */
1673 hp->hostFlags |= VENUSDOWN;
1674 hp->hostFlags &= ~RESETDONE;
1676 /* reset succeeded, we're done */
1677 hp->hostFlags |= RESETDONE;
1688 #endif /* INTERPRET_DUMP */
1692 PrintCallBackStats(void)
1695 "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1696 cbstuff.AddCallBacks, cbstuff.BreakCallBacks,
1697 cbstuff.DeleteCallBacks, cbstuff.DeleteFiles, cbstuff.CBsTimedOut,
1698 cbstuff.GotSomeSpaces, cbstuff.DeleteAllCallBacks);
1699 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1700 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs + cbstuff.nFEs,
1706 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1708 #ifndef INTERPRET_DUMP
1711 DumpCallBackState(void)
1714 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1716 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY | O_CREAT | O_TRUNC,
1720 ("Couldn't create callback dump file %s\n",
1721 AFSDIR_SERVER_CBKDUMP_FILEPATH));
1724 (void)write(fd, &magic, sizeof(magic));
1725 (void)write(fd, &now, sizeof(now));
1726 (void)write(fd, &cbstuff, sizeof(cbstuff));
1727 (void)write(fd, TimeOuts, sizeof(TimeOuts));
1728 (void)write(fd, timeout, sizeof(timeout));
1729 (void)write(fd, &tfirst, sizeof(tfirst));
1730 freelisthead = cbtoi((struct CallBack *)CBfree);
1731 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1732 freelisthead = fetoi((struct FileEntry *)FEfree);
1733 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1734 (void)write(fd, HashTable, sizeof(HashTable));
1735 (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1736 (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1744 #ifdef INTERPRET_DUMP
1746 /* This is only compiled in for the callback analyzer program */
1747 /* Returns the time of the dump */
1749 ReadDump(char *file)
1752 afs_uint32 magic, freelisthead;
1755 fd = open(file, O_RDONLY);
1757 fprintf(stderr, "Couldn't read dump file %s\n", file);
1760 read(fd, &magic, sizeof(magic));
1761 if (magic != MAGIC) {
1763 "Magic number of %s is invalid. You might be trying to\n",
1766 "run this program on a machine type with a different byte ordering.\n");
1769 read(fd, &now, sizeof(now));
1770 read(fd, &cbstuff, sizeof(cbstuff));
1771 read(fd, TimeOuts, sizeof(TimeOuts));
1772 read(fd, timeout, sizeof(timeout));
1773 read(fd, &tfirst, sizeof(tfirst));
1774 read(fd, &freelisthead, sizeof(freelisthead));
1775 CB = ((struct CallBack
1776 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1777 FE = ((struct FileEntry
1778 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1779 CBfree = (struct CallBack *)itocb(freelisthead);
1780 read(fd, &freelisthead, sizeof(freelisthead));
1781 FEfree = (struct FileEntry *)itofe(freelisthead);
1782 read(fd, HashTable, sizeof(HashTable));
1783 read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1784 read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1786 perror("Error reading dumpfile");
1792 #include "AFS_component_version_number.c"
1795 main(int argc, char **argv)
1797 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1799 register struct FileEntry *fe;
1800 register struct CallBack *cb;
1803 memset(&fid, 0, sizeof(fid));
1806 while (argc && **argv == '-') {
1809 if (!strcmp(*argv, "-host")) {
1815 cbi = atoi(*++argv);
1816 } else if (!strcmp(*argv, "-fid")) {
1822 fid.Volume = atoi(*++argv);
1823 fid.Vnode = atoi(*++argv);
1824 fid.Unique = atoi(*++argv);
1825 } else if (!strcmp(*argv, "-time")) {
1826 fprintf(stderr, "-time not supported\n");
1828 } else if (!strcmp(*argv, "-stats")) {
1830 } else if (!strcmp(*argv, "-all")) {
1832 } else if (!strcmp(*argv, "-raw")) {
1834 } else if (!strcmp(*argv, "-volume")) {
1840 vol = atoi(*++argv);
1845 if (err || argc != 1) {
1847 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
1849 "[cbid is shown for each host in the hosts.dump file]\n");
1852 now = ReadDump(*argv);
1853 if (stats || noptions == 0) {
1854 time_t uxtfirst = UXtime(tfirst);
1855 printf("The time of the dump was %u %s", now, ctime(&now));
1856 printf("The last time cleanup ran was %u %s", uxtfirst,
1858 PrintCallBackStats();
1862 register afs_uint32 *feip;
1863 register struct CallBack *cb;
1864 register struct FileEntry *fe;
1866 for (hash = 0; hash < VHASH; hash++) {
1867 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1868 if (!vol || (fe->volid == vol)) {
1869 register struct CallBack *cbnext;
1870 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1872 cbnext = itocb(cb->cnext);
1882 afs_uint32 cfirst = cbi;
1887 } while (cbi != cfirst);
1892 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1895 cb = itocb(fe->firstcb);
1898 cb = itocb(cb->cnext);
1902 struct FileEntry *fe;
1904 for (i = 1; i < cbstuff.nblks; i++) {
1905 p = (afs_int32 *) & FE[i];
1906 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1912 PrintCB(register struct CallBack *cb, afs_uint32 now)
1914 struct FileEntry *fe = itofe(cb->fhead);
1915 time_t expires = TIndexToTime(cb->thead);
1917 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1918 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
1919 expires - now, ctime(&expires));
1924 #if !defined(INTERPRET_DUMP)
1926 ** try breaking calbacks on afidp from host. Use multi_rx.
1927 ** return 0 on success, non-zero on failure
1930 MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1934 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1940 MultiBreakCallBackAlternateAddress_r(struct host *host,
1941 struct AFSCBFids *afidp)
1944 struct rx_connection **conns;
1945 struct rx_connection *connSuccess = 0;
1947 static struct rx_securityClass *sc = 0;
1948 static struct AFSCBs tc = { 0, 0 };
1951 /* nothing more can be done */
1952 if (!host->interface)
1953 return 1; /* failure */
1955 assert(host->interface->numberOfInterfaces > 0);
1957 /* the only address is the primary interface */
1958 if (host->interface->numberOfInterfaces == 1)
1959 return 1; /* failure */
1961 /* initialise a security object only once */
1963 sc = rxnull_NewClientSecurityObject();
1965 i = host->interface->numberOfInterfaces;
1966 addr = calloc(i, sizeof(afs_int32));
1967 conns = calloc(i, sizeof(struct rx_connection *));
1968 if (!addr || !conns) {
1970 ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
1974 /* initialize alternate rx connections */
1975 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
1976 /* this is the current primary address */
1977 if (host->host == host->interface->addr[i])
1980 addr[j] = host->interface->addr[i];
1982 rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
1983 rx_SetConnDeadTime(conns[j], 2);
1984 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1988 assert(j); /* at least one alternate address */
1990 ("Starting multibreakcall back on all addr for host %s\n",
1991 afs_inet_ntoa_r(host->host, hoststr)));
1993 multi_Rx(conns, j) {
1994 multi_RXAFSCB_CallBack(afidp, &tc);
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);
2006 ("multibreakcall success with addr %s\n",
2007 afs_inet_ntoa_r(addr[multi_i], hoststr)));
2014 /* Destroy all connections except the one on which we succeeded */
2015 for (i = 0; i < j; i++)
2016 if (conns[i] != connSuccess)
2017 rx_DestroyConnection(conns[i]);
2023 return 0; /* success */
2025 return 1; /* failure */
2030 ** try multiRX probes to host.
2031 ** return 0 on success, non-zero on failure
2034 MultiProbeAlternateAddress_r(struct host *host)
2037 struct rx_connection **conns;
2038 struct rx_connection *connSuccess = 0;
2040 static struct rx_securityClass *sc = 0;
2043 /* nothing more can be done */
2044 if (!host->interface)
2045 return 1; /* failure */
2047 assert(host->interface->numberOfInterfaces > 0);
2049 /* the only address is the primary interface */
2050 if (host->interface->numberOfInterfaces == 1)
2051 return 1; /* failure */
2053 /* initialise a security object only once */
2055 sc = rxnull_NewClientSecurityObject();
2057 i = host->interface->numberOfInterfaces;
2058 addr = calloc(i, sizeof(afs_int32));
2059 conns = calloc(i, sizeof(struct rx_connection *));
2060 if (!addr || !conns) {
2061 ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
2065 /* initialize alternate rx connections */
2066 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2067 /* this is the current primary address */
2068 if (host->host == host->interface->addr[i])
2071 addr[j] = host->interface->addr[i];
2073 rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
2074 rx_SetConnDeadTime(conns[j], 2);
2075 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2079 assert(j); /* at least one alternate address */
2081 ("Starting multiprobe on all addr for host %s\n",
2082 afs_inet_ntoa_r(host->host, hoststr)));
2084 multi_Rx(conns, j) {
2085 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2089 if (host->callback_rxcon)
2090 rx_DestroyConnection(host->callback_rxcon);
2091 host->callback_rxcon = conns[multi_i];
2092 host->host = addr[multi_i];
2093 connSuccess = conns[multi_i];
2094 rx_SetConnDeadTime(host->callback_rxcon, 50);
2095 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2097 ("multiprobe success with addr %s\n",
2098 afs_inet_ntoa_r(addr[multi_i], hoststr)));
2105 /* Destroy all connections except the one on which we succeeded */
2106 for (i = 0; i < j; i++)
2107 if (conns[i] != connSuccess)
2108 rx_DestroyConnection(conns[i]);
2114 return 0; /* success */
2116 return 1; /* failure */
2119 #endif /* !defined(INTERPRET_DUMP) */