2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * NEW callback package callback.c (replaces vicecb.c)
12 * Updated call back routines, NOW with:
14 * Faster DeleteVenus (Now called DeleteAllCallBacks)
15 * Call back breaking for volumes
16 * Adaptive timeouts on call backs
17 * Architected for Multi RPC
18 * No locks (currently implicit vnode locks--these will go, to)
19 * Delayed call back when rpc connection down.
20 * Bulk break of delayed call backs when rpc connection
22 * Strict limit on number of call backs.
24 * InitCallBack(nblocks)
25 * Initialize: nblocks is max number # of file entries + # of callback entries
26 * nblocks must be < 65536
27 * Space used is nblocks*16 bytes
28 * Note that space will be reclaimed by breaking callbacks of old hosts
30 * time = AddCallBack(host, fid)
32 * Returns the expiration time at the workstation.
34 * BreakCallBack(host, fid)
35 * Break all call backs for fid, except for the specified host.
38 * BreakVolumeCallBacks(volume)
39 * Break all call backs on volume, using single call to each host
40 * Delete all the call backs.
42 * DeleteCallBack(host,fid)
43 * Delete (do not break) single call back for fid.
45 * DeleteFileCallBacks(fid)
46 * Delete (do not break) all call backs for fid.
48 * DeleteAllCallBacks(host)
49 * Delete (do not break) all call backs for host.
51 * CleanupTimedOutCallBacks()
52 * Delete all timed out call back entries
53 * Must be called periodically by file server.
55 * BreakDelayedCallBacks(host)
56 * Break all delayed call backs for host.
57 * Returns 1: one or more failed, 0: success.
59 * PrintCallBackStats()
60 * Print statistics about call backs to stdout.
62 * DumpCallBacks() ---wishful thinking---
63 * Dump call back state to /tmp/callback.state.
64 * This is separately interpretable by the program pcb.
66 * Notes: In general, if a call back to a host doesn't get through,
67 * then HostDown, supplied elsewhere, is called. BreakDelayedCallBacks,
68 * however, does not call HostDown, but instead returns an indication of
69 * success if all delayed call backs were finally broken.
71 * BreakDelayedCallBacks MUST be called at the first sign of activity
72 * from the host after HostDown has been called (or a previous
73 * BreakDelayedCallBacks failed). The BreakDelayedCallBacks must be
74 * allowed to complete before any requests from that host are handled.
75 * If BreakDelayedCallBacks fails, then the host should remain
76 * down (and the request should be failed).
78 * CleanupCallBacks MUST be called periodically by the file server for
79 * this package to work correctly. Every 5 minutes is suggested.
82 #include <afsconfig.h>
83 #include <afs/param.h>
88 #include <stdlib.h> /* for malloc() */
89 #include <time.h> /* ANSI standard location for time stuff */
100 #ifdef HAVE_STRINGS_H
104 #include <afs/assert.h>
106 #include <afs/stds.h>
108 #include <afs/nfs.h> /* yuck. This is an abomination. */
111 #include <afscbint.h>
112 #include <afs/afsutil.h>
114 #include <afs/ihandle.h>
115 #include <afs/vnode.h>
116 #include <afs/volume.h>
117 #include "viced_prototypes.h"
120 #include <afs/ptclient.h> /* need definition of prlist for host.h */
123 extern afsUUID FS_HostUUID;
124 extern int hostCount;
125 int ShowProblems = 1;
127 /* Maximum number of call backs to break at once, single fid */
128 /* There is some debate as to just how large this value should be */
129 /* Ideally, it would be very very large, but I am afraid that the */
130 /* cache managers will all send in their responses simultaneously, */
131 /* thereby swamping the file server. As a result, something like */
132 /* 10 or 15 might be a better bet. */
133 #define MAX_CB_HOSTS 10
135 /* max time to break a callback, otherwise client is dead or net is hosed */
138 #define u_byte unsigned char
140 struct cbcounters cbstuff;
156 } *FE; /* Don't use FE[0] */
160 afs_uint32 cnext; /* Next call back entry */
161 afs_uint32 fhead; /* Head of this call back chain */
162 u_byte thead; /* Head of timeout chain */
163 u_byte status; /* Call back status; see definitions, below */
164 afs_uint32 hhead; /* Head of host table chain */
165 afs_uint32 tprev, tnext; /* Timeout chain */
166 afs_uint32 hprev, hnext; /* Chain from host table */
167 unsigned short spare; /* make it a multiple of 32 bits. */
168 } *CB; /* Don't use CB[0] */
170 /* status values for status field of CallBack structure */
171 #define CB_NORMAL 1 /* Normal call back */
172 #define CB_DELAYED 2 /* Delayed call back due to rpc problems.
173 The call back entry will be added back to the
174 host list at the END of the list, so that
175 searching backwards in the list will find all
176 the (consecutive)host. delayed call back entries */
177 #define CB_VOLUME 3 /* Callback for a volume */
178 #define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
180 /* call back indices to pointers, and vice-versa */
181 #define itocb(i) ((i)?CB+(i):0)
182 #define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
184 /* file entry indices to pointers, and vice-versa */
185 #define itofe(i) ((i)?FE+(i):0)
186 #define fetoi(fep) (!(fep)?0:(fep)-FE)
188 /* Timeouts: there are 128 possible timeout values in effect at any
189 * given time. Each timeout represents timeouts in an interval of 128
190 * seconds. So the maximum timeout for a call back is 128*128=16384
191 * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
192 * if space runs out or by the file server every 5 minutes. This 5
193 * minute slack should be allowed for--so a maximum time of 4 hours
196 * Timeouts must be chosen to correspond to an exact multiple
197 * of 128, because all times are truncated to a 128 multiple, and
198 * timed out if the current truncated time is <= to the truncated time
199 * corresponding to the timeout queue.
202 /* Unix time to Call Back time, and vice-versa. Call back time is
203 in units of 128 seconds, corresponding to time queues. */
204 #define CBtime(uxtime) ((uxtime)>>7)
205 #define UXtime(cbtime) ((cbtime)<<7)
207 /* Given a Unix time, compute the closest Unix time that corresponds to
208 a time queue, rounding up */
209 #define TimeCeiling(uxtime) (((uxtime)+127)&~127)
211 /* Time to live for call backs depends upon number of users of the file.
212 * TimeOuts is indexed by this number/8 (using TimeOut macro). Times
213 * in this table are for the workstation; server timeouts, add
216 static int TimeOuts[] = {
217 /* Note: don't make the first entry larger than 4 hours (see above) */
218 4*60*60, /* 0-7 users */
219 1*60*60, /* 8-15 users */
220 30*60, /* 16-23 users */
221 15*60, /* 24-31 users */
222 15*60, /* 32-39 users */
223 10*60, /* 40-47 users */
224 10*60, /* 48-55 users */
225 10*60, /* 56-63 users */
226 }; /* Anything more: MinTimeOut */
228 /* minimum time given for a call back */
229 static int MinTimeOut = (7*60);
231 #define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
232 #define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
234 /* time out at server is 3 minutes more than ws */
235 #define ServerBias (3*60)
237 /* Heads of CB queues; a timeout index is 1+index into this array */
238 static afs_uint32 timeout[128];
240 /* Convert cbtime to timeout queue index */
241 #define TIndex(cbtime) (((cbtime)&127)+1)
243 /* Convert cbtime to pointer to timeout queue head */
244 #define THead(cbtime) (&timeout[TIndex(cbtime)-1])
246 static afs_int32 tfirst; /* cbtime of oldest unexpired call back time queue */
248 /* Normalize index into timeout array so that two such indices will be
249 ordered correctly, so that they can be compared to see which times
250 sooner, or so that the difference in time out times between them
252 #define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
254 /* This converts a timeout index into the actual time it will expire */
255 #define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
258 /* Convert pointer to timeout queue head to index, and vice versa */
259 #define ttoi(t) ((t-timeout)+1)
260 #define itot(i) ((timeout)+(i-1))
262 /* 16 byte object get/free routines */
268 struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
270 afs_uint32 thead; /* head of timeout queue for youngest callback */
274 struct CallBack *CBfree = 0;
275 struct FileEntry *FEfree = 0;
277 /* Prototypes for static routines */
278 static struct FileEntry *FindFE (register AFSFid *fid);
279 static struct CallBack *iGetCB(register int *nused);
280 static int iFreeCB(register struct CallBack *cb, register int *nused);
281 static struct FileEntry *iGetFE(register int *nused);
282 static int iFreeFE(register struct FileEntry *fe, register int *nused);
283 static int TAdd(register struct CallBack *cb, register afs_uint32 *thead);
284 static int TDel(register struct CallBack *cb);
285 static int HAdd(register struct CallBack *cb, register struct host *host);
286 static int HDel(register struct CallBack *cb);
287 static int CDel(struct CallBack *cb, int deletefe);
288 static int CDelPtr(register struct FileEntry *fe, register afs_uint32 *cbp, int deletefe);
289 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host);
290 static int FDel(register struct FileEntry *fe);
291 static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead, int type, int locked);
292 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas, struct AFSCBFids *afidp, struct host *xhost);
293 static int MultiBreakVolumeCallBack_r(struct host *host, int isheld, struct VCBParams *parms, int deletefe);
294 static int MultiBreakVolumeCallBack(struct host *host, int isheld, struct VCBParams *parms);
295 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld, struct VCBParams *parms);
296 static int lih_r(register struct host *host, register int held, register struct host *hostp);
297 static int GetSomeSpace_r(struct host *hostp, int locked);
299 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
300 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
301 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
302 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
304 /* Other protos - move out sometime */
305 extern void ShutDown();
307 #define VHASH 512 /* Power of 2 */
308 static afs_uint32 HashTable[VHASH]; /* File entry hash table */
309 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
311 static struct FileEntry *FindFE (register AFSFid *fid)
315 register struct FileEntry *fe;
317 hash = VHash(fid->Volume, fid->Unique);
318 for (fei=HashTable[hash]; fei; fei = fe->fnext) {
320 if (fe->volid == fid->Volume && fe->unique == fid->Unique &&
321 fe->vnode == fid->Vnode)
327 #ifndef INTERPRET_DUMP
329 static struct CallBack *iGetCB(register int *nused)
331 register struct CallBack *ret;
333 if ((ret = CBfree)) {
334 CBfree = (struct CallBack *)(((struct object *)ret)->next);
340 static int iFreeCB(register struct CallBack *cb, register int *nused)
342 ((struct object *)cb)->next = (struct object *)CBfree;
348 static struct FileEntry *iGetFE(register int *nused)
350 register struct FileEntry *ret;
352 if ((ret = FEfree)) {
353 FEfree = (struct FileEntry *)(((struct object *)ret)->next);
359 static int iFreeFE(register struct FileEntry *fe, register int *nused)
361 ((struct object *)fe)->next = (struct object *)FEfree;
367 /* Add cb to end of specified timeout list */
368 static int TAdd(register struct CallBack *cb, register afs_uint32 *thead)
371 (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
373 register struct CallBack *thp = itocb(*thead);
375 cb->tprev = thp->tprev;
379 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
381 thp->tprev = cbtoi(cb);
384 cb->thead = ttoi(thead);
388 /* Delete call back entry from timeout list */
389 static int TDel(register struct CallBack *cb)
391 register afs_uint32 *thead = itot(cb->thead);
393 if (*thead == cbtoi(cb))
394 *thead = (*thead == cb->tnext? 0: cb->tnext);
395 if (itocb(cb->tprev))
396 itocb(cb->tprev)->tnext = cb->tnext;
397 if (itocb(cb->tnext))
398 itocb(cb->tnext)->tprev = cb->tprev;
402 /* Add cb to end of specified host list */
403 static int HAdd(register struct CallBack *cb, register struct host *host)
405 cb->hhead = h_htoi(host);
407 host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
410 register struct CallBack *hhp = itocb(host->cblist);
412 cb->hprev = hhp->hprev;
413 cb->hnext = host->cblist;
414 hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
419 /* Delete call back entry from host list */
420 static int HDel(register struct CallBack *cb)
422 register afs_uint32 *hhead = &h_itoh(cb->hhead)->cblist;
424 if (*hhead == cbtoi(cb))
425 *hhead = (*hhead == cb->hnext? 0: cb->hnext);
426 itocb(cb->hprev)->hnext = cb->hnext;
427 itocb(cb->hnext)->hprev = cb->hprev;
431 /* Delete call back entry from fid's chain of cb's */
432 /* N.B. This one also deletes the CB, and also possibly parent FE, so
433 * make sure that it is not on any other list before calling this
435 static int CDel(struct CallBack *cb, int deletefe)
438 struct FileEntry *fe = itofe(cb->fhead);
439 register afs_uint32 *cbp;
442 for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
443 cbp = &itocb(*cbp)->cnext, safety++) {
444 if (safety > cbstuff.nblks + 10) {
446 ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
451 CDelPtr(fe, cbp, deletefe);
455 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
456 * as well as file entry */
457 /* N.B. This one also deletes the CB, and also possibly parent FE, so
458 * make sure that it is not on any other list before calling this
460 int Ccdelpt=0, CcdelB=0;
462 static int CDelPtr(register struct FileEntry *fe,
463 register afs_uint32 *cbp, int deletefe)
465 register struct CallBack *cb;
475 if (deletefe && (--fe->ncbs == 0))
480 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host)
482 register afs_uint32 hostindex = h_htoi(host);
483 register struct CallBack *cb;
484 register afs_uint32 *cbp;
487 for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
488 if (safety > cbstuff.nblks) {
489 ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
494 if (cb->hhead == hostindex)
500 /* Delete file entry from hash table */
501 static int FDel(register struct FileEntry *fe)
503 register int fei = fetoi(fe);
504 register afs_uint32 *p = &HashTable[VHash(fe->volid, fe->unique)];
506 while (*p && *p != fei)
507 p = &itofe(*p)->fnext;
514 int InitCallBack(int nblks)
517 tfirst = CBtime(FT_ApproxTime());
518 /* N.B. The "-1", below, is because
519 FE[0] and CB[0] are not used--and not allocated */
520 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*nblks)))-1;
521 cbstuff.nFEs = nblks;
523 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
524 CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
525 cbstuff.nCBs = nblks;
527 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
528 cbstuff.nblks = nblks;
529 cbstuff.nbreakers = 0;
534 afs_int32 XCallBackBulk_r(struct host *ahost, struct AFSFid *fids,
537 struct AFSCallBack tcbs[AFSCBMAX];
545 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
546 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
553 for(i=0;i<nfids && i < AFSCBMAX;i++) {
554 tcbs[i].CallBackVersion = CALLBACK_VERSION;
555 tcbs[i].ExpirationTime = 0;
556 tcbs[i].CallBackType = CB_DROPPED;
558 tf.AFSCBFids_len = i;
559 tf.AFSCBFids_val = &(fids[j]);
563 tc.AFSCBs_val = tcbs;
566 code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
573 /* the locked flag tells us if the host entry has already been locked
574 * by our parent. I don't think anybody actually calls us with the
575 * host locked, but here's how to make that work: GetSomeSpace has to
576 * change so that it doesn't attempt to lock any hosts < "host". That
577 * means that it might be unable to free any objects, so it has to
578 * return an exit status. If it fails, then AddCallBack1 might fail,
579 * as well. If so, the host->ResetDone should probably be set to 0,
580 * and we probably don't want to return a callback promise to the
581 * cache manager, either. */
582 int AddCallBack1(struct host *host, AFSFid *fid, afs_uint32 *thead,
583 int type, int locked)
590 retVal = AddCallBack1_r(host, fid, thead, type, 1);
599 static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead,
600 int type, int locked)
602 struct FileEntry *fe;
603 struct CallBack *cb = 0, *lastcb = 0;
604 struct FileEntry *newfe = 0;
606 afs_uint32 *Thead = thead;
607 struct CallBack *newcb = 0;
612 /* allocate these guys first, since we can't call the allocator with
613 the host structure locked -- or we might deadlock. However, we have
614 to avoid races with FindFE... */
615 while (!(newcb = GetCB())) {
616 GetSomeSpace_r(host, locked);
618 while(!(newfe = GetFE())) { /* Get it now, so we don't have to call */
619 /* GetSomeSpace with the host locked, later. This might turn out to */
620 /* have been unneccessary, but that's actually kind of unlikely, since */
621 /* most files are not shared. */
622 GetSomeSpace_r(host, locked);
626 h_Lock_r(host); /* this can yield, so do it before we get any */
631 if (type == CB_NORMAL) {
632 time_out = TimeCeiling(FT_ApproxTime()+TimeOut(fe?fe->ncbs:0)+ServerBias);
633 Thead = THead(CBtime(time_out));
635 else if (type == CB_VOLUME) {
636 time_out = TimeCeiling((60*120+FT_ApproxTime())+ServerBias);
637 Thead = THead(CBtime(time_out));
639 else if (type == CB_BULK) {
640 /* bulk status can get so many callbacks all at once, and most of them
641 * are probably not for things that will be used for long.
643 time_out = TimeCeiling(FT_ApproxTime() + ServerBias
644 + TimeOut(22 + (fe?fe->ncbs:0)));
645 Thead = THead(CBtime(time_out));
651 register afs_uint32 hash;
656 fe->volid = fid->Volume;
657 fe->vnode = fid->Vnode;
658 fe->unique = fid->Unique;
660 hash = VHash(fid->Volume, fid->Unique);
661 fe->fnext = HashTable[hash];
662 HashTable[hash] = fetoi(fe);
664 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
665 lastcb = cb, cb = itocb(cb->cnext), safety++) {
666 if (safety > cbstuff.nblks) {
667 ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
671 if (cb->hhead == h_htoi(host))
674 if (cb) {/* Already have call back: move to new timeout list */
675 /* don't change delayed callbacks back to normal ones */
676 if (cb->status != CB_DELAYED)
678 /* Only move if new timeout is longer */
679 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
686 *(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
689 cb->fhead = fetoi(fe);
695 /* now free any still-unused callback or host entries */
696 if (newcb) FreeCB(newcb);
697 if (newfe) FreeFE(newfe);
699 if (!locked) /* freecb and freefe might(?) yield */
702 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK )
703 return time_out-ServerBias; /* Expires sooner at workstation */
708 /* Take an array full of hosts, all held. Break callbacks to them, and
709 * release the holds once you're done, except don't release xhost. xhost
710 * may be NULL. Currently only works for a single Fid in afidp array.
711 * If you want to make this work with multiple fids, you need to fix
712 * the error handling. One approach would be to force a reset if a
713 * multi-fid call fails, or you could add delayed callbacks for each
714 * fid. You probably also need to sort and remove duplicate hosts.
715 * When this is called from the BreakVolumeCallBacks path, it does NOT
716 * force a reset if the RPC fails, it just marks the host down and tries
717 * to create a delayed callback. */
718 /* N.B. be sure that code works when ncbas == 0 */
719 /* N.B. requires all the cba[*].hp pointers to be valid... */
720 /* This routine does not hold a lock on the host for the duration of
721 * the BreakCallBack RPC, which is a significant deviation from tradition.
722 * It _does_ get a lock on the host before setting VenusDown = 1,
723 * which is sufficient only if VenusDown = 0 only happens when the
724 * lock is held over the RPC and the subsequent VenusDown == 0
725 * wherever that is done. */
726 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
727 struct AFSCBFids *afidp, struct host *xhost)
730 struct rx_connection *conns[MAX_CB_HOSTS];
731 int opt_TO; /* secs, but internal adaptive parms are in ms */
732 static struct AFSCBs tc = {0,0};
734 assert(ncbas <= MAX_CB_HOSTS);
736 /* set up conns for multi-call */
737 for (i=0,j=0; i<ncbas; i++) {
738 struct host *thishost = cba[i].hp;
739 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
742 conns[j++] = thishost->callback_rxcon;
745 rx_SetConnDeadTime (thishost->callback_rxcon, 4);
746 rx_SetConnHardDeadTime (thishost->callback_rxcon, AFS_HARDDEADTIME);
750 if (j) { /* who knows what multi would do with 0 conns? */
754 multi_RXAFSCB_CallBack(afidp, &tc);
761 /* If there's an error, we have to hunt for the right host.
762 * The conns array _should_ correspond one-to-one to the cba
763 * array, except in some rare cases it might be missing one
764 * or more elements. So the optimistic case is almost
765 * always right. At worst, it's the starting point for the
767 for (hp=0,i=multi_i;i<j;i++) {
768 hp = cba[i].hp; /* optimistic, but usually right */
772 if (conns[multi_i] == hp->callback_rxcon) {
779 ViceLog(0, ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n",hp,cba));
783 ** try breaking callbacks on alternate interface addresses
785 if ( MultiBreakCallBackAlternateAddress(hp, afidp) )
789 ("BCB: Failed on file %u.%d.%d, host %s:%d is down\n",
790 afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
791 afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), hp->port));
796 hp->hostFlags |= VENUSDOWN;
798 * We always go into AddCallBack1_r with the host locked
800 AddCallBack1_r(hp,afidp->AFSCBFids_val,itot(idx), CB_DELAYED, 1);
811 for (i=0; i<ncbas; i++) {
814 if (hp && xhost != hp)
822 * Break all call backs for fid, except for the specified host (unless flag
823 * is true, in which case all get a callback message. Assumption: the specified
824 * host is h_Held, by the caller; the others aren't.
825 * Specified host may be bogus, that's ok. This used to check to see if the
826 * host was down in two places, once right after the host was h_held, and
827 * again after it was locked. That race condition is incredibly rare and
828 * relatively harmless even when it does occur, so we don't check for it now.
830 /* if flag is true, send a break callback msg to "host", too */
831 int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
833 struct FileEntry *fe;
834 struct CallBack *cb, *nextcb;
835 struct cbstruct cba[MAX_CB_HOSTS];
837 struct rx_connection *conns[MAX_CB_HOSTS];
842 ViceLog(7,("BCB: BreakCallBack(all but %s:%d, (%u,%d,%d))\n",
843 afs_inet_ntoa_r(xhost->host,hoststr), xhost->port, fid->Volume, fid->Vnode,
848 cbstuff.BreakCallBacks++;
853 hostindex = h_htoi(xhost);
854 cb = itocb(fe->firstcb);
855 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
856 /* the most common case is what follows the || */
859 tf.AFSCBFids_len = 1;
860 tf.AFSCBFids_val = fid;
863 for (ncbas=0; cb && ncbas<MAX_CB_HOSTS; cb=nextcb) {
864 nextcb = itocb(cb->cnext);
865 if ((cb->hhead != hostindex || flag)
866 && (cb->status == CB_BULK || cb->status == CB_NORMAL
867 || cb->status == CB_VOLUME) ) {
868 struct host *thishost = h_itoh(cb->hhead);
870 ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
872 else if (thishost->hostFlags & VENUSDOWN) {
873 ViceLog(7,("BCB: %s:%d is down; delaying break call back\n",
874 afs_inet_ntoa_r(thishost->host,hoststr), thishost->port));
875 cb->status = CB_DELAYED;
879 cba[ncbas].hp = thishost;
880 cba[ncbas].thead = cb->thead;
884 CDel(cb, 1); /* Usually first; so this delete
885 is reasonably inexpensive */
891 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
893 /* we need to to all these initializations again because MultiBreakCallBack may block */
898 cb = itocb(fe->firstcb);
899 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
900 /* the most common case is what follows the || */
911 /* Delete (do not break) single call back for fid */
912 int DeleteCallBack(struct host *host, AFSFid *fid)
914 register struct FileEntry *fe;
915 register afs_uint32 *pcb;
918 cbstuff.DeleteCallBacks++;
926 ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
927 fid->Volume, fid->Vnode, fid->Unique));
930 pcb = FindCBPtr(fe, host);
932 ViceLog(8,("DCB: No call back for host %s:%d, (%u, %d, %d)\n",
933 afs_inet_ntoa_r(host->host,hoststr), host->port, fid->Volume, fid->Vnode, fid->Unique));
947 * Delete (do not break) all call backs for fid. This call doesn't
948 * set all of the various host locks, but it shouldn't really matter
949 * since we're not adding callbacks, but deleting them. I'm not sure
950 * why it doesn't set the lock, however; perhaps it should.
952 int DeleteFileCallBacks(AFSFid *fid)
954 register struct FileEntry *fe;
955 register struct CallBack *cb;
956 register afs_uint32 cbi;
960 cbstuff.DeleteFiles++;
964 ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
965 fid->Volume, fid->Vnode, fid->Unique));
968 for (n=0,cbi = fe->firstcb; cbi; n++) {
980 /* Delete (do not break) all call backs for host. The host should be
982 int DeleteAllCallBacks_r(struct host *host, int deletefe)
984 register struct CallBack *cb;
985 register int cbi, first;
987 cbstuff.DeleteAllCallBacks++;
988 cbi = first = host->cblist;
990 ViceLog(8,("DV: no call backs\n"));
998 } while (cbi != first);
1004 * Break all delayed call backs for host. Returns 1 if all call backs
1005 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1006 * Must be called with VenusDown set for this host
1008 int BreakDelayedCallBacks(struct host *host)
1012 retVal = BreakDelayedCallBacks_r(host);
1017 int BreakDelayedCallBacks_r(struct host *host)
1019 struct AFSFid fids[AFSCBMAX];
1020 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1021 int cbi, first, nfids;
1022 struct CallBack *cb;
1023 struct interfaceAddr interf;
1027 cbstuff.nbreakers++;
1028 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1029 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1030 if ( host->interface ) {
1032 code = RXAFSCB_InitCallBackState3(host->callback_rxcon,
1037 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1040 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1044 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1045 afs_inet_ntoa_r(host->host,hoststr), host->port));
1047 host->hostFlags |= VENUSDOWN;
1050 ViceLog(25,("InitCallBackState success on %s\n",afs_inet_ntoa_r(host->host,hoststr)));
1051 /* reset was done successfully */
1052 host->hostFlags |= RESETDONE;
1053 host->hostFlags &= ~VENUSDOWN;
1056 else while (!(host->hostFlags & HOSTDELETED)) {
1058 host->hostFlags &= ~VENUSDOWN; /* presume up */
1059 cbi = first = host->cblist;
1063 first = host->cblist;
1066 if (cb->status == CB_DELAYED) {
1067 register struct FileEntry *fe = itofe(cb->fhead);
1068 thead[nfids] = cb->thead;
1069 fids[nfids].Volume = fe->volid;
1070 fids[nfids].Vnode = fe->vnode;
1071 fids[nfids].Unique = fe->unique;
1077 } while (cbi && cbi != first && nfids < AFSCBMAX);
1083 if (XCallBackBulk_r(host, fids, nfids)) {
1084 /* Failed, again: put them back, probably with old
1089 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1090 afs_inet_ntoa_r(host->host,hoststr), host->port));
1092 for (i = 0; i<nfids; i++) {
1095 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1096 afs_inet_ntoa_r(host->host,hoststr), host->port,
1097 fids[i].Volume, fids[i].Vnode, fids[i].Unique));
1100 AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1101 * but it turns out to cause too many tricky locking problems.
1102 * now, if break delayed fails, screw it. */
1104 host->hostFlags |= VENUSDOWN; /* Failed */
1105 ClearHostCallbacks_r(host, 1/* locked */);
1109 if (nfids < AFSCBMAX)
1113 cbstuff.nbreakers--;
1114 /* If we succeeded it's always ok to unset HFE_LATER */
1115 if (!host->hostFlags & VENUSDOWN)
1116 host->hostFlags &= ~HFE_LATER;
1117 return (host->hostFlags & VENUSDOWN);
1121 ** isheld is 0 if the host is held in h_Enumerate
1122 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1124 static int MultiBreakVolumeCallBack_r(struct host *host,
1125 int isheld, struct VCBParams *parms, int deletefe)
1130 return isheld; /* host is held only by h_Enumerate, do nothing */
1131 if ( host->hostFlags & HOSTDELETED )
1132 return 0; /* host is deleted, release hold */
1134 if (host->hostFlags & VENUSDOWN) {
1136 if (host->hostFlags & HOSTDELETED) {
1138 return 0; /* Release hold */
1140 ViceLog(8,("BVCB: volume call back for host %s:%d failed\n",
1141 afs_inet_ntoa_r(host->host,hoststr),host->port));
1143 ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
1144 afs_inet_ntoa_r(host->host,hoststr), host->port));
1146 DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state
1147 rather than attempting to
1148 selectively remember to
1149 delete the volume callbacks
1151 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1153 return 0; /* release hold */
1155 assert(parms->ncbas <= MAX_CB_HOSTS);
1157 /* Do not call MultiBreakCallBack on the current host structure
1158 ** because it would prematurely release the hold on the host
1160 if ( parms->ncbas == MAX_CB_HOSTS ) {
1161 struct AFSCBFids tf;
1163 tf.AFSCBFids_len = 1;
1164 tf.AFSCBFids_val = parms->fid;
1166 /* this releases all the hosts */
1167 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */);
1171 parms->cba[parms->ncbas].hp = host;
1172 parms->cba[(parms->ncbas)++].thead = parms->thead;
1173 return 1; /* DON'T release hold, because we still need it. */
1177 ** isheld is 0 if the host is held in h_Enumerate
1178 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1180 static int MultiBreakVolumeCallBack(struct host *host, int isheld,
1181 struct VCBParams *parms)
1185 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1191 ** isheld is 0 if the host is held in h_Enumerate
1192 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1194 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1195 struct VCBParams *parms)
1199 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1205 * Break all call backs on a single volume. Don't call this with any
1206 * hosts h_held. Note that this routine clears the callbacks before
1207 * actually breaking them, and that the vnode isn't locked during this
1208 * operation, so that people might see temporary callback loss while
1209 * this function is executing. It is just a temporary state, however,
1210 * since the callback will be broken later by this same function.
1212 * Now uses multi-RX for CallBack RPC. Note that the
1213 * multiBreakCallBacks routine does not force a reset if the RPC
1214 * fails, unlike the previous version of this routine, but does create
1215 * a delayed callback. Resets will be forced if the host is
1216 * determined to be down before the RPC is executed.
1218 int BreakVolumeCallBacks(afs_uint32 volume)
1223 struct CallBack *cb;
1224 struct FileEntry *fe;
1226 struct VCBParams henumParms;
1227 afs_uint32 tthead = 0; /* zero is illegal value */
1230 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1231 for (hash=0; hash<VHASH; hash++) {
1232 for (feip = &HashTable[hash]; (fe = itofe(*feip)); ) {
1233 if (fe->volid == volume) {
1234 register struct CallBack *cbnext;
1235 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1236 host = h_itoh(cb->hhead);
1238 cbnext = itocb(cb->cnext);
1239 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1245 /* leave hold for MultiBreakVolumeCallBack to clear */
1256 /* didn't find any callbacks, so return right away. */
1260 henumParms.ncbas = 0;
1261 henumParms.fid = &fid;
1262 henumParms.thead = tthead;
1264 h_Enumerate(MultiBreakVolumeCallBack, (char *) &henumParms);
1267 if (henumParms.ncbas) { /* do left-overs */
1268 struct AFSCBFids tf;
1269 tf.AFSCBFids_len = 1;
1270 tf.AFSCBFids_val = &fid;
1272 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1274 henumParms.ncbas = 0;
1281 #ifdef AFS_PTHREAD_ENV
1282 extern pthread_cond_t fsync_cond;
1284 extern char fsync_wait[];
1287 int BreakVolumeCallBacksLater(afs_uint32 volume)
1291 struct FileEntry *fe;
1292 struct CallBack *cb;
1296 ViceLog(25, ("Setting later on volume %d\n", volume));
1298 for (hash=0; hash<VHASH; hash++) {
1299 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1300 if (fe->volid == volume) {
1301 register struct CallBack *cbnext;
1302 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1303 host = h_itoh(cb->hhead);
1304 host->hostFlags |= HFE_LATER;
1305 cb->status = CB_DELAYED;
1306 cbnext = itocb(cb->cnext);
1309 fe->status |= FE_LATER;
1319 /* didn't find any callbacks, so return right away. */
1323 ViceLog(25, ("Fsync thread wakeup\n"));
1324 #ifdef AFS_PTHREAD_ENV
1325 assert(pthread_cond_broadcast(&fsync_cond) == 0);
1327 LWP_NoYieldSignal(&fsync_wait);
1332 int BreakLaterCallBacks(void)
1337 struct CallBack *cb;
1338 struct FileEntry *fe = NULL;
1339 struct FileEntry *myfe = NULL;
1340 struct FileEntry **fepp;
1342 struct VCBParams henumParms;
1343 unsigned short tthead = 0; /* zero is illegal value */
1346 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1350 for (hash=0; hash<VHASH; hash++) {
1351 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1352 if (fe && fe->status & FE_LATER) {
1353 ViceLog(125, ("Unchaining for %d:%d:%d\n", fe->vnode,
1354 fe->unique, fe->volid));
1356 /* Works since volid is deeper than the largest pointer */
1357 ((struct object *)fe)->next = (struct object *)myfe;
1370 /* loop over myfe and free/break */
1373 /* Clear for next pass */
1374 fid.Volume = 0, fid.Vnode = fid.Unique = 0;
1376 for (fepp = &myfe; fe = *fepp; ) {
1377 /* Pick up first volid we see and break callbacks for it */
1378 if (fid.Volume == 0 || fid.Volume == fe->volid) {
1379 register struct CallBack *cbnext;
1380 ViceLog(125, ("Caught volume %d for breaking\n", fe->volid));
1381 fid.Volume = fe->volid;
1382 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1383 host = h_itoh(cb->hhead);
1385 cbnext = itocb(cb->cnext);
1386 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1392 /* leave hold for MultiBreakVolumeCallBack to clear */
1395 (struct object *) *fepp = ((struct object *)fe)->next;
1398 (struct object **) fepp = &(((struct object *)fe)->next);
1403 ViceLog(125, ("Breaking volume %d\n", fid.Volume));
1404 henumParms.ncbas = 0;
1405 henumParms.fid = &fid;
1406 henumParms.thead = tthead;
1408 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *) &henumParms);
1411 if (henumParms.ncbas) { /* do left-overs */
1412 struct AFSCBFids tf;
1413 tf.AFSCBFids_len = 1;
1414 tf.AFSCBFids_val = &fid;
1416 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1417 henumParms.ncbas = 0;
1423 if (tthead) goto restart;
1430 * Delete all timed-out call back entries (to be called periodically by file
1433 int CleanupTimedOutCallBacks(void)
1436 CleanupTimedOutCallBacks_r();
1440 int CleanupTimedOutCallBacks_r(void)
1442 afs_uint32 now = CBtime(FT_ApproxTime());
1443 register afs_uint32 *thead;
1444 register struct CallBack *cb;
1445 register int ntimedout = 0;
1448 while (tfirst <= now) {
1450 cbi = *(thead = THead(tfirst));
1455 ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1456 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port,
1457 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1458 itofe(cb->fhead)->unique));
1462 if (ntimedout > cbstuff.nblks) {
1463 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1464 DumpCallBackState();
1467 } while (cbi != *thead);
1472 cbstuff.CBsTimedOut += ntimedout;
1473 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1474 return (ntimedout > 0);
1477 static struct host *lih_host;
1479 static int lih_r(register struct host *host, register int held,
1480 register struct host *hostp)
1483 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1484 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1490 /* This could be upgraded to get more space each time */
1491 /* first pass: find the oldest host which isn't held by anyone */
1492 /* second pass: find the oldest host who isn't "me" */
1493 /* always called with hostp unlocked */
1494 extern struct host *hostList;
1495 static int GetSomeSpace_r(struct host *hostp, int locked)
1497 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1500 cbstuff.GotSomeSpaces++;
1501 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1502 if (CleanupTimedOutCallBacks_r()) {
1508 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1512 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1519 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1521 * Next time try getting callbacks from any host even if
1522 * it's deleted (that's actually great since we can freely
1523 * remove its callbacks) or it's held since the only other
1524 * option is starvation for the file server (i.e. until the
1525 * callback timeout arrives).
1531 * No choice to clear this host's callback state
1533 /* third pass: we still haven't gotten any space, so we free what we had
1534 * previously passed over. */
1539 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1546 /* locked - set if caller has already locked the host */
1547 int ClearHostCallbacks(struct host *hp, int locked)
1551 retVal = ClearHostCallbacks_r(hp, locked);
1556 /* locked - set if caller has already locked the host */
1557 int ClearHostCallbacks_r(struct host *hp, int locked)
1559 struct interfaceAddr interf;
1564 ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
1565 if ( !(held = h_Held_r(hp)) )
1568 /** Try a non-blocking lock. If the lock is already held return
1569 * after releasing hold on hp
1572 if ( h_NBLock_r(hp) ) {
1578 if (hp->Console & 2) {
1580 * If the special console field is set it means that a thread
1581 * is waiting in AddCallBack1 after it set pointers to the
1582 * file entry and/or callback entry. Because of the bogus
1583 * usage of h_hold it won't prevent from another thread, this
1584 * one, to remove all the callbacks so just to be safe we keep
1585 * a reference. NOTE, on the last phase we'll free the calling
1586 * host's callbacks but that's ok...
1590 DeleteAllCallBacks_r(hp, 1);
1591 if (hp->hostFlags & VENUSDOWN) {
1592 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1594 /* host is up, try a call */
1595 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1596 if (hp->interface) {
1598 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1602 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1605 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1608 /* failed, mark host down and need reset */
1609 hp->hostFlags |= VENUSDOWN;
1610 hp->hostFlags &= ~RESETDONE;
1612 /* reset succeeded, we're done */
1613 hp->hostFlags |= RESETDONE;
1624 #endif /* INTERPRET_DUMP */
1627 int PrintCallBackStats(void)
1629 fprintf(stderr, "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1630 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1631 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1632 cbstuff.DeleteAllCallBacks);
1633 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1634 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1639 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1641 #ifndef INTERPRET_DUMP
1643 int DumpCallBackState(void)
1646 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1648 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1650 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1653 write(fd, &magic, sizeof(magic));
1654 write(fd, &now, sizeof(now));
1655 write(fd, &cbstuff, sizeof(cbstuff));
1656 write(fd, TimeOuts, sizeof(TimeOuts));
1657 write(fd, timeout, sizeof(timeout));
1658 write(fd, &tfirst, sizeof(tfirst));
1659 freelisthead = cbtoi((struct CallBack *) CBfree);
1660 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1661 freelisthead = fetoi((struct FileEntry *) FEfree);
1662 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1663 write(fd, HashTable, sizeof(HashTable));
1664 write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1665 write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1673 #ifdef INTERPRET_DUMP
1675 /* This is only compiled in for the callback analyzer program */
1676 /* Returns the time of the dump */
1677 time_t ReadDump(char *file)
1680 afs_uint32 magic, freelisthead;
1683 fd = open(file, O_RDONLY);
1685 fprintf(stderr, "Couldn't read dump file %s\n", file);
1688 read(fd, &magic, sizeof(magic));
1689 if (magic != MAGIC) {
1690 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1693 "run this program on a machine type with a different byte ordering.\n");
1696 read(fd, &now, sizeof(now));
1697 read(fd, &cbstuff, sizeof(cbstuff));
1698 read(fd, TimeOuts, sizeof(TimeOuts));
1699 read(fd, timeout, sizeof(timeout));
1700 read(fd, &tfirst, sizeof(tfirst));
1701 read(fd, &freelisthead, sizeof(freelisthead));
1702 CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1703 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1704 CBfree = (struct CallBack *) itocb(freelisthead);
1705 read(fd, &freelisthead, sizeof(freelisthead));
1706 FEfree = (struct FileEntry *) itofe(freelisthead);
1707 read(fd, HashTable, sizeof(HashTable));
1708 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1709 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1711 perror("Error reading dumpfile");
1717 #include "AFS_component_version_number.c"
1719 int main(int argc, char **argv)
1721 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1723 register struct FileEntry *fe;
1724 register struct CallBack *cb;
1727 memset(&fid, 0, sizeof(fid));
1729 while (argc && **argv == '-') {
1732 if (!strcmp(*argv, "-host")) {
1738 cbi = atoi(*++argv);
1740 else if (!strcmp(*argv, "-fid")) {
1746 fid.Volume = atoi(*++argv);
1747 fid.Vnode = atoi(*++argv);
1748 fid.Unique = atoi(*++argv);
1750 else if (!strcmp(*argv, "-time")) {
1751 fprintf(stderr, "-time not supported\n");
1754 else if (!strcmp(*argv, "-stats")) {
1757 else if (!strcmp(*argv, "-all")) {
1760 else if (!strcmp(*argv, "-raw")) {
1763 else if (!strcmp(*argv, "-volume")) {
1769 vol = atoi(*++argv);
1774 if (err || argc != 1) {
1776 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1777 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1780 now = ReadDump(*argv);
1781 if (stats || noptions == 0) {
1782 time_t uxtfirst = UXtime(tfirst);
1783 printf("The time of the dump was %u %s", now, ctime(&now));
1784 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1785 PrintCallBackStats();
1789 register afs_uint32 *feip;
1790 register struct CallBack *cb;
1791 register struct FileEntry *fe;
1793 for (hash=0; hash<VHASH; hash++) {
1794 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1795 if (!vol || (fe->volid == vol)) {
1796 register struct CallBack *cbnext;
1797 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1799 cbnext = itocb(cb->cnext);
1809 afs_uint32 cfirst = cbi;
1814 } while (cbi != cfirst);
1819 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1822 cb = itocb(fe->firstcb);
1825 cb = itocb(cb->cnext);
1829 struct FileEntry *fe;
1831 for (i=1; i < cbstuff.nblks; i++) {
1832 p = (afs_int32 *) &FE[i];
1833 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1838 int PrintCB(register struct CallBack *cb, afs_uint32 now)
1840 struct FileEntry *fe = itofe(cb->fhead);
1841 time_t expires = TIndexToTime(cb->thead);
1843 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1844 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1845 fe->status, expires - now, ctime(&expires));
1850 #if !defined(INTERPRET_DUMP)
1852 ** try breaking calbacks on afidp from host. Use multi_rx.
1853 ** return 0 on success, non-zero on failure
1855 int MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1859 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1864 int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *afidp)
1867 struct rx_connection** conns;
1868 struct rx_connection* connSuccess = 0;
1870 static struct rx_securityClass *sc = 0;
1871 static struct AFSCBs tc = {0,0};
1874 /* nothing more can be done */
1875 if ( !host->interface ) return 1; /* failure */
1877 assert(host->interface->numberOfInterfaces > 0 );
1879 /* the only address is the primary interface */
1880 if ( host->interface->numberOfInterfaces == 1 )
1881 return 1; /* failure */
1883 /* initialise a security object only once */
1885 sc = rxnull_NewClientSecurityObject();
1887 i = host->interface->numberOfInterfaces;
1888 addr = malloc(i * sizeof(afs_int32));
1889 conns = malloc(i * sizeof(struct rx_connection *));
1891 /* initialize alternate rx connections */
1892 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1894 /* this is the current primary address */
1895 if ( host->host == host->interface->addr[i] )
1898 addr[j] = host->interface->addr[i];
1899 conns[j] = rx_NewConnection (host->interface->addr[i],
1900 host->port, 1, sc, 0);
1901 rx_SetConnDeadTime(conns[j], 2);
1902 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1906 assert(j); /* at least one alternate address */
1907 ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
1908 afs_inet_ntoa_r(host->host,hoststr)));
1912 multi_RXAFSCB_CallBack(afidp, &tc);
1917 if ( host->callback_rxcon )
1918 rx_DestroyConnection(host->callback_rxcon);
1919 host->callback_rxcon = conns[multi_i];
1920 host->host = addr[multi_i];
1921 connSuccess = conns[multi_i];
1922 rx_SetConnDeadTime(host->callback_rxcon, 50);
1923 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1924 ViceLog(125,("multibreakcall success with addr %s\n",
1925 afs_inet_ntoa_r(addr[multi_i],hoststr)));
1932 /* Destroy all connections except the one on which we succeeded */
1933 for ( i=0; i < j; i++)
1934 if ( conns[i] != connSuccess )
1935 rx_DestroyConnection(conns[i] );
1940 if ( connSuccess ) return 0; /* success */
1941 else return 1; /* failure */
1946 ** try multiRX probes to host.
1947 ** return 0 on success, non-zero on failure
1949 int MultiProbeAlternateAddress_r(struct host *host)
1952 struct rx_connection** conns;
1953 struct rx_connection* connSuccess = 0;
1955 static struct rx_securityClass *sc = 0;
1958 /* nothing more can be done */
1959 if ( !host->interface ) return 1; /* failure */
1961 assert(host->interface->numberOfInterfaces > 0 );
1963 /* the only address is the primary interface */
1964 if ( host->interface->numberOfInterfaces == 1 )
1965 return 1; /* failure */
1967 /* initialise a security object only once */
1969 sc = rxnull_NewClientSecurityObject();
1971 i = host->interface->numberOfInterfaces;
1972 addr = malloc(i * sizeof(afs_int32));
1973 conns = malloc(i * sizeof(struct rx_connection *));
1975 /* initialize alternate rx connections */
1976 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1978 /* this is the current primary address */
1979 if ( host->host == host->interface->addr[i] )
1982 addr[j] = host->interface->addr[i];
1983 conns[j] = rx_NewConnection (host->interface->addr[i],
1984 host->port, 1, sc, 0);
1985 rx_SetConnDeadTime(conns[j], 2);
1986 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1990 assert(j); /* at least one alternate address */
1991 ViceLog(125,("Starting multiprobe on all addr for host %s\n",
1992 afs_inet_ntoa_r(host->host,hoststr)));
1996 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2001 if ( host->callback_rxcon )
2002 rx_DestroyConnection(host->callback_rxcon);
2003 host->callback_rxcon = conns[multi_i];
2004 host->host = addr[multi_i];
2005 connSuccess = conns[multi_i];
2006 rx_SetConnDeadTime(host->callback_rxcon, 50);
2007 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2008 ViceLog(125,("multiprobe success with addr %s\n",
2009 afs_inet_ntoa_r(addr[multi_i],hoststr)));
2016 /* Destroy all connections except the one on which we succeeded */
2017 for ( i=0; i < j; i++)
2018 if ( conns[i] != connSuccess )
2019 rx_DestroyConnection(conns[i] );
2024 if ( connSuccess ) return 0; /* success */
2025 else return 1; /* failure */
2028 #endif /* !defined(INTERPRET_DUMP) */