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), 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), 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), 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), 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), 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), 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), 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),host->port));
1151 ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
1152 afs_inet_ntoa_r(host->host,hoststr), 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;
1348 struct FileEntry **fepp;
1350 struct VCBParams henumParms;
1351 unsigned short tthead = 0; /* zero is illegal value */
1354 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1358 for (hash=0; hash<VHASH; hash++) {
1359 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1360 if (fe && fe->status & FE_LATER) {
1361 ViceLog(125, ("Unchaining for %d:%d:%d\n", fe->vnode,
1362 fe->unique, fe->volid));
1364 /* Works since volid is deeper than the largest pointer */
1365 ((struct object *)fe)->next = (struct object *)myfe;
1378 /* loop over myfe and free/break */
1381 /* Clear for next pass */
1382 fid.Volume = 0, fid.Vnode = fid.Unique = 0;
1384 for (fepp = &myfe; fe = *fepp; ) {
1385 /* Pick up first volid we see and break callbacks for it */
1386 if (fid.Volume == 0 || fid.Volume == fe->volid) {
1387 register struct CallBack *cbnext;
1388 ViceLog(125, ("Caught volume %d for breaking\n", fe->volid));
1389 fid.Volume = fe->volid;
1390 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1391 host = h_itoh(cb->hhead);
1393 cbnext = itocb(cb->cnext);
1394 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1399 CDel(cb, 0); /* Don't let CDel clean up the fe */
1400 /* leave hold for MultiBreakVolumeCallBack to clear */
1403 (struct object *) *fepp = ((struct object *)fe)->next;
1406 (struct object **) fepp = &(((struct object *)fe)->next);
1411 ViceLog(125, ("Breaking volume %d\n", fid.Volume));
1412 henumParms.ncbas = 0;
1413 henumParms.fid = &fid;
1414 henumParms.thead = tthead;
1416 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *) &henumParms);
1419 if (henumParms.ncbas) { /* do left-overs */
1420 struct AFSCBFids tf;
1421 tf.AFSCBFids_len = 1;
1422 tf.AFSCBFids_val = &fid;
1424 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1425 henumParms.ncbas = 0;
1431 if (tthead) goto restart;
1438 * Delete all timed-out call back entries (to be called periodically by file
1441 int CleanupTimedOutCallBacks(void)
1444 CleanupTimedOutCallBacks_r();
1448 int CleanupTimedOutCallBacks_r(void)
1450 afs_uint32 now = CBtime(FT_ApproxTime());
1451 register afs_uint32 *thead;
1452 register struct CallBack *cb;
1453 register int ntimedout = 0;
1456 while (tfirst <= now) {
1458 cbi = *(thead = THead(tfirst));
1463 ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1464 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port,
1465 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1466 itofe(cb->fhead)->unique));
1470 if (ntimedout > cbstuff.nblks) {
1471 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1472 DumpCallBackState();
1475 } while (cbi != *thead);
1480 cbstuff.CBsTimedOut += ntimedout;
1481 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1482 return (ntimedout > 0);
1485 static struct host *lih_host;
1487 static int lih_r(register struct host *host, register int held,
1488 register struct host *hostp)
1491 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1492 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1498 /* This could be upgraded to get more space each time */
1499 /* first pass: find the oldest host which isn't held by anyone */
1500 /* second pass: find the oldest host who isn't "me" */
1501 /* always called with hostp unlocked */
1502 extern struct host *hostList;
1503 static int GetSomeSpace_r(struct host *hostp, int locked)
1505 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1508 cbstuff.GotSomeSpaces++;
1509 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1510 if (CleanupTimedOutCallBacks_r()) {
1516 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1520 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1527 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1529 * Next time try getting callbacks from any host even if
1530 * it's deleted (that's actually great since we can freely
1531 * remove its callbacks) or it's held since the only other
1532 * option is starvation for the file server (i.e. until the
1533 * callback timeout arrives).
1539 * No choice to clear this host's callback state
1541 /* third pass: we still haven't gotten any space, so we free what we had
1542 * previously passed over. */
1547 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1554 /* locked - set if caller has already locked the host */
1555 int ClearHostCallbacks(struct host *hp, int locked)
1559 retVal = ClearHostCallbacks_r(hp, locked);
1564 /* locked - set if caller has already locked the host */
1565 int ClearHostCallbacks_r(struct host *hp, int locked)
1567 struct interfaceAddr interf;
1572 ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
1573 if ( !(held = h_Held_r(hp)) )
1576 /** Try a non-blocking lock. If the lock is already held return
1577 * after releasing hold on hp
1580 if ( h_NBLock_r(hp) ) {
1586 if (hp->Console & 2) {
1588 * If the special console field is set it means that a thread
1589 * is waiting in AddCallBack1 after it set pointers to the
1590 * file entry and/or callback entry. Because of the bogus
1591 * usage of h_hold it won't prevent from another thread, this
1592 * one, to remove all the callbacks so just to be safe we keep
1593 * a reference. NOTE, on the last phase we'll free the calling
1594 * host's callbacks but that's ok...
1598 DeleteAllCallBacks_r(hp, 1);
1599 if (hp->hostFlags & VENUSDOWN) {
1600 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1602 /* host is up, try a call */
1603 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1604 if (hp->interface) {
1606 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1610 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1613 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1616 /* failed, mark host down and need reset */
1617 hp->hostFlags |= VENUSDOWN;
1618 hp->hostFlags &= ~RESETDONE;
1620 /* reset succeeded, we're done */
1621 hp->hostFlags |= RESETDONE;
1632 #endif /* INTERPRET_DUMP */
1635 int PrintCallBackStats(void)
1637 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",
1638 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1639 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1640 cbstuff.DeleteAllCallBacks);
1641 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1642 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1647 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1649 #ifndef INTERPRET_DUMP
1651 int DumpCallBackState(void)
1654 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1656 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1658 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1661 write(fd, &magic, sizeof(magic));
1662 write(fd, &now, sizeof(now));
1663 write(fd, &cbstuff, sizeof(cbstuff));
1664 write(fd, TimeOuts, sizeof(TimeOuts));
1665 write(fd, timeout, sizeof(timeout));
1666 write(fd, &tfirst, sizeof(tfirst));
1667 freelisthead = cbtoi((struct CallBack *) CBfree);
1668 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1669 freelisthead = fetoi((struct FileEntry *) FEfree);
1670 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1671 write(fd, HashTable, sizeof(HashTable));
1672 write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1673 write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1681 #ifdef INTERPRET_DUMP
1683 /* This is only compiled in for the callback analyzer program */
1684 /* Returns the time of the dump */
1685 time_t ReadDump(char *file)
1688 afs_uint32 magic, freelisthead;
1691 fd = open(file, O_RDONLY);
1693 fprintf(stderr, "Couldn't read dump file %s\n", file);
1696 read(fd, &magic, sizeof(magic));
1697 if (magic != MAGIC) {
1698 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1701 "run this program on a machine type with a different byte ordering.\n");
1704 read(fd, &now, sizeof(now));
1705 read(fd, &cbstuff, sizeof(cbstuff));
1706 read(fd, TimeOuts, sizeof(TimeOuts));
1707 read(fd, timeout, sizeof(timeout));
1708 read(fd, &tfirst, sizeof(tfirst));
1709 read(fd, &freelisthead, sizeof(freelisthead));
1710 CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1711 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1712 CBfree = (struct CallBack *) itocb(freelisthead);
1713 read(fd, &freelisthead, sizeof(freelisthead));
1714 FEfree = (struct FileEntry *) itofe(freelisthead);
1715 read(fd, HashTable, sizeof(HashTable));
1716 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1717 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1719 perror("Error reading dumpfile");
1725 #include "AFS_component_version_number.c"
1727 int main(int argc, char **argv)
1729 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1731 register struct FileEntry *fe;
1732 register struct CallBack *cb;
1735 memset(&fid, 0, sizeof(fid));
1737 while (argc && **argv == '-') {
1740 if (!strcmp(*argv, "-host")) {
1746 cbi = atoi(*++argv);
1748 else if (!strcmp(*argv, "-fid")) {
1754 fid.Volume = atoi(*++argv);
1755 fid.Vnode = atoi(*++argv);
1756 fid.Unique = atoi(*++argv);
1758 else if (!strcmp(*argv, "-time")) {
1759 fprintf(stderr, "-time not supported\n");
1762 else if (!strcmp(*argv, "-stats")) {
1765 else if (!strcmp(*argv, "-all")) {
1768 else if (!strcmp(*argv, "-raw")) {
1771 else if (!strcmp(*argv, "-volume")) {
1777 vol = atoi(*++argv);
1782 if (err || argc != 1) {
1784 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1785 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1788 now = ReadDump(*argv);
1789 if (stats || noptions == 0) {
1790 time_t uxtfirst = UXtime(tfirst);
1791 printf("The time of the dump was %u %s", now, ctime(&now));
1792 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1793 PrintCallBackStats();
1797 register afs_uint32 *feip;
1798 register struct CallBack *cb;
1799 register struct FileEntry *fe;
1801 for (hash=0; hash<VHASH; hash++) {
1802 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1803 if (!vol || (fe->volid == vol)) {
1804 register struct CallBack *cbnext;
1805 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1807 cbnext = itocb(cb->cnext);
1817 afs_uint32 cfirst = cbi;
1822 } while (cbi != cfirst);
1827 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1830 cb = itocb(fe->firstcb);
1833 cb = itocb(cb->cnext);
1837 struct FileEntry *fe;
1839 for (i=1; i < cbstuff.nblks; i++) {
1840 p = (afs_int32 *) &FE[i];
1841 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1846 int PrintCB(register struct CallBack *cb, afs_uint32 now)
1848 struct FileEntry *fe = itofe(cb->fhead);
1849 time_t expires = TIndexToTime(cb->thead);
1851 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1852 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1853 fe->status, expires - now, ctime(&expires));
1858 #if !defined(INTERPRET_DUMP)
1860 ** try breaking calbacks on afidp from host. Use multi_rx.
1861 ** return 0 on success, non-zero on failure
1863 int MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1867 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1872 int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *afidp)
1875 struct rx_connection** conns;
1876 struct rx_connection* connSuccess = 0;
1878 static struct rx_securityClass *sc = 0;
1879 static struct AFSCBs tc = {0,0};
1882 /* nothing more can be done */
1883 if ( !host->interface ) return 1; /* failure */
1885 assert(host->interface->numberOfInterfaces > 0 );
1887 /* the only address is the primary interface */
1888 if ( host->interface->numberOfInterfaces == 1 )
1889 return 1; /* failure */
1891 /* initialise a security object only once */
1893 sc = rxnull_NewClientSecurityObject();
1895 i = host->interface->numberOfInterfaces;
1896 addr = malloc(i * sizeof(afs_int32));
1897 conns = malloc(i * sizeof(struct rx_connection *));
1898 if (!addr || !conns) {
1899 ViceLog(0, ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
1903 /* initialize alternate rx connections */
1904 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1906 /* this is the current primary address */
1907 if ( host->host == host->interface->addr[i] )
1910 addr[j] = host->interface->addr[i];
1911 conns[j] = rx_NewConnection (host->interface->addr[i],
1912 host->port, 1, sc, 0);
1913 rx_SetConnDeadTime(conns[j], 2);
1914 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1918 assert(j); /* at least one alternate address */
1919 ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
1920 afs_inet_ntoa_r(host->host,hoststr)));
1924 multi_RXAFSCB_CallBack(afidp, &tc);
1929 if ( host->callback_rxcon )
1930 rx_DestroyConnection(host->callback_rxcon);
1931 host->callback_rxcon = conns[multi_i];
1932 host->host = addr[multi_i];
1933 connSuccess = conns[multi_i];
1934 rx_SetConnDeadTime(host->callback_rxcon, 50);
1935 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1936 ViceLog(125,("multibreakcall success with addr %s\n",
1937 afs_inet_ntoa_r(addr[multi_i],hoststr)));
1944 /* Destroy all connections except the one on which we succeeded */
1945 for ( i=0; i < j; i++)
1946 if ( conns[i] != connSuccess )
1947 rx_DestroyConnection(conns[i] );
1952 if ( connSuccess ) return 0; /* success */
1953 else return 1; /* failure */
1958 ** try multiRX probes to host.
1959 ** return 0 on success, non-zero on failure
1961 int MultiProbeAlternateAddress_r(struct host *host)
1964 struct rx_connection** conns;
1965 struct rx_connection* connSuccess = 0;
1967 static struct rx_securityClass *sc = 0;
1970 /* nothing more can be done */
1971 if ( !host->interface ) return 1; /* failure */
1973 assert(host->interface->numberOfInterfaces > 0 );
1975 /* the only address is the primary interface */
1976 if ( host->interface->numberOfInterfaces == 1 )
1977 return 1; /* failure */
1979 /* initialise a security object only once */
1981 sc = rxnull_NewClientSecurityObject();
1983 i = host->interface->numberOfInterfaces;
1984 addr = malloc(i * sizeof(afs_int32));
1985 conns = malloc(i * sizeof(struct rx_connection *));
1986 if (!addr || !conns) {
1987 ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
1991 /* initialize alternate rx connections */
1992 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1994 /* this is the current primary address */
1995 if ( host->host == host->interface->addr[i] )
1998 addr[j] = host->interface->addr[i];
1999 conns[j] = rx_NewConnection (host->interface->addr[i],
2000 host->port, 1, sc, 0);
2001 rx_SetConnDeadTime(conns[j], 2);
2002 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2006 assert(j); /* at least one alternate address */
2007 ViceLog(125,("Starting multiprobe on all addr for host %s\n",
2008 afs_inet_ntoa_r(host->host,hoststr)));
2012 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2017 if ( host->callback_rxcon )
2018 rx_DestroyConnection(host->callback_rxcon);
2019 host->callback_rxcon = conns[multi_i];
2020 host->host = addr[multi_i];
2021 connSuccess = conns[multi_i];
2022 rx_SetConnDeadTime(host->callback_rxcon, 50);
2023 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2024 ViceLog(125,("multiprobe success with addr %s\n",
2025 afs_inet_ntoa_r(addr[multi_i],hoststr)));
2032 /* Destroy all connections except the one on which we succeeded */
2033 for ( i=0; i < j; i++)
2034 if ( conns[i] != connSuccess )
2035 rx_DestroyConnection(conns[i] );
2040 if ( connSuccess ) return 0; /* success */
2041 else return 1; /* failure */
2044 #endif /* !defined(INTERPRET_DUMP) */