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 rx_GetConnection(thishost->callback_rxcon);
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) {
862 /* H_UNLOCK around this so h_FreeConnection does not deadlock.
863 h_FreeConnection should *never* be called on a callback connection,
864 but on 10/27/04 a deadlock occurred where it was, when we know why,
865 this should be reverted. -- shadow */
867 for (i = 0; i < j; i++) {
868 rx_PutConnection(conns[i]);
876 * Break all call backs for fid, except for the specified host (unless flag
877 * is true, in which case all get a callback message. Assumption: the specified
878 * host is h_Held, by the caller; the others aren't.
879 * Specified host may be bogus, that's ok. This used to check to see if the
880 * host was down in two places, once right after the host was h_held, and
881 * again after it was locked. That race condition is incredibly rare and
882 * relatively harmless even when it does occur, so we don't check for it now.
884 /* if flag is true, send a break callback msg to "host", too */
886 BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
888 struct FileEntry *fe;
889 struct CallBack *cb, *nextcb;
890 struct cbstruct cba[MAX_CB_HOSTS];
897 ("BCB: BreakCallBack(all but %s:%d, (%u,%u,%u))\n",
898 afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
899 fid->Volume, fid->Vnode, fid->Unique));
902 cbstuff.BreakCallBacks++;
907 hostindex = h_htoi(xhost);
908 cb = itocb(fe->firstcb);
909 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
910 /* the most common case is what follows the || */
913 tf.AFSCBFids_len = 1;
914 tf.AFSCBFids_val = fid;
917 for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
918 nextcb = itocb(cb->cnext);
919 if ((cb->hhead != hostindex || flag)
920 && (cb->status == CB_BULK || cb->status == CB_NORMAL
921 || cb->status == CB_VOLUME)) {
922 struct host *thishost = h_itoh(cb->hhead);
924 ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
925 } else if (thishost->hostFlags & VENUSDOWN) {
927 ("BCB: %s:%d is down; delaying break call back\n",
928 afs_inet_ntoa_r(thishost->host, hoststr),
929 ntohs(thishost->port)));
930 cb->status = CB_DELAYED;
933 cba[ncbas].hp = thishost;
934 cba[ncbas].thead = cb->thead;
938 CDel(cb, 1); /* Usually first; so this delete
939 * is reasonably inexpensive */
945 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
947 /* we need to to all these initializations again because MultiBreakCallBack may block */
952 cb = itocb(fe->firstcb);
953 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
954 /* the most common case is what follows the || */
965 /* Delete (do not break) single call back for fid */
967 DeleteCallBack(struct host *host, AFSFid * fid)
969 register struct FileEntry *fe;
970 register afs_uint32 *pcb;
973 cbstuff.DeleteCallBacks++;
982 ("DCB: No call backs for fid (%u, %u, %u)\n", fid->Volume,
983 fid->Vnode, fid->Unique));
986 pcb = FindCBPtr(fe, host);
989 ("DCB: No call back for host %s:%d, (%u, %u, %u)\n",
990 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
991 fid->Volume, fid->Vnode, fid->Unique));
1005 * Delete (do not break) all call backs for fid. This call doesn't
1006 * set all of the various host locks, but it shouldn't really matter
1007 * since we're not adding callbacks, but deleting them. I'm not sure
1008 * why it doesn't set the lock, however; perhaps it should.
1011 DeleteFileCallBacks(AFSFid * fid)
1013 register struct FileEntry *fe;
1014 register struct CallBack *cb;
1015 register afs_uint32 cbi;
1019 cbstuff.DeleteFiles++;
1024 ("DF: No fid (%u,%u,%u) to delete\n", fid->Volume, fid->Vnode,
1028 for (n = 0, cbi = fe->firstcb; cbi; n++) {
1040 /* Delete (do not break) all call backs for host. The host should be
1043 DeleteAllCallBacks_r(struct host *host, int deletefe)
1045 register struct CallBack *cb;
1046 register int cbi, first;
1048 cbstuff.DeleteAllCallBacks++;
1049 cbi = first = host->cblist;
1051 ViceLog(8, ("DV: no call backs\n"));
1059 } while (cbi != first);
1065 * Break all delayed call backs for host. Returns 1 if all call backs
1066 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1067 * Must be called with VenusDown set for this host
1070 BreakDelayedCallBacks(struct host *host)
1074 retVal = BreakDelayedCallBacks_r(host);
1080 BreakDelayedCallBacks_r(struct host *host)
1082 struct AFSFid fids[AFSCBMAX];
1083 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1084 int cbi, first, nfids;
1085 struct CallBack *cb;
1089 cbstuff.nbreakers++;
1090 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1091 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1092 if (host->interface) {
1095 RXAFSCB_InitCallBackState3(host->callback_rxcon,
1100 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1103 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1107 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1108 afs_inet_ntoa_r(host->host, hoststr),
1109 ntohs(host->port)));
1111 host->hostFlags |= VENUSDOWN;
1114 ("InitCallBackState success on %s\n",
1115 afs_inet_ntoa_r(host->host, hoststr)));
1116 /* reset was done successfully */
1117 host->hostFlags |= RESETDONE;
1118 host->hostFlags &= ~VENUSDOWN;
1121 while (!(host->hostFlags & HOSTDELETED)) {
1123 host->hostFlags &= ~VENUSDOWN; /* presume up */
1124 cbi = first = host->cblist;
1128 first = host->cblist;
1131 if (cb->status == CB_DELAYED) {
1132 register struct FileEntry *fe = itofe(cb->fhead);
1133 thead[nfids] = cb->thead;
1134 fids[nfids].Volume = fe->volid;
1135 fids[nfids].Vnode = fe->vnode;
1136 fids[nfids].Unique = fe->unique;
1142 } while (cbi && cbi != first && nfids < AFSCBMAX);
1148 if (XCallBackBulk_r(host, fids, nfids)) {
1149 /* Failed, again: put them back, probably with old
1154 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1155 afs_inet_ntoa_r(host->host, hoststr),
1156 ntohs(host->port)));
1158 for (i = 0; i < nfids; i++) {
1161 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1162 afs_inet_ntoa_r(host->host, hoststr),
1163 ntohs(host->port), fids[i].Volume,
1164 fids[i].Vnode, fids[i].Unique));
1167 * AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1168 * * but it turns out to cause too many tricky locking problems.
1169 * * now, if break delayed fails, screw it. */
1171 host->hostFlags |= VENUSDOWN; /* Failed */
1172 ClearHostCallbacks_r(host, 1 /* locked */ );
1176 if (nfids < AFSCBMAX)
1180 cbstuff.nbreakers--;
1181 /* If we succeeded it's always ok to unset HFE_LATER */
1182 if (!host->hostFlags & VENUSDOWN)
1183 host->hostFlags &= ~HFE_LATER;
1184 return (host->hostFlags & VENUSDOWN);
1188 ** isheld is 0 if the host is held in h_Enumerate
1189 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1192 MultiBreakVolumeCallBack_r(struct host *host, int isheld,
1193 struct VCBParams *parms, int deletefe)
1198 return isheld; /* host is held only by h_Enumerate, do nothing */
1199 if (host->hostFlags & HOSTDELETED)
1200 return 0; /* host is deleted, release hold */
1202 if (host->hostFlags & VENUSDOWN) {
1204 if (host->hostFlags & HOSTDELETED) {
1206 return 0; /* Release hold */
1209 ("BVCB: volume call back for host %s:%d failed\n",
1210 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1213 ("CB: volume callback for host %s:%d failed\n",
1214 afs_inet_ntoa_r(host->host, hoststr),
1215 ntohs(host->port)));
1217 DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state
1218 * rather than attempting to
1219 * selectively remember to
1220 * delete the volume callbacks
1222 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1224 return 0; /* release hold */
1226 assert(parms->ncbas <= MAX_CB_HOSTS);
1228 /* Do not call MultiBreakCallBack on the current host structure
1229 ** because it would prematurely release the hold on the host
1231 if (parms->ncbas == MAX_CB_HOSTS) {
1232 struct AFSCBFids tf;
1234 tf.AFSCBFids_len = 1;
1235 tf.AFSCBFids_val = parms->fid;
1237 /* this releases all the hosts */
1238 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */ );
1242 parms->cba[parms->ncbas].hp = host;
1243 parms->cba[(parms->ncbas)++].thead = parms->thead;
1244 return 1; /* DON'T release hold, because we still need it. */
1248 ** isheld is 0 if the host is held in h_Enumerate
1249 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1252 MultiBreakVolumeCallBack(struct host *host, int isheld,
1253 struct VCBParams *parms)
1257 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1263 ** isheld is 0 if the host is held in h_Enumerate
1264 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1267 MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1268 struct VCBParams *parms)
1272 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1278 * Break all call backs on a single volume. Don't call this with any
1279 * hosts h_held. Note that this routine clears the callbacks before
1280 * actually breaking them, and that the vnode isn't locked during this
1281 * operation, so that people might see temporary callback loss while
1282 * this function is executing. It is just a temporary state, however,
1283 * since the callback will be broken later by this same function.
1285 * Now uses multi-RX for CallBack RPC. Note that the
1286 * multiBreakCallBacks routine does not force a reset if the RPC
1287 * fails, unlike the previous version of this routine, but does create
1288 * a delayed callback. Resets will be forced if the host is
1289 * determined to be down before the RPC is executed.
1292 BreakVolumeCallBacks(afs_uint32 volume)
1297 struct CallBack *cb;
1298 struct FileEntry *fe;
1300 struct VCBParams henumParms;
1301 afs_uint32 tthead = 0; /* zero is illegal value */
1304 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1305 for (hash = 0; hash < VHASH; hash++) {
1306 for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
1307 if (fe->volid == volume) {
1308 register struct CallBack *cbnext;
1309 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1310 host = h_itoh(cb->hhead);
1312 cbnext = itocb(cb->cnext);
1313 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1319 /* leave hold for MultiBreakVolumeCallBack to clear */
1330 /* didn't find any callbacks, so return right away. */
1334 henumParms.ncbas = 0;
1335 henumParms.fid = &fid;
1336 henumParms.thead = tthead;
1338 h_Enumerate(MultiBreakVolumeCallBack, (char *)&henumParms);
1340 if (henumParms.ncbas) { /* do left-overs */
1341 struct AFSCBFids tf;
1342 tf.AFSCBFids_len = 1;
1343 tf.AFSCBFids_val = &fid;
1345 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1347 henumParms.ncbas = 0;
1353 #ifdef AFS_PTHREAD_ENV
1354 extern pthread_cond_t fsync_cond;
1356 extern char fsync_wait[];
1360 BreakVolumeCallBacksLater(afs_uint32 volume)
1364 struct FileEntry *fe;
1365 struct CallBack *cb;
1369 ViceLog(25, ("Setting later on volume %u\n", volume));
1371 for (hash = 0; hash < VHASH; hash++) {
1372 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1373 if (fe->volid == volume) {
1374 register struct CallBack *cbnext;
1375 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1376 host = h_itoh(cb->hhead);
1377 host->hostFlags |= HFE_LATER;
1378 cb->status = CB_DELAYED;
1379 cbnext = itocb(cb->cnext);
1382 fe->status |= FE_LATER;
1391 /* didn't find any callbacks, so return right away. */
1395 ViceLog(25, ("Fsync thread wakeup\n"));
1396 #ifdef AFS_PTHREAD_ENV
1397 assert(pthread_cond_broadcast(&fsync_cond) == 0);
1399 LWP_NoYieldSignal(fsync_wait);
1405 BreakLaterCallBacks(void)
1410 struct CallBack *cb;
1411 struct FileEntry *fe = NULL;
1412 struct FileEntry *myfe = NULL;
1414 struct VCBParams henumParms;
1415 unsigned short tthead = 0; /* zero is illegal value */
1418 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1421 /* Pick the first volume we see to clean up */
1422 fid.Volume = fid.Vnode = fid.Unique = 0;
1424 for (hash = 0; hash < VHASH; hash++) {
1425 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1426 if (fe && (fe->status & FE_LATER)
1427 && (fid.Volume == 0 || fid.Volume == fe->volid)) {
1428 /* Ugly, but used to avoid left side casting */
1429 struct object *tmpfe;
1431 ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
1433 fid.Volume = fe->volid;
1435 /* Works since volid is deeper than the largest pointer */
1436 tmpfe = (struct object *)fe;
1437 tmpfe->next = (struct object *)myfe;
1450 /* loop over FEs from myfe and free/break */
1452 for (fe = myfe; fe;) {
1453 register struct CallBack *cbnext;
1454 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1455 host = h_itoh(cb->hhead);
1457 cbnext = itocb(cb->cnext);
1458 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1463 CDel(cb, 0); /* Don't let CDel clean up the fe */
1464 /* leave hold for MultiBreakVolumeCallBack to clear */
1467 fe = (struct FileEntry *)((struct object *)fe)->next;
1472 ViceLog(125, ("Breaking volume %u\n", fid.Volume));
1473 henumParms.ncbas = 0;
1474 henumParms.fid = &fid;
1475 henumParms.thead = tthead;
1477 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *)&henumParms);
1479 if (henumParms.ncbas) { /* do left-overs */
1480 struct AFSCBFids tf;
1481 tf.AFSCBFids_len = 1;
1482 tf.AFSCBFids_val = &fid;
1484 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1485 henumParms.ncbas = 0;
1490 /* Arrange to be called again */
1495 * Delete all timed-out call back entries (to be called periodically by file
1499 CleanupTimedOutCallBacks(void)
1502 CleanupTimedOutCallBacks_r();
1508 CleanupTimedOutCallBacks_r(void)
1510 afs_uint32 now = CBtime(FT_ApproxTime());
1511 register afs_uint32 *thead;
1512 register struct CallBack *cb;
1513 register int ntimedout = 0;
1516 while (tfirst <= now) {
1518 cbi = *(thead = THead(tfirst));
1524 ("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1525 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
1526 h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
1527 itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
1531 if (ntimedout > cbstuff.nblks) {
1532 ViceLog(0, ("CCB: Internal Error -- shutting down...\n"));
1533 DumpCallBackState();
1534 ShutDownAndCore(PANIC);
1536 } while (cbi != *thead);
1541 cbstuff.CBsTimedOut += ntimedout;
1542 ViceLog(7, ("CCB: deleted %d timed out callbacks\n", ntimedout));
1543 return (ntimedout > 0);
1546 static struct host *lih_host;
1547 static int lih_host_held = 0;
1550 lih_r(register struct host *host, register int held,
1551 register struct host *hostp)
1555 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1556 && (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
1566 /* This could be upgraded to get more space each time */
1567 /* first pass: find the oldest host which isn't held by anyone */
1568 /* second pass: find the oldest host who isn't "me" */
1569 /* always called with hostp unlocked */
1570 extern struct host *hostList;
1572 GetSomeSpace_r(struct host *hostp, int locked)
1574 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1577 cbstuff.GotSomeSpaces++;
1579 ("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1580 if (CleanupTimedOutCallBacks_r()) {
1586 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1590 if (!ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
1603 ("GSS: Try harder for longest inactive host cnt= %d\n",
1606 * Next time try getting callbacks from any host even if
1607 * it's deleted (that's actually great since we can freely
1608 * remove its callbacks) or it's held since the only other
1609 * option is starvation for the file server (i.e. until the
1610 * callback timeout arrives).
1616 * No choice to clear this host's callback state
1618 /* third pass: we still haven't gotten any space, so we free what we had
1619 * previously passed over. */
1624 ClearHostCallbacks_r(hostp, 1 /*already locked */ );
1631 /* locked - set if caller has already locked the host */
1633 ClearHostCallbacks_r(struct host *hp, int locked)
1640 ("GSS: Delete longest inactive host %s\n",
1641 afs_inet_ntoa_r(hp->host, hoststr)));
1642 if (!(held = h_Held_r(hp)))
1645 /** Try a non-blocking lock. If the lock is already held return
1646 * after releasing hold on hp
1649 if (h_NBLock_r(hp)) {
1655 if (hp->Console & 2) {
1657 * If the special console field is set it means that a thread
1658 * is waiting in AddCallBack1 after it set pointers to the
1659 * file entry and/or callback entry. Because of the bogus
1660 * usage of h_hold it won't prevent from another thread, this
1661 * one, to remove all the callbacks so just to be safe we keep
1662 * a reference. NOTE, on the last phase we'll free the calling
1663 * host's callbacks but that's ok...
1667 DeleteAllCallBacks_r(hp, 1);
1668 if (hp->hostFlags & VENUSDOWN) {
1669 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1671 /* host is up, try a call */
1672 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1673 if (hp->interface) {
1676 RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1680 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1683 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1685 /* failed, mark host down and need reset */
1686 hp->hostFlags |= VENUSDOWN;
1687 hp->hostFlags &= ~RESETDONE;
1689 /* reset succeeded, we're done */
1690 hp->hostFlags |= RESETDONE;
1701 #endif /* INTERPRET_DUMP */
1705 PrintCallBackStats(void)
1708 "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1709 cbstuff.AddCallBacks, cbstuff.BreakCallBacks,
1710 cbstuff.DeleteCallBacks, cbstuff.DeleteFiles, cbstuff.CBsTimedOut,
1711 cbstuff.GotSomeSpaces, cbstuff.DeleteAllCallBacks);
1712 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1713 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs + cbstuff.nFEs,
1719 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1721 #ifndef INTERPRET_DUMP
1724 DumpCallBackState(void)
1727 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1729 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY | O_CREAT | O_TRUNC,
1733 ("Couldn't create callback dump file %s\n",
1734 AFSDIR_SERVER_CBKDUMP_FILEPATH));
1737 (void)write(fd, &magic, sizeof(magic));
1738 (void)write(fd, &now, sizeof(now));
1739 (void)write(fd, &cbstuff, sizeof(cbstuff));
1740 (void)write(fd, TimeOuts, sizeof(TimeOuts));
1741 (void)write(fd, timeout, sizeof(timeout));
1742 (void)write(fd, &tfirst, sizeof(tfirst));
1743 freelisthead = cbtoi((struct CallBack *)CBfree);
1744 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1745 freelisthead = fetoi((struct FileEntry *)FEfree);
1746 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1747 (void)write(fd, HashTable, sizeof(HashTable));
1748 (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1749 (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1757 #ifdef INTERPRET_DUMP
1759 /* This is only compiled in for the callback analyzer program */
1760 /* Returns the time of the dump */
1762 ReadDump(char *file)
1765 afs_uint32 magic, freelisthead;
1768 fd = open(file, O_RDONLY);
1770 fprintf(stderr, "Couldn't read dump file %s\n", file);
1773 read(fd, &magic, sizeof(magic));
1774 if (magic != MAGIC) {
1776 "Magic number of %s is invalid. You might be trying to\n",
1779 "run this program on a machine type with a different byte ordering.\n");
1782 read(fd, &now, sizeof(now));
1783 read(fd, &cbstuff, sizeof(cbstuff));
1784 read(fd, TimeOuts, sizeof(TimeOuts));
1785 read(fd, timeout, sizeof(timeout));
1786 read(fd, &tfirst, sizeof(tfirst));
1787 read(fd, &freelisthead, sizeof(freelisthead));
1788 CB = ((struct CallBack
1789 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1790 FE = ((struct FileEntry
1791 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1792 CBfree = (struct CallBack *)itocb(freelisthead);
1793 read(fd, &freelisthead, sizeof(freelisthead));
1794 FEfree = (struct FileEntry *)itofe(freelisthead);
1795 read(fd, HashTable, sizeof(HashTable));
1796 read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1797 read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1799 perror("Error reading dumpfile");
1805 #include "AFS_component_version_number.c"
1808 main(int argc, char **argv)
1810 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1812 register struct FileEntry *fe;
1813 register struct CallBack *cb;
1816 memset(&fid, 0, sizeof(fid));
1819 while (argc && **argv == '-') {
1822 if (!strcmp(*argv, "-host")) {
1828 cbi = atoi(*++argv);
1829 } else if (!strcmp(*argv, "-fid")) {
1835 fid.Volume = atoi(*++argv);
1836 fid.Vnode = atoi(*++argv);
1837 fid.Unique = atoi(*++argv);
1838 } else if (!strcmp(*argv, "-time")) {
1839 fprintf(stderr, "-time not supported\n");
1841 } else if (!strcmp(*argv, "-stats")) {
1843 } else if (!strcmp(*argv, "-all")) {
1845 } else if (!strcmp(*argv, "-raw")) {
1847 } else if (!strcmp(*argv, "-volume")) {
1853 vol = atoi(*++argv);
1858 if (err || argc != 1) {
1860 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
1862 "[cbid is shown for each host in the hosts.dump file]\n");
1865 now = ReadDump(*argv);
1866 if (stats || noptions == 0) {
1867 time_t uxtfirst = UXtime(tfirst);
1868 printf("The time of the dump was %u %s", now, ctime(&now));
1869 printf("The last time cleanup ran was %u %s", uxtfirst,
1871 PrintCallBackStats();
1875 register afs_uint32 *feip;
1876 register struct CallBack *cb;
1877 register struct FileEntry *fe;
1879 for (hash = 0; hash < VHASH; hash++) {
1880 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1881 if (!vol || (fe->volid == vol)) {
1882 register struct CallBack *cbnext;
1883 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1885 cbnext = itocb(cb->cnext);
1895 afs_uint32 cfirst = cbi;
1900 } while (cbi != cfirst);
1905 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1908 cb = itocb(fe->firstcb);
1911 cb = itocb(cb->cnext);
1915 struct FileEntry *fe;
1917 for (i = 1; i < cbstuff.nblks; i++) {
1918 p = (afs_int32 *) & FE[i];
1919 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1925 PrintCB(register struct CallBack *cb, afs_uint32 now)
1927 struct FileEntry *fe = itofe(cb->fhead);
1928 time_t expires = TIndexToTime(cb->thead);
1930 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1931 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
1932 expires - now, ctime(&expires));
1937 #if !defined(INTERPRET_DUMP)
1939 ** try breaking calbacks on afidp from host. Use multi_rx.
1940 ** return 0 on success, non-zero on failure
1943 MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1947 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1953 MultiBreakCallBackAlternateAddress_r(struct host *host,
1954 struct AFSCBFids *afidp)
1957 struct rx_connection **conns;
1958 struct rx_connection *connSuccess = 0;
1960 static struct rx_securityClass *sc = 0;
1961 static struct AFSCBs tc = { 0, 0 };
1964 /* nothing more can be done */
1965 if (!host->interface)
1966 return 1; /* failure */
1968 assert(host->interface->numberOfInterfaces > 0);
1970 /* the only address is the primary interface */
1971 if (host->interface->numberOfInterfaces == 1)
1972 return 1; /* failure */
1974 /* initialise a security object only once */
1976 sc = rxnull_NewClientSecurityObject();
1978 i = host->interface->numberOfInterfaces;
1979 addr = calloc(i, sizeof(afs_int32));
1980 conns = calloc(i, sizeof(struct rx_connection *));
1981 if (!addr || !conns) {
1983 ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
1987 /* initialize alternate rx connections */
1988 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
1989 /* this is the current primary address */
1990 if (host->host == host->interface->addr[i])
1993 addr[j] = host->interface->addr[i];
1995 rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
1996 rx_SetConnDeadTime(conns[j], 2);
1997 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2001 assert(j); /* at least one alternate address */
2003 ("Starting multibreakcall back on all addr for host %s\n",
2004 afs_inet_ntoa_r(host->host, hoststr)));
2006 multi_Rx(conns, j) {
2007 multi_RXAFSCB_CallBack(afidp, &tc);
2011 if (host->callback_rxcon)
2012 rx_DestroyConnection(host->callback_rxcon);
2013 host->callback_rxcon = conns[multi_i];
2014 host->host = addr[multi_i];
2015 connSuccess = conns[multi_i];
2016 rx_SetConnDeadTime(host->callback_rxcon, 50);
2017 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2019 ("multibreakcall success with addr %s\n",
2020 afs_inet_ntoa_r(addr[multi_i], hoststr)));
2027 /* Destroy all connections except the one on which we succeeded */
2028 for (i = 0; i < j; i++)
2029 if (conns[i] != connSuccess)
2030 rx_DestroyConnection(conns[i]);
2036 return 0; /* success */
2038 return 1; /* failure */
2043 ** try multiRX probes to host.
2044 ** return 0 on success, non-zero on failure
2047 MultiProbeAlternateAddress_r(struct host *host)
2050 struct rx_connection **conns;
2051 struct rx_connection *connSuccess = 0;
2053 static struct rx_securityClass *sc = 0;
2056 /* nothing more can be done */
2057 if (!host->interface)
2058 return 1; /* failure */
2060 assert(host->interface->numberOfInterfaces > 0);
2062 /* the only address is the primary interface */
2063 if (host->interface->numberOfInterfaces == 1)
2064 return 1; /* failure */
2066 /* initialise a security object only once */
2068 sc = rxnull_NewClientSecurityObject();
2070 i = host->interface->numberOfInterfaces;
2071 addr = calloc(i, sizeof(afs_int32));
2072 conns = calloc(i, sizeof(struct rx_connection *));
2073 if (!addr || !conns) {
2074 ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
2078 /* initialize alternate rx connections */
2079 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2080 /* this is the current primary address */
2081 if (host->host == host->interface->addr[i])
2084 addr[j] = host->interface->addr[i];
2086 rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
2087 rx_SetConnDeadTime(conns[j], 2);
2088 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2092 assert(j); /* at least one alternate address */
2094 ("Starting multiprobe on all addr for host %s\n",
2095 afs_inet_ntoa_r(host->host, hoststr)));
2097 multi_Rx(conns, j) {
2098 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2102 if (host->callback_rxcon)
2103 rx_DestroyConnection(host->callback_rxcon);
2104 host->callback_rxcon = conns[multi_i];
2105 host->host = addr[multi_i];
2106 connSuccess = conns[multi_i];
2107 rx_SetConnDeadTime(host->callback_rxcon, 50);
2108 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2110 ("multiprobe success with addr %s\n",
2111 afs_inet_ntoa_r(addr[multi_i], hoststr)));
2118 /* Destroy all connections except the one on which we succeeded */
2119 for (i = 0; i < j; i++)
2120 if (conns[i] != connSuccess)
2121 rx_DestroyConnection(conns[i]);
2127 return 0; /* success */
2129 return 1; /* failure */
2132 #endif /* !defined(INTERPRET_DUMP) */