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;
522 ViceLog(0, ("Failed malloc in InitCallBack\n"));
525 cbstuff.nFEs = nblks;
527 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
528 CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
530 ViceLog(0, ("Failed malloc in InitCallBack\n"));
533 cbstuff.nCBs = nblks;
535 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
536 cbstuff.nblks = nblks;
537 cbstuff.nbreakers = 0;
542 afs_int32 XCallBackBulk_r(struct host *ahost, struct AFSFid *fids,
545 struct AFSCallBack tcbs[AFSCBMAX];
553 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
554 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
561 for(i=0;i<nfids && i < AFSCBMAX;i++) {
562 tcbs[i].CallBackVersion = CALLBACK_VERSION;
563 tcbs[i].ExpirationTime = 0;
564 tcbs[i].CallBackType = CB_DROPPED;
566 tf.AFSCBFids_len = i;
567 tf.AFSCBFids_val = &(fids[j]);
571 tc.AFSCBs_val = tcbs;
574 code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
581 /* the locked flag tells us if the host entry has already been locked
582 * by our parent. I don't think anybody actually calls us with the
583 * host locked, but here's how to make that work: GetSomeSpace has to
584 * change so that it doesn't attempt to lock any hosts < "host". That
585 * means that it might be unable to free any objects, so it has to
586 * return an exit status. If it fails, then AddCallBack1 might fail,
587 * as well. If so, the host->ResetDone should probably be set to 0,
588 * and we probably don't want to return a callback promise to the
589 * cache manager, either. */
590 int AddCallBack1(struct host *host, AFSFid *fid, afs_uint32 *thead,
591 int type, int locked)
598 retVal = AddCallBack1_r(host, fid, thead, type, 1);
607 static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead,
608 int type, int locked)
610 struct FileEntry *fe;
611 struct CallBack *cb = 0, *lastcb = 0;
612 struct FileEntry *newfe = 0;
614 afs_uint32 *Thead = thead;
615 struct CallBack *newcb = 0;
620 /* allocate these guys first, since we can't call the allocator with
621 the host structure locked -- or we might deadlock. However, we have
622 to avoid races with FindFE... */
623 while (!(newcb = GetCB())) {
624 GetSomeSpace_r(host, locked);
626 while(!(newfe = GetFE())) { /* Get it now, so we don't have to call */
627 /* GetSomeSpace with the host locked, later. This might turn out to */
628 /* have been unneccessary, but that's actually kind of unlikely, since */
629 /* most files are not shared. */
630 GetSomeSpace_r(host, locked);
634 h_Lock_r(host); /* this can yield, so do it before we get any */
639 if (type == CB_NORMAL) {
640 time_out = TimeCeiling(FT_ApproxTime()+TimeOut(fe?fe->ncbs:0)+ServerBias);
641 Thead = THead(CBtime(time_out));
643 else if (type == CB_VOLUME) {
644 time_out = TimeCeiling((60*120+FT_ApproxTime())+ServerBias);
645 Thead = THead(CBtime(time_out));
647 else if (type == CB_BULK) {
648 /* bulk status can get so many callbacks all at once, and most of them
649 * are probably not for things that will be used for long.
651 time_out = TimeCeiling(FT_ApproxTime() + ServerBias
652 + TimeOut(22 + (fe?fe->ncbs:0)));
653 Thead = THead(CBtime(time_out));
659 register afs_uint32 hash;
664 fe->volid = fid->Volume;
665 fe->vnode = fid->Vnode;
666 fe->unique = fid->Unique;
668 hash = VHash(fid->Volume, fid->Unique);
669 fe->fnext = HashTable[hash];
670 HashTable[hash] = fetoi(fe);
672 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
673 lastcb = cb, cb = itocb(cb->cnext), safety++) {
674 if (safety > cbstuff.nblks) {
675 ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
679 if (cb->hhead == h_htoi(host))
682 if (cb) {/* Already have call back: move to new timeout list */
683 /* don't change delayed callbacks back to normal ones */
684 if (cb->status != CB_DELAYED)
686 /* Only move if new timeout is longer */
687 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
694 *(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
697 cb->fhead = fetoi(fe);
703 /* now free any still-unused callback or host entries */
704 if (newcb) FreeCB(newcb);
705 if (newfe) FreeFE(newfe);
707 if (!locked) /* freecb and freefe might(?) yield */
710 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK )
711 return time_out-ServerBias; /* Expires sooner at workstation */
716 /* Take an array full of hosts, all held. Break callbacks to them, and
717 * release the holds once you're done, except don't release xhost. xhost
718 * may be NULL. Currently only works for a single Fid in afidp array.
719 * If you want to make this work with multiple fids, you need to fix
720 * the error handling. One approach would be to force a reset if a
721 * multi-fid call fails, or you could add delayed callbacks for each
722 * fid. You probably also need to sort and remove duplicate hosts.
723 * When this is called from the BreakVolumeCallBacks path, it does NOT
724 * force a reset if the RPC fails, it just marks the host down and tries
725 * to create a delayed callback. */
726 /* N.B. be sure that code works when ncbas == 0 */
727 /* N.B. requires all the cba[*].hp pointers to be valid... */
728 /* This routine does not hold a lock on the host for the duration of
729 * the BreakCallBack RPC, which is a significant deviation from tradition.
730 * It _does_ get a lock on the host before setting VenusDown = 1,
731 * which is sufficient only if VenusDown = 0 only happens when the
732 * lock is held over the RPC and the subsequent VenusDown == 0
733 * wherever that is done. */
734 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
735 struct AFSCBFids *afidp, struct host *xhost)
738 struct rx_connection *conns[MAX_CB_HOSTS];
739 int opt_TO; /* secs, but internal adaptive parms are in ms */
740 static struct AFSCBs tc = {0,0};
742 assert(ncbas <= MAX_CB_HOSTS);
744 /* set up conns for multi-call */
745 for (i=0,j=0; i<ncbas; i++) {
746 struct host *thishost = cba[i].hp;
747 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
750 conns[j++] = thishost->callback_rxcon;
753 rx_SetConnDeadTime (thishost->callback_rxcon, 4);
754 rx_SetConnHardDeadTime (thishost->callback_rxcon, AFS_HARDDEADTIME);
758 if (j) { /* who knows what multi would do with 0 conns? */
762 multi_RXAFSCB_CallBack(afidp, &tc);
769 /* If there's an error, we have to hunt for the right host.
770 * The conns array _should_ correspond one-to-one to the cba
771 * array, except in some rare cases it might be missing one
772 * or more elements. So the optimistic case is almost
773 * always right. At worst, it's the starting point for the
775 for (hp=0,i=multi_i;i<j;i++) {
776 hp = cba[i].hp; /* optimistic, but usually right */
780 if (conns[multi_i] == hp->callback_rxcon) {
787 ViceLog(0, ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n",hp,cba));
791 ** try breaking callbacks on alternate interface addresses
793 if ( MultiBreakCallBackAlternateAddress(hp, afidp) )
797 ("BCB: Failed on file %u.%d.%d, host %s:%d is down\n",
798 afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
799 afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), ntohs(hp->port)));
804 hp->hostFlags |= VENUSDOWN;
806 * We always go into AddCallBack1_r with the host locked
808 AddCallBack1_r(hp,afidp->AFSCBFids_val,itot(idx), CB_DELAYED, 1);
819 for (i=0; i<ncbas; i++) {
822 if (hp && xhost != hp)
830 * Break all call backs for fid, except for the specified host (unless flag
831 * is true, in which case all get a callback message. Assumption: the specified
832 * host is h_Held, by the caller; the others aren't.
833 * Specified host may be bogus, that's ok. This used to check to see if the
834 * host was down in two places, once right after the host was h_held, and
835 * again after it was locked. That race condition is incredibly rare and
836 * relatively harmless even when it does occur, so we don't check for it now.
838 /* if flag is true, send a break callback msg to "host", too */
839 int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
841 struct FileEntry *fe;
842 struct CallBack *cb, *nextcb;
843 struct cbstruct cba[MAX_CB_HOSTS];
845 struct rx_connection *conns[MAX_CB_HOSTS];
850 ViceLog(7,("BCB: BreakCallBack(all but %s:%d, (%u,%d,%d))\n",
851 afs_inet_ntoa_r(xhost->host,hoststr), ntohs(xhost->port), fid->Volume, fid->Vnode,
856 cbstuff.BreakCallBacks++;
861 hostindex = h_htoi(xhost);
862 cb = itocb(fe->firstcb);
863 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
864 /* the most common case is what follows the || */
867 tf.AFSCBFids_len = 1;
868 tf.AFSCBFids_val = fid;
871 for (ncbas=0; cb && ncbas<MAX_CB_HOSTS; cb=nextcb) {
872 nextcb = itocb(cb->cnext);
873 if ((cb->hhead != hostindex || flag)
874 && (cb->status == CB_BULK || cb->status == CB_NORMAL
875 || cb->status == CB_VOLUME) ) {
876 struct host *thishost = h_itoh(cb->hhead);
878 ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
880 else if (thishost->hostFlags & VENUSDOWN) {
881 ViceLog(7,("BCB: %s:%d is down; delaying break call back\n",
882 afs_inet_ntoa_r(thishost->host,hoststr), ntohs(thishost->port)));
883 cb->status = CB_DELAYED;
887 cba[ncbas].hp = thishost;
888 cba[ncbas].thead = cb->thead;
892 CDel(cb, 1); /* Usually first; so this delete
893 is reasonably inexpensive */
899 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
901 /* we need to to all these initializations again because MultiBreakCallBack may block */
906 cb = itocb(fe->firstcb);
907 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
908 /* the most common case is what follows the || */
919 /* Delete (do not break) single call back for fid */
920 int DeleteCallBack(struct host *host, AFSFid *fid)
922 register struct FileEntry *fe;
923 register afs_uint32 *pcb;
926 cbstuff.DeleteCallBacks++;
934 ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
935 fid->Volume, fid->Vnode, fid->Unique));
938 pcb = FindCBPtr(fe, host);
940 ViceLog(8,("DCB: No call back for host %s:%d, (%u, %d, %d)\n",
941 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port), fid->Volume, fid->Vnode, fid->Unique));
955 * Delete (do not break) all call backs for fid. This call doesn't
956 * set all of the various host locks, but it shouldn't really matter
957 * since we're not adding callbacks, but deleting them. I'm not sure
958 * why it doesn't set the lock, however; perhaps it should.
960 int DeleteFileCallBacks(AFSFid *fid)
962 register struct FileEntry *fe;
963 register struct CallBack *cb;
964 register afs_uint32 cbi;
968 cbstuff.DeleteFiles++;
972 ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
973 fid->Volume, fid->Vnode, fid->Unique));
976 for (n=0,cbi = fe->firstcb; cbi; n++) {
988 /* Delete (do not break) all call backs for host. The host should be
990 int DeleteAllCallBacks_r(struct host *host, int deletefe)
992 register struct CallBack *cb;
993 register int cbi, first;
995 cbstuff.DeleteAllCallBacks++;
996 cbi = first = host->cblist;
998 ViceLog(8,("DV: no call backs\n"));
1006 } while (cbi != first);
1012 * Break all delayed call backs for host. Returns 1 if all call backs
1013 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1014 * Must be called with VenusDown set for this host
1016 int BreakDelayedCallBacks(struct host *host)
1020 retVal = BreakDelayedCallBacks_r(host);
1025 int BreakDelayedCallBacks_r(struct host *host)
1027 struct AFSFid fids[AFSCBMAX];
1028 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1029 int cbi, first, nfids;
1030 struct CallBack *cb;
1031 struct interfaceAddr interf;
1035 cbstuff.nbreakers++;
1036 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1037 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1038 if ( host->interface ) {
1040 code = RXAFSCB_InitCallBackState3(host->callback_rxcon,
1045 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1048 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1052 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1053 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
1055 host->hostFlags |= VENUSDOWN;
1058 ViceLog(25,("InitCallBackState success on %s\n",afs_inet_ntoa_r(host->host,hoststr)));
1059 /* reset was done successfully */
1060 host->hostFlags |= RESETDONE;
1061 host->hostFlags &= ~VENUSDOWN;
1064 else while (!(host->hostFlags & HOSTDELETED)) {
1066 host->hostFlags &= ~VENUSDOWN; /* presume up */
1067 cbi = first = host->cblist;
1071 first = host->cblist;
1074 if (cb->status == CB_DELAYED) {
1075 register struct FileEntry *fe = itofe(cb->fhead);
1076 thead[nfids] = cb->thead;
1077 fids[nfids].Volume = fe->volid;
1078 fids[nfids].Vnode = fe->vnode;
1079 fids[nfids].Unique = fe->unique;
1085 } while (cbi && cbi != first && nfids < AFSCBMAX);
1091 if (XCallBackBulk_r(host, fids, nfids)) {
1092 /* Failed, again: put them back, probably with old
1097 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1098 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
1100 for (i = 0; i<nfids; i++) {
1103 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1104 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port),
1105 fids[i].Volume, fids[i].Vnode, fids[i].Unique));
1108 AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1109 * but it turns out to cause too many tricky locking problems.
1110 * now, if break delayed fails, screw it. */
1112 host->hostFlags |= VENUSDOWN; /* Failed */
1113 ClearHostCallbacks_r(host, 1/* locked */);
1117 if (nfids < AFSCBMAX)
1121 cbstuff.nbreakers--;
1122 /* If we succeeded it's always ok to unset HFE_LATER */
1123 if (!host->hostFlags & VENUSDOWN)
1124 host->hostFlags &= ~HFE_LATER;
1125 return (host->hostFlags & VENUSDOWN);
1129 ** isheld is 0 if the host is held in h_Enumerate
1130 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1132 static int MultiBreakVolumeCallBack_r(struct host *host,
1133 int isheld, struct VCBParams *parms, int deletefe)
1138 return isheld; /* host is held only by h_Enumerate, do nothing */
1139 if ( host->hostFlags & HOSTDELETED )
1140 return 0; /* host is deleted, release hold */
1142 if (host->hostFlags & VENUSDOWN) {
1144 if (host->hostFlags & HOSTDELETED) {
1146 return 0; /* Release hold */
1148 ViceLog(8,("BVCB: volume call back for host %s:%d failed\n",
1149 afs_inet_ntoa_r(host->host,hoststr),ntohs(host->port)));
1151 ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
1152 afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
1154 DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state
1155 rather than attempting to
1156 selectively remember to
1157 delete the volume callbacks
1159 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1161 return 0; /* release hold */
1163 assert(parms->ncbas <= MAX_CB_HOSTS);
1165 /* Do not call MultiBreakCallBack on the current host structure
1166 ** because it would prematurely release the hold on the host
1168 if ( parms->ncbas == MAX_CB_HOSTS ) {
1169 struct AFSCBFids tf;
1171 tf.AFSCBFids_len = 1;
1172 tf.AFSCBFids_val = parms->fid;
1174 /* this releases all the hosts */
1175 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */);
1179 parms->cba[parms->ncbas].hp = host;
1180 parms->cba[(parms->ncbas)++].thead = parms->thead;
1181 return 1; /* DON'T release hold, because we still need it. */
1185 ** isheld is 0 if the host is held in h_Enumerate
1186 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1188 static int MultiBreakVolumeCallBack(struct host *host, int isheld,
1189 struct VCBParams *parms)
1193 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1199 ** isheld is 0 if the host is held in h_Enumerate
1200 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1202 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1203 struct VCBParams *parms)
1207 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1213 * Break all call backs on a single volume. Don't call this with any
1214 * hosts h_held. Note that this routine clears the callbacks before
1215 * actually breaking them, and that the vnode isn't locked during this
1216 * operation, so that people might see temporary callback loss while
1217 * this function is executing. It is just a temporary state, however,
1218 * since the callback will be broken later by this same function.
1220 * Now uses multi-RX for CallBack RPC. Note that the
1221 * multiBreakCallBacks routine does not force a reset if the RPC
1222 * fails, unlike the previous version of this routine, but does create
1223 * a delayed callback. Resets will be forced if the host is
1224 * determined to be down before the RPC is executed.
1226 int BreakVolumeCallBacks(afs_uint32 volume)
1231 struct CallBack *cb;
1232 struct FileEntry *fe;
1234 struct VCBParams henumParms;
1235 afs_uint32 tthead = 0; /* zero is illegal value */
1238 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1239 for (hash=0; hash<VHASH; hash++) {
1240 for (feip = &HashTable[hash]; (fe = itofe(*feip)); ) {
1241 if (fe->volid == volume) {
1242 register struct CallBack *cbnext;
1243 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1244 host = h_itoh(cb->hhead);
1246 cbnext = itocb(cb->cnext);
1247 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1253 /* leave hold for MultiBreakVolumeCallBack to clear */
1264 /* didn't find any callbacks, so return right away. */
1268 henumParms.ncbas = 0;
1269 henumParms.fid = &fid;
1270 henumParms.thead = tthead;
1272 h_Enumerate(MultiBreakVolumeCallBack, (char *) &henumParms);
1275 if (henumParms.ncbas) { /* do left-overs */
1276 struct AFSCBFids tf;
1277 tf.AFSCBFids_len = 1;
1278 tf.AFSCBFids_val = &fid;
1280 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1282 henumParms.ncbas = 0;
1289 #ifdef AFS_PTHREAD_ENV
1290 extern pthread_cond_t fsync_cond;
1292 extern char fsync_wait[];
1295 int BreakVolumeCallBacksLater(afs_uint32 volume)
1299 struct FileEntry *fe;
1300 struct CallBack *cb;
1304 ViceLog(25, ("Setting later on volume %d\n", volume));
1306 for (hash=0; hash<VHASH; hash++) {
1307 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1308 if (fe->volid == volume) {
1309 register struct CallBack *cbnext;
1310 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1311 host = h_itoh(cb->hhead);
1312 host->hostFlags |= HFE_LATER;
1313 cb->status = CB_DELAYED;
1314 cbnext = itocb(cb->cnext);
1317 fe->status |= FE_LATER;
1327 /* didn't find any callbacks, so return right away. */
1331 ViceLog(25, ("Fsync thread wakeup\n"));
1332 #ifdef AFS_PTHREAD_ENV
1333 assert(pthread_cond_broadcast(&fsync_cond) == 0);
1335 LWP_NoYieldSignal(&fsync_wait);
1340 int BreakLaterCallBacks(void)
1345 struct CallBack *cb;
1346 struct FileEntry *fe = NULL;
1347 struct FileEntry *myfe = NULL;
1349 struct VCBParams henumParms;
1350 unsigned short tthead = 0; /* zero is illegal value */
1353 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1356 /* Pick the first volume we see to clean up */
1357 fid.Volume = fid.Vnode = fid.Unique = 0;
1359 for (hash=0; hash<VHASH; hash++) {
1360 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1361 if (fe && (fe->status & FE_LATER) &&
1362 (fid.Volume == 0 || fid.Volume == fe->volid)) {
1363 ViceLog(125, ("Unchaining for %d:%d:%d\n", fe->vnode,
1364 fe->unique, fe->volid));
1365 fid.Volume = fe->volid;
1367 /* Works since volid is deeper than the largest pointer */
1368 ((struct object *)fe)->next = (struct object *)myfe;
1380 /* loop over FEs from myfe and free/break */
1383 for (fe = myfe; fe; ) {
1384 register struct CallBack *cbnext;
1385 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1386 host = h_itoh(cb->hhead);
1388 cbnext = itocb(cb->cnext);
1389 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1394 CDel(cb, 0); /* Don't let CDel clean up the fe */
1395 /* leave hold for MultiBreakVolumeCallBack to clear */
1398 (struct object *)fe = ((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 /* Arrange to be called again */
1428 * Delete all timed-out call back entries (to be called periodically by file
1431 int CleanupTimedOutCallBacks(void)
1434 CleanupTimedOutCallBacks_r();
1438 int CleanupTimedOutCallBacks_r(void)
1440 afs_uint32 now = CBtime(FT_ApproxTime());
1441 register afs_uint32 *thead;
1442 register struct CallBack *cb;
1443 register int ntimedout = 0;
1446 while (tfirst <= now) {
1448 cbi = *(thead = THead(tfirst));
1453 ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1454 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port,
1455 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1456 itofe(cb->fhead)->unique));
1460 if (ntimedout > cbstuff.nblks) {
1461 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1462 DumpCallBackState();
1465 } while (cbi != *thead);
1470 cbstuff.CBsTimedOut += ntimedout;
1471 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1472 return (ntimedout > 0);
1475 static struct host *lih_host;
1477 static int lih_r(register struct host *host, register int held,
1478 register struct host *hostp)
1481 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1482 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1488 /* This could be upgraded to get more space each time */
1489 /* first pass: find the oldest host which isn't held by anyone */
1490 /* second pass: find the oldest host who isn't "me" */
1491 /* always called with hostp unlocked */
1492 extern struct host *hostList;
1493 static int GetSomeSpace_r(struct host *hostp, int locked)
1495 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1498 cbstuff.GotSomeSpaces++;
1499 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1500 if (CleanupTimedOutCallBacks_r()) {
1506 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1510 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1517 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1519 * Next time try getting callbacks from any host even if
1520 * it's deleted (that's actually great since we can freely
1521 * remove its callbacks) or it's held since the only other
1522 * option is starvation for the file server (i.e. until the
1523 * callback timeout arrives).
1529 * No choice to clear this host's callback state
1531 /* third pass: we still haven't gotten any space, so we free what we had
1532 * previously passed over. */
1537 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1544 /* locked - set if caller has already locked the host */
1545 static int ClearHostCallbacks_r(struct host *hp, int locked)
1547 struct interfaceAddr interf;
1552 ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
1553 if ( !(held = h_Held_r(hp)) )
1556 /** Try a non-blocking lock. If the lock is already held return
1557 * after releasing hold on hp
1560 if ( h_NBLock_r(hp) ) {
1566 if (hp->Console & 2) {
1568 * If the special console field is set it means that a thread
1569 * is waiting in AddCallBack1 after it set pointers to the
1570 * file entry and/or callback entry. Because of the bogus
1571 * usage of h_hold it won't prevent from another thread, this
1572 * one, to remove all the callbacks so just to be safe we keep
1573 * a reference. NOTE, on the last phase we'll free the calling
1574 * host's callbacks but that's ok...
1578 DeleteAllCallBacks_r(hp, 1);
1579 if (hp->hostFlags & VENUSDOWN) {
1580 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1582 /* host is up, try a call */
1583 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1584 if (hp->interface) {
1586 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1590 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1593 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1596 /* failed, mark host down and need reset */
1597 hp->hostFlags |= VENUSDOWN;
1598 hp->hostFlags &= ~RESETDONE;
1600 /* reset succeeded, we're done */
1601 hp->hostFlags |= RESETDONE;
1612 #endif /* INTERPRET_DUMP */
1615 int PrintCallBackStats(void)
1617 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",
1618 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1619 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1620 cbstuff.DeleteAllCallBacks);
1621 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1622 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1627 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1629 #ifndef INTERPRET_DUMP
1631 int DumpCallBackState(void)
1634 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1636 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1638 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1641 write(fd, &magic, sizeof(magic));
1642 write(fd, &now, sizeof(now));
1643 write(fd, &cbstuff, sizeof(cbstuff));
1644 write(fd, TimeOuts, sizeof(TimeOuts));
1645 write(fd, timeout, sizeof(timeout));
1646 write(fd, &tfirst, sizeof(tfirst));
1647 freelisthead = cbtoi((struct CallBack *) CBfree);
1648 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1649 freelisthead = fetoi((struct FileEntry *) FEfree);
1650 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1651 write(fd, HashTable, sizeof(HashTable));
1652 write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1653 write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1661 #ifdef INTERPRET_DUMP
1663 /* This is only compiled in for the callback analyzer program */
1664 /* Returns the time of the dump */
1665 time_t ReadDump(char *file)
1668 afs_uint32 magic, freelisthead;
1671 fd = open(file, O_RDONLY);
1673 fprintf(stderr, "Couldn't read dump file %s\n", file);
1676 read(fd, &magic, sizeof(magic));
1677 if (magic != MAGIC) {
1678 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1681 "run this program on a machine type with a different byte ordering.\n");
1684 read(fd, &now, sizeof(now));
1685 read(fd, &cbstuff, sizeof(cbstuff));
1686 read(fd, TimeOuts, sizeof(TimeOuts));
1687 read(fd, timeout, sizeof(timeout));
1688 read(fd, &tfirst, sizeof(tfirst));
1689 read(fd, &freelisthead, sizeof(freelisthead));
1690 CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1691 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1692 CBfree = (struct CallBack *) itocb(freelisthead);
1693 read(fd, &freelisthead, sizeof(freelisthead));
1694 FEfree = (struct FileEntry *) itofe(freelisthead);
1695 read(fd, HashTable, sizeof(HashTable));
1696 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1697 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1699 perror("Error reading dumpfile");
1705 #include "AFS_component_version_number.c"
1707 int main(int argc, char **argv)
1709 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1711 register struct FileEntry *fe;
1712 register struct CallBack *cb;
1715 memset(&fid, 0, sizeof(fid));
1717 while (argc && **argv == '-') {
1720 if (!strcmp(*argv, "-host")) {
1726 cbi = atoi(*++argv);
1728 else if (!strcmp(*argv, "-fid")) {
1734 fid.Volume = atoi(*++argv);
1735 fid.Vnode = atoi(*++argv);
1736 fid.Unique = atoi(*++argv);
1738 else if (!strcmp(*argv, "-time")) {
1739 fprintf(stderr, "-time not supported\n");
1742 else if (!strcmp(*argv, "-stats")) {
1745 else if (!strcmp(*argv, "-all")) {
1748 else if (!strcmp(*argv, "-raw")) {
1751 else if (!strcmp(*argv, "-volume")) {
1757 vol = atoi(*++argv);
1762 if (err || argc != 1) {
1764 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1765 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1768 now = ReadDump(*argv);
1769 if (stats || noptions == 0) {
1770 time_t uxtfirst = UXtime(tfirst);
1771 printf("The time of the dump was %u %s", now, ctime(&now));
1772 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1773 PrintCallBackStats();
1777 register afs_uint32 *feip;
1778 register struct CallBack *cb;
1779 register struct FileEntry *fe;
1781 for (hash=0; hash<VHASH; hash++) {
1782 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1783 if (!vol || (fe->volid == vol)) {
1784 register struct CallBack *cbnext;
1785 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1787 cbnext = itocb(cb->cnext);
1797 afs_uint32 cfirst = cbi;
1802 } while (cbi != cfirst);
1807 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1810 cb = itocb(fe->firstcb);
1813 cb = itocb(cb->cnext);
1817 struct FileEntry *fe;
1819 for (i=1; i < cbstuff.nblks; i++) {
1820 p = (afs_int32 *) &FE[i];
1821 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1826 int PrintCB(register struct CallBack *cb, afs_uint32 now)
1828 struct FileEntry *fe = itofe(cb->fhead);
1829 time_t expires = TIndexToTime(cb->thead);
1831 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1832 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1833 fe->status, expires - now, ctime(&expires));
1838 #if !defined(INTERPRET_DUMP)
1840 ** try breaking calbacks on afidp from host. Use multi_rx.
1841 ** return 0 on success, non-zero on failure
1843 int MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1847 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1852 int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *afidp)
1855 struct rx_connection** conns;
1856 struct rx_connection* connSuccess = 0;
1858 static struct rx_securityClass *sc = 0;
1859 static struct AFSCBs tc = {0,0};
1862 /* nothing more can be done */
1863 if ( !host->interface ) return 1; /* failure */
1865 assert(host->interface->numberOfInterfaces > 0 );
1867 /* the only address is the primary interface */
1868 if ( host->interface->numberOfInterfaces == 1 )
1869 return 1; /* failure */
1871 /* initialise a security object only once */
1873 sc = rxnull_NewClientSecurityObject();
1875 i = host->interface->numberOfInterfaces;
1876 addr = malloc(i * sizeof(afs_int32));
1877 conns = malloc(i * sizeof(struct rx_connection *));
1878 if (!addr || !conns) {
1879 ViceLog(0, ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
1883 /* initialize alternate rx connections */
1884 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1886 /* this is the current primary address */
1887 if ( host->host == host->interface->addr[i] )
1890 addr[j] = host->interface->addr[i];
1891 conns[j] = rx_NewConnection (host->interface->addr[i],
1892 host->port, 1, sc, 0);
1893 rx_SetConnDeadTime(conns[j], 2);
1894 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1898 assert(j); /* at least one alternate address */
1899 ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
1900 afs_inet_ntoa_r(host->host,hoststr)));
1904 multi_RXAFSCB_CallBack(afidp, &tc);
1909 if ( host->callback_rxcon )
1910 rx_DestroyConnection(host->callback_rxcon);
1911 host->callback_rxcon = conns[multi_i];
1912 host->host = addr[multi_i];
1913 connSuccess = conns[multi_i];
1914 rx_SetConnDeadTime(host->callback_rxcon, 50);
1915 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1916 ViceLog(125,("multibreakcall success with addr %s\n",
1917 afs_inet_ntoa_r(addr[multi_i],hoststr)));
1924 /* Destroy all connections except the one on which we succeeded */
1925 for ( i=0; i < j; i++)
1926 if ( conns[i] != connSuccess )
1927 rx_DestroyConnection(conns[i] );
1932 if ( connSuccess ) return 0; /* success */
1933 else return 1; /* failure */
1938 ** try multiRX probes to host.
1939 ** return 0 on success, non-zero on failure
1941 int MultiProbeAlternateAddress_r(struct host *host)
1944 struct rx_connection** conns;
1945 struct rx_connection* connSuccess = 0;
1947 static struct rx_securityClass *sc = 0;
1950 /* nothing more can be done */
1951 if ( !host->interface ) return 1; /* failure */
1953 assert(host->interface->numberOfInterfaces > 0 );
1955 /* the only address is the primary interface */
1956 if ( host->interface->numberOfInterfaces == 1 )
1957 return 1; /* failure */
1959 /* initialise a security object only once */
1961 sc = rxnull_NewClientSecurityObject();
1963 i = host->interface->numberOfInterfaces;
1964 addr = malloc(i * sizeof(afs_int32));
1965 conns = malloc(i * sizeof(struct rx_connection *));
1966 if (!addr || !conns) {
1967 ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
1971 /* initialize alternate rx connections */
1972 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1974 /* this is the current primary address */
1975 if ( host->host == host->interface->addr[i] )
1978 addr[j] = host->interface->addr[i];
1979 conns[j] = rx_NewConnection (host->interface->addr[i],
1980 host->port, 1, sc, 0);
1981 rx_SetConnDeadTime(conns[j], 2);
1982 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1986 assert(j); /* at least one alternate address */
1987 ViceLog(125,("Starting multiprobe on all addr for host %s\n",
1988 afs_inet_ntoa_r(host->host,hoststr)));
1992 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
1997 if ( host->callback_rxcon )
1998 rx_DestroyConnection(host->callback_rxcon);
1999 host->callback_rxcon = conns[multi_i];
2000 host->host = addr[multi_i];
2001 connSuccess = conns[multi_i];
2002 rx_SetConnDeadTime(host->callback_rxcon, 50);
2003 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2004 ViceLog(125,("multiprobe success with addr %s\n",
2005 afs_inet_ntoa_r(addr[multi_i],hoststr)));
2012 /* Destroy all connections except the one on which we succeeded */
2013 for ( i=0; i < j; i++)
2014 if ( conns[i] != connSuccess )
2015 rx_DestroyConnection(conns[i] );
2020 if ( connSuccess ) return 0; /* success */
2021 else return 1; /* failure */
2024 #endif /* !defined(INTERPRET_DUMP) */