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 *tmpfe;
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 (fe = myfe; fe; ) {
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 */
1394 /* if we delete the head element, relink chain */
1396 (struct object *)myfe = ((struct object *)fe)->next;
1398 (struct object *)fe = ((struct object *)fe)->next;
1401 (struct object *)fe = ((struct object *)fe)->next;
1406 ViceLog(125, ("Breaking volume %d\n", fid.Volume));
1407 henumParms.ncbas = 0;
1408 henumParms.fid = &fid;
1409 henumParms.thead = tthead;
1411 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *) &henumParms);
1414 if (henumParms.ncbas) { /* do left-overs */
1415 struct AFSCBFids tf;
1416 tf.AFSCBFids_len = 1;
1417 tf.AFSCBFids_val = &fid;
1419 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1420 henumParms.ncbas = 0;
1426 if (tthead) goto restart;
1433 * Delete all timed-out call back entries (to be called periodically by file
1436 int CleanupTimedOutCallBacks(void)
1439 CleanupTimedOutCallBacks_r();
1443 int CleanupTimedOutCallBacks_r(void)
1445 afs_uint32 now = CBtime(FT_ApproxTime());
1446 register afs_uint32 *thead;
1447 register struct CallBack *cb;
1448 register int ntimedout = 0;
1451 while (tfirst <= now) {
1453 cbi = *(thead = THead(tfirst));
1458 ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1459 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port,
1460 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1461 itofe(cb->fhead)->unique));
1465 if (ntimedout > cbstuff.nblks) {
1466 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1467 DumpCallBackState();
1470 } while (cbi != *thead);
1475 cbstuff.CBsTimedOut += ntimedout;
1476 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1477 return (ntimedout > 0);
1480 static struct host *lih_host;
1482 static int lih_r(register struct host *host, register int held,
1483 register struct host *hostp)
1486 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1487 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1493 /* This could be upgraded to get more space each time */
1494 /* first pass: find the oldest host which isn't held by anyone */
1495 /* second pass: find the oldest host who isn't "me" */
1496 /* always called with hostp unlocked */
1497 extern struct host *hostList;
1498 static int GetSomeSpace_r(struct host *hostp, int locked)
1500 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1503 cbstuff.GotSomeSpaces++;
1504 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1505 if (CleanupTimedOutCallBacks_r()) {
1511 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1515 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1522 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1524 * Next time try getting callbacks from any host even if
1525 * it's deleted (that's actually great since we can freely
1526 * remove its callbacks) or it's held since the only other
1527 * option is starvation for the file server (i.e. until the
1528 * callback timeout arrives).
1534 * No choice to clear this host's callback state
1536 /* third pass: we still haven't gotten any space, so we free what we had
1537 * previously passed over. */
1542 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1549 /* locked - set if caller has already locked the host */
1550 int ClearHostCallbacks(struct host *hp, int locked)
1554 retVal = ClearHostCallbacks_r(hp, locked);
1559 /* locked - set if caller has already locked the host */
1560 int ClearHostCallbacks_r(struct host *hp, int locked)
1562 struct interfaceAddr interf;
1567 ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
1568 if ( !(held = h_Held_r(hp)) )
1571 /** Try a non-blocking lock. If the lock is already held return
1572 * after releasing hold on hp
1575 if ( h_NBLock_r(hp) ) {
1581 if (hp->Console & 2) {
1583 * If the special console field is set it means that a thread
1584 * is waiting in AddCallBack1 after it set pointers to the
1585 * file entry and/or callback entry. Because of the bogus
1586 * usage of h_hold it won't prevent from another thread, this
1587 * one, to remove all the callbacks so just to be safe we keep
1588 * a reference. NOTE, on the last phase we'll free the calling
1589 * host's callbacks but that's ok...
1593 DeleteAllCallBacks_r(hp, 1);
1594 if (hp->hostFlags & VENUSDOWN) {
1595 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1597 /* host is up, try a call */
1598 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1599 if (hp->interface) {
1601 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1605 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1608 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1611 /* failed, mark host down and need reset */
1612 hp->hostFlags |= VENUSDOWN;
1613 hp->hostFlags &= ~RESETDONE;
1615 /* reset succeeded, we're done */
1616 hp->hostFlags |= RESETDONE;
1627 #endif /* INTERPRET_DUMP */
1630 int PrintCallBackStats(void)
1632 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",
1633 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1634 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1635 cbstuff.DeleteAllCallBacks);
1636 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1637 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1642 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1644 #ifndef INTERPRET_DUMP
1646 int DumpCallBackState(void)
1649 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1651 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1653 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1656 write(fd, &magic, sizeof(magic));
1657 write(fd, &now, sizeof(now));
1658 write(fd, &cbstuff, sizeof(cbstuff));
1659 write(fd, TimeOuts, sizeof(TimeOuts));
1660 write(fd, timeout, sizeof(timeout));
1661 write(fd, &tfirst, sizeof(tfirst));
1662 freelisthead = cbtoi((struct CallBack *) CBfree);
1663 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1664 freelisthead = fetoi((struct FileEntry *) FEfree);
1665 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1666 write(fd, HashTable, sizeof(HashTable));
1667 write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1668 write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1676 #ifdef INTERPRET_DUMP
1678 /* This is only compiled in for the callback analyzer program */
1679 /* Returns the time of the dump */
1680 time_t ReadDump(char *file)
1683 afs_uint32 magic, freelisthead;
1686 fd = open(file, O_RDONLY);
1688 fprintf(stderr, "Couldn't read dump file %s\n", file);
1691 read(fd, &magic, sizeof(magic));
1692 if (magic != MAGIC) {
1693 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1696 "run this program on a machine type with a different byte ordering.\n");
1699 read(fd, &now, sizeof(now));
1700 read(fd, &cbstuff, sizeof(cbstuff));
1701 read(fd, TimeOuts, sizeof(TimeOuts));
1702 read(fd, timeout, sizeof(timeout));
1703 read(fd, &tfirst, sizeof(tfirst));
1704 read(fd, &freelisthead, sizeof(freelisthead));
1705 CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1706 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1707 CBfree = (struct CallBack *) itocb(freelisthead);
1708 read(fd, &freelisthead, sizeof(freelisthead));
1709 FEfree = (struct FileEntry *) itofe(freelisthead);
1710 read(fd, HashTable, sizeof(HashTable));
1711 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1712 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1714 perror("Error reading dumpfile");
1720 #include "AFS_component_version_number.c"
1722 int main(int argc, char **argv)
1724 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1726 register struct FileEntry *fe;
1727 register struct CallBack *cb;
1730 memset(&fid, 0, sizeof(fid));
1732 while (argc && **argv == '-') {
1735 if (!strcmp(*argv, "-host")) {
1741 cbi = atoi(*++argv);
1743 else if (!strcmp(*argv, "-fid")) {
1749 fid.Volume = atoi(*++argv);
1750 fid.Vnode = atoi(*++argv);
1751 fid.Unique = atoi(*++argv);
1753 else if (!strcmp(*argv, "-time")) {
1754 fprintf(stderr, "-time not supported\n");
1757 else if (!strcmp(*argv, "-stats")) {
1760 else if (!strcmp(*argv, "-all")) {
1763 else if (!strcmp(*argv, "-raw")) {
1766 else if (!strcmp(*argv, "-volume")) {
1772 vol = atoi(*++argv);
1777 if (err || argc != 1) {
1779 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1780 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1783 now = ReadDump(*argv);
1784 if (stats || noptions == 0) {
1785 time_t uxtfirst = UXtime(tfirst);
1786 printf("The time of the dump was %u %s", now, ctime(&now));
1787 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1788 PrintCallBackStats();
1792 register afs_uint32 *feip;
1793 register struct CallBack *cb;
1794 register struct FileEntry *fe;
1796 for (hash=0; hash<VHASH; hash++) {
1797 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1798 if (!vol || (fe->volid == vol)) {
1799 register struct CallBack *cbnext;
1800 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1802 cbnext = itocb(cb->cnext);
1812 afs_uint32 cfirst = cbi;
1817 } while (cbi != cfirst);
1822 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1825 cb = itocb(fe->firstcb);
1828 cb = itocb(cb->cnext);
1832 struct FileEntry *fe;
1834 for (i=1; i < cbstuff.nblks; i++) {
1835 p = (afs_int32 *) &FE[i];
1836 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1841 int PrintCB(register struct CallBack *cb, afs_uint32 now)
1843 struct FileEntry *fe = itofe(cb->fhead);
1844 time_t expires = TIndexToTime(cb->thead);
1846 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1847 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1848 fe->status, expires - now, ctime(&expires));
1853 #if !defined(INTERPRET_DUMP)
1855 ** try breaking calbacks on afidp from host. Use multi_rx.
1856 ** return 0 on success, non-zero on failure
1858 int MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1862 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1867 int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *afidp)
1870 struct rx_connection** conns;
1871 struct rx_connection* connSuccess = 0;
1873 static struct rx_securityClass *sc = 0;
1874 static struct AFSCBs tc = {0,0};
1877 /* nothing more can be done */
1878 if ( !host->interface ) return 1; /* failure */
1880 assert(host->interface->numberOfInterfaces > 0 );
1882 /* the only address is the primary interface */
1883 if ( host->interface->numberOfInterfaces == 1 )
1884 return 1; /* failure */
1886 /* initialise a security object only once */
1888 sc = rxnull_NewClientSecurityObject();
1890 i = host->interface->numberOfInterfaces;
1891 addr = malloc(i * sizeof(afs_int32));
1892 conns = malloc(i * sizeof(struct rx_connection *));
1894 /* initialize alternate rx connections */
1895 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1897 /* this is the current primary address */
1898 if ( host->host == host->interface->addr[i] )
1901 addr[j] = host->interface->addr[i];
1902 conns[j] = rx_NewConnection (host->interface->addr[i],
1903 host->port, 1, sc, 0);
1904 rx_SetConnDeadTime(conns[j], 2);
1905 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1909 assert(j); /* at least one alternate address */
1910 ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
1911 afs_inet_ntoa_r(host->host,hoststr)));
1915 multi_RXAFSCB_CallBack(afidp, &tc);
1920 if ( host->callback_rxcon )
1921 rx_DestroyConnection(host->callback_rxcon);
1922 host->callback_rxcon = conns[multi_i];
1923 host->host = addr[multi_i];
1924 connSuccess = conns[multi_i];
1925 rx_SetConnDeadTime(host->callback_rxcon, 50);
1926 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1927 ViceLog(125,("multibreakcall success with addr %s\n",
1928 afs_inet_ntoa_r(addr[multi_i],hoststr)));
1935 /* Destroy all connections except the one on which we succeeded */
1936 for ( i=0; i < j; i++)
1937 if ( conns[i] != connSuccess )
1938 rx_DestroyConnection(conns[i] );
1943 if ( connSuccess ) return 0; /* success */
1944 else return 1; /* failure */
1949 ** try multiRX probes to host.
1950 ** return 0 on success, non-zero on failure
1952 int MultiProbeAlternateAddress_r(struct host *host)
1955 struct rx_connection** conns;
1956 struct rx_connection* connSuccess = 0;
1958 static struct rx_securityClass *sc = 0;
1961 /* nothing more can be done */
1962 if ( !host->interface ) return 1; /* failure */
1964 assert(host->interface->numberOfInterfaces > 0 );
1966 /* the only address is the primary interface */
1967 if ( host->interface->numberOfInterfaces == 1 )
1968 return 1; /* failure */
1970 /* initialise a security object only once */
1972 sc = rxnull_NewClientSecurityObject();
1974 i = host->interface->numberOfInterfaces;
1975 addr = malloc(i * sizeof(afs_int32));
1976 conns = malloc(i * sizeof(struct rx_connection *));
1978 /* initialize alternate rx connections */
1979 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1981 /* this is the current primary address */
1982 if ( host->host == host->interface->addr[i] )
1985 addr[j] = host->interface->addr[i];
1986 conns[j] = rx_NewConnection (host->interface->addr[i],
1987 host->port, 1, sc, 0);
1988 rx_SetConnDeadTime(conns[j], 2);
1989 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1993 assert(j); /* at least one alternate address */
1994 ViceLog(125,("Starting multiprobe on all addr for host %s\n",
1995 afs_inet_ntoa_r(host->host,hoststr)));
1999 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2004 if ( host->callback_rxcon )
2005 rx_DestroyConnection(host->callback_rxcon);
2006 host->callback_rxcon = conns[multi_i];
2007 host->host = addr[multi_i];
2008 connSuccess = conns[multi_i];
2009 rx_SetConnDeadTime(host->callback_rxcon, 50);
2010 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2011 ViceLog(125,("multiprobe success with addr %s\n",
2012 afs_inet_ntoa_r(addr[multi_i],hoststr)));
2019 /* Destroy all connections except the one on which we succeeded */
2020 for ( i=0; i < j; i++)
2021 if ( conns[i] != connSuccess )
2022 rx_DestroyConnection(conns[i] );
2027 if ( connSuccess ) return 0; /* success */
2028 else return 1; /* failure */
2031 #endif /* !defined(INTERPRET_DUMP) */