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 int opt_TO; /* secs, but internal adaptive parms are in ms */
770 static struct AFSCBs tc = { 0, 0 };
772 assert(ncbas <= MAX_CB_HOSTS);
774 /* set up conns for multi-call */
775 for (i = 0, j = 0; i < ncbas; i++) {
776 struct host *thishost = cba[i].hp;
777 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
780 conns[j++] = thishost->callback_rxcon;
783 rx_SetConnDeadTime(thishost->callback_rxcon, 4);
784 rx_SetConnHardDeadTime(thishost->callback_rxcon, AFS_HARDDEADTIME);
788 if (j) { /* who knows what multi would do with 0 conns? */
792 multi_RXAFSCB_CallBack(afidp, &tc);
799 /* If there's an error, we have to hunt for the right host.
800 * The conns array _should_ correspond one-to-one to the cba
801 * array, except in some rare cases it might be missing one
802 * or more elements. So the optimistic case is almost
803 * always right. At worst, it's the starting point for the
805 for (hp = 0, i = multi_i; i < j; i++) {
806 hp = cba[i].hp; /* optimistic, but usually right */
810 if (conns[multi_i] == hp->callback_rxcon) {
818 ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n", hp,
822 ** try breaking callbacks on alternate interface addresses
824 if (MultiBreakCallBackAlternateAddress(hp, afidp)) {
827 ("BCB: Failed on file %u.%u.%u, host %s:%d is down\n",
828 afidp->AFSCBFids_val->Volume,
829 afidp->AFSCBFids_val->Vnode,
830 afidp->AFSCBFids_val->Unique,
831 afs_inet_ntoa_r(hp->host, hoststr),
837 hp->hostFlags |= VENUSDOWN;
839 * We always go into AddCallBack1_r with the host locked
841 AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
854 for (i = 0; i < ncbas; i++) {
857 if (hp && xhost != hp)
865 * Break all call backs for fid, except for the specified host (unless flag
866 * is true, in which case all get a callback message. Assumption: the specified
867 * host is h_Held, by the caller; the others aren't.
868 * Specified host may be bogus, that's ok. This used to check to see if the
869 * host was down in two places, once right after the host was h_held, and
870 * again after it was locked. That race condition is incredibly rare and
871 * relatively harmless even when it does occur, so we don't check for it now.
873 /* if flag is true, send a break callback msg to "host", too */
875 BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
877 struct FileEntry *fe;
878 struct CallBack *cb, *nextcb;
879 struct cbstruct cba[MAX_CB_HOSTS];
881 struct rx_connection *conns[MAX_CB_HOSTS];
887 ("BCB: BreakCallBack(all but %s:%d, (%u,%u,%u))\n",
888 afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
889 fid->Volume, fid->Vnode, fid->Unique));
892 cbstuff.BreakCallBacks++;
897 hostindex = h_htoi(xhost);
898 cb = itocb(fe->firstcb);
899 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
900 /* the most common case is what follows the || */
903 tf.AFSCBFids_len = 1;
904 tf.AFSCBFids_val = fid;
907 for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
908 nextcb = itocb(cb->cnext);
909 if ((cb->hhead != hostindex || flag)
910 && (cb->status == CB_BULK || cb->status == CB_NORMAL
911 || cb->status == CB_VOLUME)) {
912 struct host *thishost = h_itoh(cb->hhead);
914 ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
915 } else if (thishost->hostFlags & VENUSDOWN) {
917 ("BCB: %s:%d is down; delaying break call back\n",
918 afs_inet_ntoa_r(thishost->host, hoststr),
919 ntohs(thishost->port)));
920 cb->status = CB_DELAYED;
923 cba[ncbas].hp = thishost;
924 cba[ncbas].thead = cb->thead;
928 CDel(cb, 1); /* Usually first; so this delete
929 * is reasonably inexpensive */
935 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
937 /* we need to to all these initializations again because MultiBreakCallBack may block */
942 cb = itocb(fe->firstcb);
943 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
944 /* the most common case is what follows the || */
955 /* Delete (do not break) single call back for fid */
957 DeleteCallBack(struct host *host, AFSFid * fid)
959 register struct FileEntry *fe;
960 register afs_uint32 *pcb;
963 cbstuff.DeleteCallBacks++;
972 ("DCB: No call backs for fid (%u, %u, %u)\n", fid->Volume,
973 fid->Vnode, fid->Unique));
976 pcb = FindCBPtr(fe, host);
979 ("DCB: No call back for host %s:%d, (%u, %u, %u)\n",
980 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
981 fid->Volume, fid->Vnode, fid->Unique));
995 * Delete (do not break) all call backs for fid. This call doesn't
996 * set all of the various host locks, but it shouldn't really matter
997 * since we're not adding callbacks, but deleting them. I'm not sure
998 * why it doesn't set the lock, however; perhaps it should.
1001 DeleteFileCallBacks(AFSFid * fid)
1003 register struct FileEntry *fe;
1004 register struct CallBack *cb;
1005 register afs_uint32 cbi;
1009 cbstuff.DeleteFiles++;
1014 ("DF: No fid (%u,%u,%u) to delete\n", fid->Volume, fid->Vnode,
1018 for (n = 0, cbi = fe->firstcb; cbi; n++) {
1030 /* Delete (do not break) all call backs for host. The host should be
1033 DeleteAllCallBacks_r(struct host *host, int deletefe)
1035 register struct CallBack *cb;
1036 register int cbi, first;
1038 cbstuff.DeleteAllCallBacks++;
1039 cbi = first = host->cblist;
1041 ViceLog(8, ("DV: no call backs\n"));
1049 } while (cbi != first);
1055 * Break all delayed call backs for host. Returns 1 if all call backs
1056 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1057 * Must be called with VenusDown set for this host
1060 BreakDelayedCallBacks(struct host *host)
1064 retVal = BreakDelayedCallBacks_r(host);
1070 BreakDelayedCallBacks_r(struct host *host)
1072 struct AFSFid fids[AFSCBMAX];
1073 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1074 int cbi, first, nfids;
1075 struct CallBack *cb;
1076 struct interfaceAddr interf;
1080 cbstuff.nbreakers++;
1081 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1082 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1083 if (host->interface) {
1086 RXAFSCB_InitCallBackState3(host->callback_rxcon,
1091 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1094 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1098 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1099 afs_inet_ntoa_r(host->host, hoststr),
1100 ntohs(host->port)));
1102 host->hostFlags |= VENUSDOWN;
1105 ("InitCallBackState success on %s\n",
1106 afs_inet_ntoa_r(host->host, hoststr)));
1107 /* reset was done successfully */
1108 host->hostFlags |= RESETDONE;
1109 host->hostFlags &= ~VENUSDOWN;
1112 while (!(host->hostFlags & HOSTDELETED)) {
1114 host->hostFlags &= ~VENUSDOWN; /* presume up */
1115 cbi = first = host->cblist;
1119 first = host->cblist;
1122 if (cb->status == CB_DELAYED) {
1123 register struct FileEntry *fe = itofe(cb->fhead);
1124 thead[nfids] = cb->thead;
1125 fids[nfids].Volume = fe->volid;
1126 fids[nfids].Vnode = fe->vnode;
1127 fids[nfids].Unique = fe->unique;
1133 } while (cbi && cbi != first && nfids < AFSCBMAX);
1139 if (XCallBackBulk_r(host, fids, nfids)) {
1140 /* Failed, again: put them back, probably with old
1145 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1146 afs_inet_ntoa_r(host->host, hoststr),
1147 ntohs(host->port)));
1149 for (i = 0; i < nfids; i++) {
1152 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1153 afs_inet_ntoa_r(host->host, hoststr),
1154 ntohs(host->port), fids[i].Volume,
1155 fids[i].Vnode, fids[i].Unique));
1158 * AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1159 * * but it turns out to cause too many tricky locking problems.
1160 * * now, if break delayed fails, screw it. */
1162 host->hostFlags |= VENUSDOWN; /* Failed */
1163 ClearHostCallbacks_r(host, 1 /* locked */ );
1167 if (nfids < AFSCBMAX)
1171 cbstuff.nbreakers--;
1172 /* If we succeeded it's always ok to unset HFE_LATER */
1173 if (!host->hostFlags & VENUSDOWN)
1174 host->hostFlags &= ~HFE_LATER;
1175 return (host->hostFlags & VENUSDOWN);
1179 ** isheld is 0 if the host is held in h_Enumerate
1180 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1183 MultiBreakVolumeCallBack_r(struct host *host, int isheld,
1184 struct VCBParams *parms, int deletefe)
1189 return isheld; /* host is held only by h_Enumerate, do nothing */
1190 if (host->hostFlags & HOSTDELETED)
1191 return 0; /* host is deleted, release hold */
1193 if (host->hostFlags & VENUSDOWN) {
1195 if (host->hostFlags & HOSTDELETED) {
1197 return 0; /* Release hold */
1200 ("BVCB: volume call back for host %s:%d failed\n",
1201 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1204 ("CB: volume callback for host %s:%d failed\n",
1205 afs_inet_ntoa_r(host->host, hoststr),
1206 ntohs(host->port)));
1208 DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state
1209 * rather than attempting to
1210 * selectively remember to
1211 * delete the volume callbacks
1213 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1215 return 0; /* release hold */
1217 assert(parms->ncbas <= MAX_CB_HOSTS);
1219 /* Do not call MultiBreakCallBack on the current host structure
1220 ** because it would prematurely release the hold on the host
1222 if (parms->ncbas == MAX_CB_HOSTS) {
1223 struct AFSCBFids tf;
1225 tf.AFSCBFids_len = 1;
1226 tf.AFSCBFids_val = parms->fid;
1228 /* this releases all the hosts */
1229 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */ );
1233 parms->cba[parms->ncbas].hp = host;
1234 parms->cba[(parms->ncbas)++].thead = parms->thead;
1235 return 1; /* DON'T release hold, because we still need it. */
1239 ** isheld is 0 if the host is held in h_Enumerate
1240 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1243 MultiBreakVolumeCallBack(struct host *host, int isheld,
1244 struct VCBParams *parms)
1248 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1254 ** isheld is 0 if the host is held in h_Enumerate
1255 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1258 MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1259 struct VCBParams *parms)
1263 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1269 * Break all call backs on a single volume. Don't call this with any
1270 * hosts h_held. Note that this routine clears the callbacks before
1271 * actually breaking them, and that the vnode isn't locked during this
1272 * operation, so that people might see temporary callback loss while
1273 * this function is executing. It is just a temporary state, however,
1274 * since the callback will be broken later by this same function.
1276 * Now uses multi-RX for CallBack RPC. Note that the
1277 * multiBreakCallBacks routine does not force a reset if the RPC
1278 * fails, unlike the previous version of this routine, but does create
1279 * a delayed callback. Resets will be forced if the host is
1280 * determined to be down before the RPC is executed.
1283 BreakVolumeCallBacks(afs_uint32 volume)
1288 struct CallBack *cb;
1289 struct FileEntry *fe;
1291 struct VCBParams henumParms;
1292 afs_uint32 tthead = 0; /* zero is illegal value */
1295 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1296 for (hash = 0; hash < VHASH; hash++) {
1297 for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
1298 if (fe->volid == volume) {
1299 register struct CallBack *cbnext;
1300 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1301 host = h_itoh(cb->hhead);
1303 cbnext = itocb(cb->cnext);
1304 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1310 /* leave hold for MultiBreakVolumeCallBack to clear */
1321 /* didn't find any callbacks, so return right away. */
1325 henumParms.ncbas = 0;
1326 henumParms.fid = &fid;
1327 henumParms.thead = tthead;
1329 h_Enumerate(MultiBreakVolumeCallBack, (char *)&henumParms);
1331 if (henumParms.ncbas) { /* do left-overs */
1332 struct AFSCBFids tf;
1333 tf.AFSCBFids_len = 1;
1334 tf.AFSCBFids_val = &fid;
1336 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1338 henumParms.ncbas = 0;
1344 #ifdef AFS_PTHREAD_ENV
1345 extern pthread_cond_t fsync_cond;
1347 extern char fsync_wait[];
1351 BreakVolumeCallBacksLater(afs_uint32 volume)
1355 struct FileEntry *fe;
1356 struct CallBack *cb;
1360 ViceLog(25, ("Setting later on volume %u\n", volume));
1362 for (hash = 0; hash < VHASH; hash++) {
1363 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1364 if (fe->volid == volume) {
1365 register struct CallBack *cbnext;
1366 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1367 host = h_itoh(cb->hhead);
1368 host->hostFlags |= HFE_LATER;
1369 cb->status = CB_DELAYED;
1370 cbnext = itocb(cb->cnext);
1373 fe->status |= FE_LATER;
1382 /* didn't find any callbacks, so return right away. */
1386 ViceLog(25, ("Fsync thread wakeup\n"));
1387 #ifdef AFS_PTHREAD_ENV
1388 assert(pthread_cond_broadcast(&fsync_cond) == 0);
1390 LWP_NoYieldSignal(fsync_wait);
1396 BreakLaterCallBacks(void)
1401 struct CallBack *cb;
1402 struct FileEntry *fe = NULL;
1403 struct FileEntry *myfe = NULL;
1405 struct VCBParams henumParms;
1406 unsigned short tthead = 0; /* zero is illegal value */
1409 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1412 /* Pick the first volume we see to clean up */
1413 fid.Volume = fid.Vnode = fid.Unique = 0;
1415 for (hash = 0; hash < VHASH; hash++) {
1416 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1417 if (fe && (fe->status & FE_LATER)
1418 && (fid.Volume == 0 || fid.Volume == fe->volid)) {
1419 /* Ugly, but used to avoid left side casting */
1420 struct object *tmpfe;
1422 ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
1424 fid.Volume = fe->volid;
1426 /* Works since volid is deeper than the largest pointer */
1427 tmpfe = (struct object *)fe;
1428 tmpfe->next = (struct object *)myfe;
1441 /* loop over FEs from myfe and free/break */
1443 for (fe = myfe; fe;) {
1444 register struct CallBack *cbnext;
1445 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1446 host = h_itoh(cb->hhead);
1448 cbnext = itocb(cb->cnext);
1449 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1454 CDel(cb, 0); /* Don't let CDel clean up the fe */
1455 /* leave hold for MultiBreakVolumeCallBack to clear */
1458 fe = (struct FileEntry *)((struct object *)fe)->next;
1463 ViceLog(125, ("Breaking volume %u\n", fid.Volume));
1464 henumParms.ncbas = 0;
1465 henumParms.fid = &fid;
1466 henumParms.thead = tthead;
1468 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *)&henumParms);
1470 if (henumParms.ncbas) { /* do left-overs */
1471 struct AFSCBFids tf;
1472 tf.AFSCBFids_len = 1;
1473 tf.AFSCBFids_val = &fid;
1475 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1476 henumParms.ncbas = 0;
1481 /* Arrange to be called again */
1486 * Delete all timed-out call back entries (to be called periodically by file
1490 CleanupTimedOutCallBacks(void)
1493 CleanupTimedOutCallBacks_r();
1498 CleanupTimedOutCallBacks_r(void)
1500 afs_uint32 now = CBtime(FT_ApproxTime());
1501 register afs_uint32 *thead;
1502 register struct CallBack *cb;
1503 register int ntimedout = 0;
1506 while (tfirst <= now) {
1508 cbi = *(thead = THead(tfirst));
1514 ("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1515 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
1516 h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
1517 itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
1521 if (ntimedout > cbstuff.nblks) {
1522 ViceLog(0, ("CCB: Internal Error -- shutting down...\n"));
1523 DumpCallBackState();
1524 ShutDownAndCore(PANIC);
1526 } while (cbi != *thead);
1531 cbstuff.CBsTimedOut += ntimedout;
1532 ViceLog(7, ("CCB: deleted %d timed out callbacks\n", ntimedout));
1533 return (ntimedout > 0);
1536 static struct host *lih_host;
1537 static int lih_host_held = 0;
1540 lih_r(register struct host *host, register int held,
1541 register struct host *hostp)
1545 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1546 && (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
1556 /* This could be upgraded to get more space each time */
1557 /* first pass: find the oldest host which isn't held by anyone */
1558 /* second pass: find the oldest host who isn't "me" */
1559 /* always called with hostp unlocked */
1560 extern struct host *hostList;
1562 GetSomeSpace_r(struct host *hostp, int locked)
1564 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1567 cbstuff.GotSomeSpaces++;
1569 ("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1570 if (CleanupTimedOutCallBacks_r()) {
1576 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1580 if (!ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
1593 ("GSS: Try harder for longest inactive host cnt= %d\n",
1596 * Next time try getting callbacks from any host even if
1597 * it's deleted (that's actually great since we can freely
1598 * remove its callbacks) or it's held since the only other
1599 * option is starvation for the file server (i.e. until the
1600 * callback timeout arrives).
1606 * No choice to clear this host's callback state
1608 /* third pass: we still haven't gotten any space, so we free what we had
1609 * previously passed over. */
1614 ClearHostCallbacks_r(hostp, 1 /*already locked */ );
1621 /* locked - set if caller has already locked the host */
1623 ClearHostCallbacks_r(struct host *hp, int locked)
1625 struct interfaceAddr interf;
1631 ("GSS: Delete longest inactive host %s\n",
1632 afs_inet_ntoa_r(hp->host, hoststr)));
1633 if (!(held = h_Held_r(hp)))
1636 /** Try a non-blocking lock. If the lock is already held return
1637 * after releasing hold on hp
1640 if (h_NBLock_r(hp)) {
1646 if (hp->Console & 2) {
1648 * If the special console field is set it means that a thread
1649 * is waiting in AddCallBack1 after it set pointers to the
1650 * file entry and/or callback entry. Because of the bogus
1651 * usage of h_hold it won't prevent from another thread, this
1652 * one, to remove all the callbacks so just to be safe we keep
1653 * a reference. NOTE, on the last phase we'll free the calling
1654 * host's callbacks but that's ok...
1658 DeleteAllCallBacks_r(hp, 1);
1659 if (hp->hostFlags & VENUSDOWN) {
1660 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1662 /* host is up, try a call */
1663 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1664 if (hp->interface) {
1667 RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1671 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1674 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1676 /* failed, mark host down and need reset */
1677 hp->hostFlags |= VENUSDOWN;
1678 hp->hostFlags &= ~RESETDONE;
1680 /* reset succeeded, we're done */
1681 hp->hostFlags |= RESETDONE;
1692 #endif /* INTERPRET_DUMP */
1696 PrintCallBackStats(void)
1699 "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1700 cbstuff.AddCallBacks, cbstuff.BreakCallBacks,
1701 cbstuff.DeleteCallBacks, cbstuff.DeleteFiles, cbstuff.CBsTimedOut,
1702 cbstuff.GotSomeSpaces, cbstuff.DeleteAllCallBacks);
1703 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1704 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs + cbstuff.nFEs,
1710 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1712 #ifndef INTERPRET_DUMP
1715 DumpCallBackState(void)
1718 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1720 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY | O_CREAT | O_TRUNC,
1724 ("Couldn't create callback dump file %s\n",
1725 AFSDIR_SERVER_CBKDUMP_FILEPATH));
1728 (void)write(fd, &magic, sizeof(magic));
1729 (void)write(fd, &now, sizeof(now));
1730 (void)write(fd, &cbstuff, sizeof(cbstuff));
1731 (void)write(fd, TimeOuts, sizeof(TimeOuts));
1732 (void)write(fd, timeout, sizeof(timeout));
1733 (void)write(fd, &tfirst, sizeof(tfirst));
1734 freelisthead = cbtoi((struct CallBack *)CBfree);
1735 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1736 freelisthead = fetoi((struct FileEntry *)FEfree);
1737 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1738 (void)write(fd, HashTable, sizeof(HashTable));
1739 (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1740 (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1748 #ifdef INTERPRET_DUMP
1750 /* This is only compiled in for the callback analyzer program */
1751 /* Returns the time of the dump */
1753 ReadDump(char *file)
1756 afs_uint32 magic, freelisthead;
1759 fd = open(file, O_RDONLY);
1761 fprintf(stderr, "Couldn't read dump file %s\n", file);
1764 read(fd, &magic, sizeof(magic));
1765 if (magic != MAGIC) {
1767 "Magic number of %s is invalid. You might be trying to\n",
1770 "run this program on a machine type with a different byte ordering.\n");
1773 read(fd, &now, sizeof(now));
1774 read(fd, &cbstuff, sizeof(cbstuff));
1775 read(fd, TimeOuts, sizeof(TimeOuts));
1776 read(fd, timeout, sizeof(timeout));
1777 read(fd, &tfirst, sizeof(tfirst));
1778 read(fd, &freelisthead, sizeof(freelisthead));
1779 CB = ((struct CallBack
1780 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1781 FE = ((struct FileEntry
1782 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1783 CBfree = (struct CallBack *)itocb(freelisthead);
1784 read(fd, &freelisthead, sizeof(freelisthead));
1785 FEfree = (struct FileEntry *)itofe(freelisthead);
1786 read(fd, HashTable, sizeof(HashTable));
1787 read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1788 read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1790 perror("Error reading dumpfile");
1796 #include "AFS_component_version_number.c"
1799 main(int argc, char **argv)
1801 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1803 register struct FileEntry *fe;
1804 register struct CallBack *cb;
1807 memset(&fid, 0, sizeof(fid));
1810 while (argc && **argv == '-') {
1813 if (!strcmp(*argv, "-host")) {
1819 cbi = atoi(*++argv);
1820 } else if (!strcmp(*argv, "-fid")) {
1826 fid.Volume = atoi(*++argv);
1827 fid.Vnode = atoi(*++argv);
1828 fid.Unique = atoi(*++argv);
1829 } else if (!strcmp(*argv, "-time")) {
1830 fprintf(stderr, "-time not supported\n");
1832 } else if (!strcmp(*argv, "-stats")) {
1834 } else if (!strcmp(*argv, "-all")) {
1836 } else if (!strcmp(*argv, "-raw")) {
1838 } else if (!strcmp(*argv, "-volume")) {
1844 vol = atoi(*++argv);
1849 if (err || argc != 1) {
1851 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
1853 "[cbid is shown for each host in the hosts.dump file]\n");
1856 now = ReadDump(*argv);
1857 if (stats || noptions == 0) {
1858 time_t uxtfirst = UXtime(tfirst);
1859 printf("The time of the dump was %u %s", now, ctime(&now));
1860 printf("The last time cleanup ran was %u %s", uxtfirst,
1862 PrintCallBackStats();
1866 register afs_uint32 *feip;
1867 register struct CallBack *cb;
1868 register struct FileEntry *fe;
1870 for (hash = 0; hash < VHASH; hash++) {
1871 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1872 if (!vol || (fe->volid == vol)) {
1873 register struct CallBack *cbnext;
1874 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1876 cbnext = itocb(cb->cnext);
1886 afs_uint32 cfirst = cbi;
1891 } while (cbi != cfirst);
1896 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1899 cb = itocb(fe->firstcb);
1902 cb = itocb(cb->cnext);
1906 struct FileEntry *fe;
1908 for (i = 1; i < cbstuff.nblks; i++) {
1909 p = (afs_int32 *) & FE[i];
1910 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1916 PrintCB(register struct CallBack *cb, afs_uint32 now)
1918 struct FileEntry *fe = itofe(cb->fhead);
1919 time_t expires = TIndexToTime(cb->thead);
1921 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1922 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
1923 expires - now, ctime(&expires));
1928 #if !defined(INTERPRET_DUMP)
1930 ** try breaking calbacks on afidp from host. Use multi_rx.
1931 ** return 0 on success, non-zero on failure
1934 MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1938 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1944 MultiBreakCallBackAlternateAddress_r(struct host *host,
1945 struct AFSCBFids *afidp)
1948 struct rx_connection **conns;
1949 struct rx_connection *connSuccess = 0;
1951 static struct rx_securityClass *sc = 0;
1952 static struct AFSCBs tc = { 0, 0 };
1955 /* nothing more can be done */
1956 if (!host->interface)
1957 return 1; /* failure */
1959 assert(host->interface->numberOfInterfaces > 0);
1961 /* the only address is the primary interface */
1962 if (host->interface->numberOfInterfaces == 1)
1963 return 1; /* failure */
1965 /* initialise a security object only once */
1967 sc = rxnull_NewClientSecurityObject();
1969 i = host->interface->numberOfInterfaces;
1970 addr = calloc(i, sizeof(afs_int32));
1971 conns = calloc(i, sizeof(struct rx_connection *));
1972 if (!addr || !conns) {
1974 ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
1978 /* initialize alternate rx connections */
1979 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
1980 /* this is the current primary address */
1981 if (host->host == host->interface->addr[i])
1984 addr[j] = host->interface->addr[i];
1986 rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
1987 rx_SetConnDeadTime(conns[j], 2);
1988 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1992 assert(j); /* at least one alternate address */
1994 ("Starting multibreakcall back on all addr for host %s\n",
1995 afs_inet_ntoa_r(host->host, hoststr)));
1997 multi_Rx(conns, j) {
1998 multi_RXAFSCB_CallBack(afidp, &tc);
2002 if (host->callback_rxcon)
2003 rx_DestroyConnection(host->callback_rxcon);
2004 host->callback_rxcon = conns[multi_i];
2005 host->host = addr[multi_i];
2006 connSuccess = conns[multi_i];
2007 rx_SetConnDeadTime(host->callback_rxcon, 50);
2008 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2010 ("multibreakcall success with addr %s\n",
2011 afs_inet_ntoa_r(addr[multi_i], hoststr)));
2018 /* Destroy all connections except the one on which we succeeded */
2019 for (i = 0; i < j; i++)
2020 if (conns[i] != connSuccess)
2021 rx_DestroyConnection(conns[i]);
2027 return 0; /* success */
2029 return 1; /* failure */
2034 ** try multiRX probes to host.
2035 ** return 0 on success, non-zero on failure
2038 MultiProbeAlternateAddress_r(struct host *host)
2041 struct rx_connection **conns;
2042 struct rx_connection *connSuccess = 0;
2044 static struct rx_securityClass *sc = 0;
2047 /* nothing more can be done */
2048 if (!host->interface)
2049 return 1; /* failure */
2051 assert(host->interface->numberOfInterfaces > 0);
2053 /* the only address is the primary interface */
2054 if (host->interface->numberOfInterfaces == 1)
2055 return 1; /* failure */
2057 /* initialise a security object only once */
2059 sc = rxnull_NewClientSecurityObject();
2061 i = host->interface->numberOfInterfaces;
2062 addr = calloc(i, sizeof(afs_int32));
2063 conns = calloc(i, sizeof(struct rx_connection *));
2064 if (!addr || !conns) {
2065 ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
2069 /* initialize alternate rx connections */
2070 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2071 /* this is the current primary address */
2072 if (host->host == host->interface->addr[i])
2075 addr[j] = host->interface->addr[i];
2077 rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
2078 rx_SetConnDeadTime(conns[j], 2);
2079 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2083 assert(j); /* at least one alternate address */
2085 ("Starting multiprobe on all addr for host %s\n",
2086 afs_inet_ntoa_r(host->host, hoststr)));
2088 multi_Rx(conns, j) {
2089 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2093 if (host->callback_rxcon)
2094 rx_DestroyConnection(host->callback_rxcon);
2095 host->callback_rxcon = conns[multi_i];
2096 host->host = addr[multi_i];
2097 connSuccess = conns[multi_i];
2098 rx_SetConnDeadTime(host->callback_rxcon, 50);
2099 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2101 ("multiprobe success with addr %s\n",
2102 afs_inet_ntoa_r(addr[multi_i], hoststr)));
2109 /* Destroy all connections except the one on which we succeeded */
2110 for (i = 0; i < j; i++)
2111 if (conns[i] != connSuccess)
2112 rx_DestroyConnection(conns[i]);
2118 return 0; /* success */
2120 return 1; /* failure */
2123 #endif /* !defined(INTERPRET_DUMP) */