2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * NEW callback package callback.c (replaces vicecb.c)
12 * Updated call back routines, NOW with:
14 * Faster DeleteVenus (Now called DeleteAllCallBacks)
15 * Call back breaking for volumes
16 * Adaptive timeouts on call backs
17 * Architected for Multi RPC
18 * No locks (currently implicit vnode locks--these will go, to)
19 * Delayed call back when rpc connection down.
20 * Bulk break of delayed call backs when rpc connection
22 * Strict limit on number of call backs.
24 * InitCallBack(nblocks)
25 * Initialize: nblocks is max number # of file entries + # of callback entries
26 * nblocks must be < 65536
27 * Space used is nblocks*16 bytes
28 * Note that space will be reclaimed by breaking callbacks of old hosts
30 * time = AddCallBack(host, fid)
32 * Returns the expiration time at the workstation.
34 * BreakCallBack(host, fid)
35 * Break all call backs for fid, except for the specified host.
38 * BreakVolumeCallBacks(volume)
39 * Break all call backs on volume, using single call to each host
40 * Delete all the call backs.
42 * DeleteCallBack(host,fid)
43 * Delete (do not break) single call back for fid.
45 * DeleteFileCallBacks(fid)
46 * Delete (do not break) all call backs for fid.
48 * DeleteAllCallBacks(host)
49 * Delete (do not break) all call backs for host.
51 * CleanupTimedOutCallBacks()
52 * Delete all timed out call back entries
53 * Must be called periodically by file server.
55 * BreakDelayedCallBacks(host)
56 * Break all delayed call backs for host.
57 * Returns 1: one or more failed, 0: success.
59 * PrintCallBackStats()
60 * Print statistics about call backs to stdout.
62 * DumpCallBacks() ---wishful thinking---
63 * Dump call back state to /tmp/callback.state.
64 * This is separately interpretable by the program pcb.
66 * Notes: In general, if a call back to a host doesn't get through,
67 * then HostDown, supplied elsewhere, is called. BreakDelayedCallBacks,
68 * however, does not call HostDown, but instead returns an indication of
69 * success if all delayed call backs were finally broken.
71 * BreakDelayedCallBacks MUST be called at the first sign of activity
72 * from the host after HostDown has been called (or a previous
73 * BreakDelayedCallBacks failed). The BreakDelayedCallBacks must be
74 * allowed to complete before any requests from that host are handled.
75 * If BreakDelayedCallBacks fails, then the host should remain
76 * down (and the request should be failed).
78 * CleanupCallBacks MUST be called periodically by the file server for
79 * this package to work correctly. Every 5 minutes is suggested.
82 #include <afsconfig.h>
83 #include <afs/param.h>
89 #include <stdlib.h> /* for malloc() */
90 #include <time.h> /* ANSI standard location for time stuff */
101 #ifdef HAVE_STRINGS_H
105 #include <afs/assert.h>
107 #include <afs/stds.h>
109 #include <afs/nfs.h> /* yuck. This is an abomination. */
112 #include <afscbint.h>
113 #include <afs/afsutil.h>
115 #include <afs/ihandle.h>
116 #include <afs/vnode.h>
117 #include <afs/volume.h>
118 #include "viced_prototypes.h"
121 #include <afs/ptclient.h> /* need definition of prlist for host.h */
124 extern afsUUID FS_HostUUID;
125 extern int hostCount;
126 int ShowProblems = 1;
128 /* Maximum number of call backs to break at once, single fid */
129 /* There is some debate as to just how large this value should be */
130 /* Ideally, it would be very very large, but I am afraid that the */
131 /* cache managers will all send in their responses simultaneously, */
132 /* thereby swamping the file server. As a result, something like */
133 /* 10 or 15 might be a better bet. */
134 #define MAX_CB_HOSTS 10
136 /* max time to break a callback, otherwise client is dead or net is hosed */
139 #define u_byte unsigned char
141 struct cbcounters cbstuff;
157 } *FE; /* Don't use FE[0] */
161 afs_uint32 cnext; /* Next call back entry */
162 afs_uint32 fhead; /* Head of this call back chain */
163 u_byte thead; /* Head of timeout chain */
164 u_byte status; /* Call back status; see definitions, below */
165 afs_uint32 hhead; /* Head of host table chain */
166 afs_uint32 tprev, tnext; /* Timeout chain */
167 afs_uint32 hprev, hnext; /* Chain from host table */
168 unsigned short spare; /* make it a multiple of 32 bits. */
169 } *CB; /* Don't use CB[0] */
171 /* status values for status field of CallBack structure */
172 #define CB_NORMAL 1 /* Normal call back */
173 #define CB_DELAYED 2 /* Delayed call back due to rpc problems.
174 * The call back entry will be added back to the
175 * host list at the END of the list, so that
176 * searching backwards in the list will find all
177 * the (consecutive)host. delayed call back entries */
178 #define CB_VOLUME 3 /* Callback for a volume */
179 #define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
181 /* call back indices to pointers, and vice-versa */
182 #define itocb(i) ((i)?CB+(i):0)
183 #define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
185 /* file entry indices to pointers, and vice-versa */
186 #define itofe(i) ((i)?FE+(i):0)
187 #define fetoi(fep) (!(fep)?0:(fep)-FE)
189 /* Timeouts: there are 128 possible timeout values in effect at any
190 * given time. Each timeout represents timeouts in an interval of 128
191 * seconds. So the maximum timeout for a call back is 128*128=16384
192 * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
193 * if space runs out or by the file server every 5 minutes. This 5
194 * minute slack should be allowed for--so a maximum time of 4 hours
197 * Timeouts must be chosen to correspond to an exact multiple
198 * of 128, because all times are truncated to a 128 multiple, and
199 * timed out if the current truncated time is <= to the truncated time
200 * corresponding to the timeout queue.
203 /* Unix time to Call Back time, and vice-versa. Call back time is
204 in units of 128 seconds, corresponding to time queues. */
205 #define CBtime(uxtime) ((uxtime)>>7)
206 #define UXtime(cbtime) ((cbtime)<<7)
208 /* Given a Unix time, compute the closest Unix time that corresponds to
209 a time queue, rounding up */
210 #define TimeCeiling(uxtime) (((uxtime)+127)&~127)
212 /* Time to live for call backs depends upon number of users of the file.
213 * TimeOuts is indexed by this number/8 (using TimeOut macro). Times
214 * in this table are for the workstation; server timeouts, add
217 static int TimeOuts[] = {
218 /* Note: don't make the first entry larger than 4 hours (see above) */
219 4 * 60 * 60, /* 0-7 users */
220 1 * 60 * 60, /* 8-15 users */
221 30 * 60, /* 16-23 users */
222 15 * 60, /* 24-31 users */
223 15 * 60, /* 32-39 users */
224 10 * 60, /* 40-47 users */
225 10 * 60, /* 48-55 users */
226 10 * 60, /* 56-63 users */
227 }; /* Anything more: MinTimeOut */
229 /* minimum time given for a call back */
230 static int MinTimeOut = (7 * 60);
232 #define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
233 #define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
235 /* time out at server is 3 minutes more than ws */
236 #define ServerBias (3*60)
238 /* Heads of CB queues; a timeout index is 1+index into this array */
239 static afs_uint32 timeout[128];
241 /* Convert cbtime to timeout queue index */
242 #define TIndex(cbtime) (((cbtime)&127)+1)
244 /* Convert cbtime to pointer to timeout queue head */
245 #define THead(cbtime) (&timeout[TIndex(cbtime)-1])
247 static afs_int32 tfirst; /* cbtime of oldest unexpired call back time queue */
249 /* Normalize index into timeout array so that two such indices will be
250 ordered correctly, so that they can be compared to see which times
251 sooner, or so that the difference in time out times between them
253 #define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
255 /* This converts a timeout index into the actual time it will expire */
256 #define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
259 /* Convert pointer to timeout queue head to index, and vice versa */
260 #define ttoi(t) ((t-timeout)+1)
261 #define itot(i) ((timeout)+(i-1))
263 /* 16 byte object get/free routines */
269 struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
271 afs_uint32 thead; /* head of timeout queue for youngest callback */
275 struct CallBack *CBfree = 0;
276 struct FileEntry *FEfree = 0;
278 /* Prototypes for static routines */
279 static struct FileEntry *FindFE(register AFSFid * fid);
280 static struct CallBack *iGetCB(register int *nused);
281 static int iFreeCB(register struct CallBack *cb, register int *nused);
282 static struct FileEntry *iGetFE(register int *nused);
283 static int iFreeFE(register struct FileEntry *fe, register int *nused);
284 static int TAdd(register struct CallBack *cb, register afs_uint32 * thead);
285 static int TDel(register struct CallBack *cb);
286 static int HAdd(register struct CallBack *cb, register struct host *host);
287 static int HDel(register struct CallBack *cb);
288 static int CDel(struct CallBack *cb, int deletefe);
289 static int CDelPtr(register struct FileEntry *fe, register afs_uint32 * cbp,
291 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host);
292 static int FDel(register struct FileEntry *fe);
293 static int AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead,
294 int type, int locked);
295 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
296 struct AFSCBFids *afidp, struct host *xhost);
297 static int MultiBreakVolumeCallBack_r(struct host *host, int isheld,
298 struct VCBParams *parms, int deletefe);
299 static int MultiBreakVolumeCallBack(struct host *host, int isheld,
300 struct VCBParams *parms);
301 static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
302 struct VCBParams *parms);
303 static int lih_r(register struct host *host, register int held,
304 register struct host *hostp);
305 static int GetSomeSpace_r(struct host *hostp, int locked);
306 static int ClearHostCallbacks_r(struct host *hp, int locked);
308 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
309 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
310 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
311 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
313 /* Other protos - move out sometime */
314 extern void ShutDown();
316 #define VHASH 512 /* Power of 2 */
317 static afs_uint32 HashTable[VHASH]; /* File entry hash table */
318 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
320 static struct FileEntry *
321 FindFE(register AFSFid * fid)
325 register struct FileEntry *fe;
327 hash = VHash(fid->Volume, fid->Unique);
328 for (fei = HashTable[hash]; fei; fei = fe->fnext) {
330 if (fe->volid == fid->Volume && fe->unique == fid->Unique
331 && fe->vnode == fid->Vnode)
337 #ifndef INTERPRET_DUMP
339 static struct CallBack *
340 iGetCB(register int *nused)
342 register struct CallBack *ret;
344 if ((ret = CBfree)) {
345 CBfree = (struct CallBack *)(((struct object *)ret)->next);
352 iFreeCB(register struct CallBack *cb, register int *nused)
354 ((struct object *)cb)->next = (struct object *)CBfree;
360 static struct FileEntry *
361 iGetFE(register int *nused)
363 register struct FileEntry *ret;
365 if ((ret = FEfree)) {
366 FEfree = (struct FileEntry *)(((struct object *)ret)->next);
373 iFreeFE(register struct FileEntry *fe, register int *nused)
375 ((struct object *)fe)->next = (struct object *)FEfree;
381 /* Add cb to end of specified timeout list */
383 TAdd(register struct CallBack *cb, register afs_uint32 * thead)
386 (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
388 register struct CallBack *thp = itocb(*thead);
390 cb->tprev = thp->tprev;
394 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
396 thp->tprev = cbtoi(cb);
399 cb->thead = ttoi(thead);
403 /* Delete call back entry from timeout list */
405 TDel(register struct CallBack *cb)
407 register afs_uint32 *thead = itot(cb->thead);
409 if (*thead == cbtoi(cb))
410 *thead = (*thead == cb->tnext ? 0 : cb->tnext);
411 if (itocb(cb->tprev))
412 itocb(cb->tprev)->tnext = cb->tnext;
413 if (itocb(cb->tnext))
414 itocb(cb->tnext)->tprev = cb->tprev;
418 /* Add cb to end of specified host list */
420 HAdd(register struct CallBack *cb, register struct host *host)
422 cb->hhead = h_htoi(host);
424 host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
426 register struct CallBack *hhp = itocb(host->cblist);
428 cb->hprev = hhp->hprev;
429 cb->hnext = host->cblist;
430 hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
435 /* Delete call back entry from host list */
437 HDel(register struct CallBack *cb)
439 register afs_uint32 *hhead = &h_itoh(cb->hhead)->cblist;
441 if (*hhead == cbtoi(cb))
442 *hhead = (*hhead == cb->hnext ? 0 : cb->hnext);
443 itocb(cb->hprev)->hnext = cb->hnext;
444 itocb(cb->hnext)->hprev = cb->hprev;
448 /* Delete call back entry from fid's chain of cb's */
449 /* N.B. This one also deletes the CB, and also possibly parent FE, so
450 * make sure that it is not on any other list before calling this
453 CDel(struct CallBack *cb, int deletefe)
456 struct FileEntry *fe = itofe(cb->fhead);
457 register afs_uint32 *cbp;
460 for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
461 cbp = &itocb(*cbp)->cnext, safety++) {
462 if (safety > cbstuff.nblks + 10) {
465 ("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",
466 cbi, fe->firstcb, *cbp));
468 ShutDownAndCore(PANIC);
471 CDelPtr(fe, cbp, deletefe);
475 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
476 * as well as file entry */
477 /* N.B. This one also deletes the CB, and also possibly parent FE, so
478 * make sure that it is not on any other list before calling this
480 int Ccdelpt = 0, CcdelB = 0;
483 CDelPtr(register struct FileEntry *fe, register afs_uint32 * cbp,
486 register struct CallBack *cb;
496 if (deletefe && (--fe->ncbs == 0))
502 FindCBPtr(struct FileEntry *fe, struct host *host)
504 register afs_uint32 hostindex = h_htoi(host);
505 register struct CallBack *cb;
506 register afs_uint32 *cbp;
509 for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
510 if (safety > cbstuff.nblks) {
511 ViceLog(0, ("FindCBPtr: Internal Error -- shutting down.\n"));
513 ShutDownAndCore(PANIC);
516 if (cb->hhead == hostindex)
522 /* Delete file entry from hash table */
524 FDel(register struct FileEntry *fe)
526 register int fei = fetoi(fe);
527 register afs_uint32 *p = &HashTable[VHash(fe->volid, fe->unique)];
529 while (*p && *p != fei)
530 p = &itofe(*p)->fnext;
538 InitCallBack(int nblks)
541 tfirst = CBtime(FT_ApproxTime());
542 /* N.B. The "-1", below, is because
543 * FE[0] and CB[0] are not used--and not allocated */
544 FE = ((struct FileEntry *)(calloc(nblks, sizeof(struct FileEntry)))) - 1;
546 ViceLog(0, ("Failed malloc in InitCallBack\n"));
549 cbstuff.nFEs = nblks;
551 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
552 CB = ((struct CallBack *)(calloc(nblks, sizeof(struct CallBack)))) - 1;
554 ViceLog(0, ("Failed malloc in InitCallBack\n"));
557 cbstuff.nCBs = nblks;
559 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
560 cbstuff.nblks = nblks;
561 cbstuff.nbreakers = 0;
567 XCallBackBulk_r(struct host * ahost, struct AFSFid * fids, afs_int32 nfids)
569 struct AFSCallBack tcbs[AFSCBMAX];
575 struct rx_connection *cb_conn = NULL;
578 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
579 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
586 for (i = 0; i < nfids && i < AFSCBMAX; i++) {
587 tcbs[i].CallBackVersion = CALLBACK_VERSION;
588 tcbs[i].ExpirationTime = 0;
589 tcbs[i].CallBackType = CB_DROPPED;
591 tf.AFSCBFids_len = i;
592 tf.AFSCBFids_val = &(fids[j]);
596 tc.AFSCBs_val = tcbs;
598 cb_conn = ahost->callback_rxcon;
599 rx_GetConnection(cb_conn);
601 code |= RXAFSCB_CallBack(cb_conn, &tf, &tc);
602 rx_PutConnection(cb_conn);
610 /* the locked flag tells us if the host entry has already been locked
611 * by our parent. I don't think anybody actually calls us with the
612 * host locked, but here's how to make that work: GetSomeSpace has to
613 * change so that it doesn't attempt to lock any hosts < "host". That
614 * means that it might be unable to free any objects, so it has to
615 * return an exit status. If it fails, then AddCallBack1 might fail,
616 * as well. If so, the host->ResetDone should probably be set to 0,
617 * and we probably don't want to return a callback promise to the
618 * cache manager, either. */
620 AddCallBack1(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
628 retVal = AddCallBack1_r(host, fid, thead, type, 1);
638 AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
641 struct FileEntry *fe;
642 struct CallBack *cb = 0, *lastcb = 0;
643 struct FileEntry *newfe = 0;
645 afs_uint32 *Thead = thead;
646 struct CallBack *newcb = 0;
651 /* allocate these guys first, since we can't call the allocator with
652 * the host structure locked -- or we might deadlock. However, we have
653 * to avoid races with FindFE... */
654 while (!(newcb = GetCB())) {
655 GetSomeSpace_r(host, locked);
657 while (!(newfe = GetFE())) { /* Get it now, so we don't have to call */
658 /* GetSomeSpace with the host locked, later. This might turn out to */
659 /* have been unneccessary, but that's actually kind of unlikely, since */
660 /* most files are not shared. */
661 GetSomeSpace_r(host, locked);
665 h_Lock_r(host); /* this can yield, so do it before we get any */
670 if (type == CB_NORMAL) {
672 TimeCeiling(FT_ApproxTime() + TimeOut(fe ? fe->ncbs : 0) +
674 Thead = THead(CBtime(time_out));
675 } else if (type == CB_VOLUME) {
676 time_out = TimeCeiling((60 * 120 + FT_ApproxTime()) + ServerBias);
677 Thead = THead(CBtime(time_out));
678 } else if (type == CB_BULK) {
679 /* bulk status can get so many callbacks all at once, and most of them
680 * are probably not for things that will be used for long.
683 TimeCeiling(FT_ApproxTime() + ServerBias +
684 TimeOut(22 + (fe ? fe->ncbs : 0)));
685 Thead = THead(CBtime(time_out));
691 register afs_uint32 hash;
696 fe->volid = fid->Volume;
697 fe->vnode = fid->Vnode;
698 fe->unique = fid->Unique;
700 hash = VHash(fid->Volume, fid->Unique);
701 fe->fnext = HashTable[hash];
702 HashTable[hash] = fetoi(fe);
704 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
705 lastcb = cb, cb = itocb(cb->cnext), safety++) {
706 if (safety > cbstuff.nblks) {
707 ViceLog(0, ("AddCallBack1: Internal Error -- shutting down.\n"));
709 ShutDownAndCore(PANIC);
711 if (cb->hhead == h_htoi(host))
714 if (cb) { /* Already have call back: move to new timeout list */
715 /* don't change delayed callbacks back to normal ones */
716 if (cb->status != CB_DELAYED)
718 /* Only move if new timeout is longer */
719 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
726 *(lastcb ? &lastcb->cnext : &fe->firstcb) = cbtoi(cb);
729 cb->fhead = fetoi(fe);
735 /* now free any still-unused callback or host entries */
741 if (!locked) /* freecb and freefe might(?) yield */
744 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK)
745 return time_out - ServerBias; /* Expires sooner at workstation */
750 /* Take an array full of hosts, all held. Break callbacks to them, and
751 * release the holds once you're done, except don't release xhost. xhost
752 * may be NULL. Currently only works for a single Fid in afidp array.
753 * If you want to make this work with multiple fids, you need to fix
754 * the error handling. One approach would be to force a reset if a
755 * multi-fid call fails, or you could add delayed callbacks for each
756 * fid. You probably also need to sort and remove duplicate hosts.
757 * When this is called from the BreakVolumeCallBacks path, it does NOT
758 * force a reset if the RPC fails, it just marks the host down and tries
759 * to create a delayed callback. */
760 /* N.B. be sure that code works when ncbas == 0 */
761 /* N.B. requires all the cba[*].hp pointers to be valid... */
762 /* This routine does not hold a lock on the host for the duration of
763 * the BreakCallBack RPC, which is a significant deviation from tradition.
764 * It _does_ get a lock on the host before setting VenusDown = 1,
765 * which is sufficient only if VenusDown = 0 only happens when the
766 * lock is held over the RPC and the subsequent VenusDown == 0
767 * wherever that is done. */
769 MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
770 struct AFSCBFids *afidp, struct host *xhost)
773 struct rx_connection *conns[MAX_CB_HOSTS];
774 static struct AFSCBs tc = { 0, 0 };
776 assert(ncbas <= MAX_CB_HOSTS);
778 /* set up conns for multi-call */
779 for (i = 0, j = 0; i < ncbas; i++) {
780 struct host *thishost = cba[i].hp;
781 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
784 rx_GetConnection(thishost->callback_rxcon);
785 conns[j++] = thishost->callback_rxcon;
788 rx_SetConnDeadTime(thishost->callback_rxcon, 4);
789 rx_SetConnHardDeadTime(thishost->callback_rxcon, AFS_HARDDEADTIME);
793 if (j) { /* who knows what multi would do with 0 conns? */
797 multi_RXAFSCB_CallBack(afidp, &tc);
804 /* If there's an error, we have to hunt for the right host.
805 * The conns array _should_ correspond one-to-one to the cba
806 * array, except in some rare cases it might be missing one
807 * or more elements. So the optimistic case is almost
808 * always right. At worst, it's the starting point for the
810 for (hp = 0, i = multi_i; i < j; i++) {
811 hp = cba[i].hp; /* optimistic, but usually right */
815 if (conns[multi_i] == hp->callback_rxcon) {
823 ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n", hp,
827 ** try breaking callbacks on alternate interface addresses
829 if (MultiBreakCallBackAlternateAddress(hp, afidp)) {
832 ("BCB: Failed on file %u.%u.%u, host %s:%d is down\n",
833 afidp->AFSCBFids_val->Volume,
834 afidp->AFSCBFids_val->Vnode,
835 afidp->AFSCBFids_val->Unique,
836 afs_inet_ntoa_r(hp->host, hoststr),
842 hp->hostFlags |= VENUSDOWN;
844 * We always go into AddCallBack1_r with the host locked
846 AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
859 for (i = 0; i < ncbas; i++) {
862 if (hp && xhost != hp) {
867 /* H_UNLOCK around this so h_FreeConnection does not deadlock.
868 h_FreeConnection should *never* be called on a callback connection,
869 but on 10/27/04 a deadlock occurred where it was, when we know why,
870 this should be reverted. -- shadow */
872 for (i = 0; i < j; i++) {
873 rx_PutConnection(conns[i]);
881 * Break all call backs for fid, except for the specified host (unless flag
882 * is true, in which case all get a callback message. Assumption: the specified
883 * host is h_Held, by the caller; the others aren't.
884 * Specified host may be bogus, that's ok. This used to check to see if the
885 * host was down in two places, once right after the host was h_held, and
886 * again after it was locked. That race condition is incredibly rare and
887 * relatively harmless even when it does occur, so we don't check for it now.
889 /* if flag is true, send a break callback msg to "host", too */
891 BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
893 struct FileEntry *fe;
894 struct CallBack *cb, *nextcb;
895 struct cbstruct cba[MAX_CB_HOSTS];
902 ("BCB: BreakCallBack(all but %s:%d, (%u,%u,%u))\n",
903 afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
904 fid->Volume, fid->Vnode, fid->Unique));
907 cbstuff.BreakCallBacks++;
912 hostindex = h_htoi(xhost);
913 cb = itocb(fe->firstcb);
914 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
915 /* the most common case is what follows the || */
918 tf.AFSCBFids_len = 1;
919 tf.AFSCBFids_val = fid;
922 for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
923 nextcb = itocb(cb->cnext);
924 if ((cb->hhead != hostindex || flag)
925 && (cb->status == CB_BULK || cb->status == CB_NORMAL
926 || cb->status == CB_VOLUME)) {
927 struct host *thishost = h_itoh(cb->hhead);
929 ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
930 } else if (thishost->hostFlags & VENUSDOWN) {
932 ("BCB: %s:%d is down; delaying break call back\n",
933 afs_inet_ntoa_r(thishost->host, hoststr),
934 ntohs(thishost->port)));
935 cb->status = CB_DELAYED;
938 cba[ncbas].hp = thishost;
939 cba[ncbas].thead = cb->thead;
943 CDel(cb, 1); /* Usually first; so this delete
944 * is reasonably inexpensive */
950 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
952 /* we need to to all these initializations again because MultiBreakCallBack may block */
957 cb = itocb(fe->firstcb);
958 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
959 /* the most common case is what follows the || */
970 /* Delete (do not break) single call back for fid */
972 DeleteCallBack(struct host *host, AFSFid * fid)
974 register struct FileEntry *fe;
975 register afs_uint32 *pcb;
978 cbstuff.DeleteCallBacks++;
987 ("DCB: No call backs for fid (%u, %u, %u)\n", fid->Volume,
988 fid->Vnode, fid->Unique));
991 pcb = FindCBPtr(fe, host);
994 ("DCB: No call back for host %s:%d, (%u, %u, %u)\n",
995 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
996 fid->Volume, fid->Vnode, fid->Unique));
1003 CDelPtr(fe, pcb, 1);
1010 * Delete (do not break) all call backs for fid. This call doesn't
1011 * set all of the various host locks, but it shouldn't really matter
1012 * since we're not adding callbacks, but deleting them. I'm not sure
1013 * why it doesn't set the lock, however; perhaps it should.
1016 DeleteFileCallBacks(AFSFid * fid)
1018 register struct FileEntry *fe;
1019 register struct CallBack *cb;
1020 register afs_uint32 cbi;
1024 cbstuff.DeleteFiles++;
1029 ("DF: No fid (%u,%u,%u) to delete\n", fid->Volume, fid->Vnode,
1033 for (n = 0, cbi = fe->firstcb; cbi; n++) {
1045 /* Delete (do not break) all call backs for host. The host should be
1048 DeleteAllCallBacks_r(struct host *host, int deletefe)
1050 register struct CallBack *cb;
1051 register int cbi, first;
1053 cbstuff.DeleteAllCallBacks++;
1054 cbi = first = host->cblist;
1056 ViceLog(8, ("DV: no call backs\n"));
1064 } while (cbi != first);
1070 * Break all delayed call backs for host. Returns 1 if all call backs
1071 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1072 * Must be called with VenusDown set for this host
1075 BreakDelayedCallBacks(struct host *host)
1079 retVal = BreakDelayedCallBacks_r(host);
1085 BreakDelayedCallBacks_r(struct host *host)
1087 struct AFSFid fids[AFSCBMAX];
1088 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1089 int cbi, first, nfids;
1090 struct CallBack *cb;
1093 struct rx_connection *cb_conn;
1095 cbstuff.nbreakers++;
1096 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1097 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1098 cb_conn = host->callback_rxcon;
1099 rx_GetConnection(cb_conn);
1100 if (host->interface) {
1103 RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
1106 code = RXAFSCB_InitCallBackState(cb_conn);
1108 rx_PutConnection(cb_conn);
1111 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1115 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1116 afs_inet_ntoa_r(host->host, hoststr),
1117 ntohs(host->port)));
1119 host->hostFlags |= VENUSDOWN;
1122 ("InitCallBackState success on %s\n",
1123 afs_inet_ntoa_r(host->host, hoststr)));
1124 /* reset was done successfully */
1125 host->hostFlags |= RESETDONE;
1126 host->hostFlags &= ~VENUSDOWN;
1129 while (!(host->hostFlags & HOSTDELETED)) {
1131 host->hostFlags &= ~VENUSDOWN; /* presume up */
1132 cbi = first = host->cblist;
1136 first = host->cblist;
1139 if (cb->status == CB_DELAYED) {
1140 register struct FileEntry *fe = itofe(cb->fhead);
1141 thead[nfids] = cb->thead;
1142 fids[nfids].Volume = fe->volid;
1143 fids[nfids].Vnode = fe->vnode;
1144 fids[nfids].Unique = fe->unique;
1150 } while (cbi && cbi != first && nfids < AFSCBMAX);
1156 if (XCallBackBulk_r(host, fids, nfids)) {
1157 /* Failed, again: put them back, probably with old
1162 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1163 afs_inet_ntoa_r(host->host, hoststr),
1164 ntohs(host->port)));
1166 for (i = 0; i < nfids; i++) {
1169 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1170 afs_inet_ntoa_r(host->host, hoststr),
1171 ntohs(host->port), fids[i].Volume,
1172 fids[i].Vnode, fids[i].Unique));
1175 * AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1176 * * but it turns out to cause too many tricky locking problems.
1177 * * now, if break delayed fails, screw it. */
1179 host->hostFlags |= VENUSDOWN; /* Failed */
1180 ClearHostCallbacks_r(host, 1 /* locked */ );
1184 if (nfids < AFSCBMAX)
1188 cbstuff.nbreakers--;
1189 /* If we succeeded it's always ok to unset HFE_LATER */
1190 if (!host->hostFlags & VENUSDOWN)
1191 host->hostFlags &= ~HFE_LATER;
1192 return (host->hostFlags & VENUSDOWN);
1196 ** isheld is 0 if the host is held in h_Enumerate
1197 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1200 MultiBreakVolumeCallBack_r(struct host *host, int isheld,
1201 struct VCBParams *parms, int deletefe)
1206 return isheld; /* host is held only by h_Enumerate, do nothing */
1207 if (host->hostFlags & HOSTDELETED)
1208 return 0; /* host is deleted, release hold */
1210 if (host->hostFlags & VENUSDOWN) {
1212 if (host->hostFlags & HOSTDELETED) {
1214 return 0; /* Release hold */
1217 ("BVCB: volume call back for host %s:%d failed\n",
1218 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1221 ("CB: volume callback for host %s:%d failed\n",
1222 afs_inet_ntoa_r(host->host, hoststr),
1223 ntohs(host->port)));
1225 DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state
1226 * rather than attempting to
1227 * selectively remember to
1228 * delete the volume callbacks
1230 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1232 return 0; /* release hold */
1234 assert(parms->ncbas <= MAX_CB_HOSTS);
1236 /* Do not call MultiBreakCallBack on the current host structure
1237 ** because it would prematurely release the hold on the host
1239 if (parms->ncbas == MAX_CB_HOSTS) {
1240 struct AFSCBFids tf;
1242 tf.AFSCBFids_len = 1;
1243 tf.AFSCBFids_val = parms->fid;
1245 /* this releases all the hosts */
1246 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */ );
1250 parms->cba[parms->ncbas].hp = host;
1251 parms->cba[(parms->ncbas)++].thead = parms->thead;
1252 return 1; /* DON'T release hold, because we still need it. */
1256 ** isheld is 0 if the host is held in h_Enumerate
1257 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1260 MultiBreakVolumeCallBack(struct host *host, int isheld,
1261 struct VCBParams *parms)
1265 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1271 ** isheld is 0 if the host is held in h_Enumerate
1272 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1275 MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1276 struct VCBParams *parms)
1280 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1286 * Break all call backs on a single volume. Don't call this with any
1287 * hosts h_held. Note that this routine clears the callbacks before
1288 * actually breaking them, and that the vnode isn't locked during this
1289 * operation, so that people might see temporary callback loss while
1290 * this function is executing. It is just a temporary state, however,
1291 * since the callback will be broken later by this same function.
1293 * Now uses multi-RX for CallBack RPC. Note that the
1294 * multiBreakCallBacks routine does not force a reset if the RPC
1295 * fails, unlike the previous version of this routine, but does create
1296 * a delayed callback. Resets will be forced if the host is
1297 * determined to be down before the RPC is executed.
1300 BreakVolumeCallBacks(afs_uint32 volume)
1305 struct CallBack *cb;
1306 struct FileEntry *fe;
1308 struct VCBParams henumParms;
1309 afs_uint32 tthead = 0; /* zero is illegal value */
1312 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1313 for (hash = 0; hash < VHASH; hash++) {
1314 for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
1315 if (fe->volid == volume) {
1316 register struct CallBack *cbnext;
1317 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1318 host = h_itoh(cb->hhead);
1320 cbnext = itocb(cb->cnext);
1321 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1327 /* leave hold for MultiBreakVolumeCallBack to clear */
1338 /* didn't find any callbacks, so return right away. */
1342 henumParms.ncbas = 0;
1343 henumParms.fid = &fid;
1344 henumParms.thead = tthead;
1346 h_Enumerate(MultiBreakVolumeCallBack, (char *)&henumParms);
1348 if (henumParms.ncbas) { /* do left-overs */
1349 struct AFSCBFids tf;
1350 tf.AFSCBFids_len = 1;
1351 tf.AFSCBFids_val = &fid;
1353 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1355 henumParms.ncbas = 0;
1361 #ifdef AFS_PTHREAD_ENV
1362 extern pthread_cond_t fsync_cond;
1364 extern char fsync_wait[];
1368 BreakVolumeCallBacksLater(afs_uint32 volume)
1372 struct FileEntry *fe;
1373 struct CallBack *cb;
1377 ViceLog(25, ("Setting later on volume %u\n", volume));
1379 for (hash = 0; hash < VHASH; hash++) {
1380 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1381 if (fe->volid == volume) {
1382 register struct CallBack *cbnext;
1383 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1384 host = h_itoh(cb->hhead);
1385 host->hostFlags |= HFE_LATER;
1386 cb->status = CB_DELAYED;
1387 cbnext = itocb(cb->cnext);
1390 fe->status |= FE_LATER;
1399 /* didn't find any callbacks, so return right away. */
1403 ViceLog(25, ("Fsync thread wakeup\n"));
1404 #ifdef AFS_PTHREAD_ENV
1405 assert(pthread_cond_broadcast(&fsync_cond) == 0);
1407 LWP_NoYieldSignal(fsync_wait);
1413 BreakLaterCallBacks(void)
1418 struct CallBack *cb;
1419 struct FileEntry *fe = NULL;
1420 struct FileEntry *myfe = NULL;
1422 struct VCBParams henumParms;
1423 unsigned short tthead = 0; /* zero is illegal value */
1426 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1429 /* Pick the first volume we see to clean up */
1430 fid.Volume = fid.Vnode = fid.Unique = 0;
1432 for (hash = 0; hash < VHASH; hash++) {
1433 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1434 if (fe && (fe->status & FE_LATER)
1435 && (fid.Volume == 0 || fid.Volume == fe->volid)) {
1436 /* Ugly, but used to avoid left side casting */
1437 struct object *tmpfe;
1439 ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
1441 fid.Volume = fe->volid;
1443 /* Works since volid is deeper than the largest pointer */
1444 tmpfe = (struct object *)fe;
1445 tmpfe->next = (struct object *)myfe;
1458 /* loop over FEs from myfe and free/break */
1460 for (fe = myfe; fe;) {
1461 register struct CallBack *cbnext;
1462 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1463 host = h_itoh(cb->hhead);
1465 cbnext = itocb(cb->cnext);
1466 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1471 CDel(cb, 0); /* Don't let CDel clean up the fe */
1472 /* leave hold for MultiBreakVolumeCallBack to clear */
1475 fe = (struct FileEntry *)((struct object *)fe)->next;
1480 ViceLog(125, ("Breaking volume %u\n", fid.Volume));
1481 henumParms.ncbas = 0;
1482 henumParms.fid = &fid;
1483 henumParms.thead = tthead;
1485 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *)&henumParms);
1487 if (henumParms.ncbas) { /* do left-overs */
1488 struct AFSCBFids tf;
1489 tf.AFSCBFids_len = 1;
1490 tf.AFSCBFids_val = &fid;
1492 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1493 henumParms.ncbas = 0;
1498 /* Arrange to be called again */
1503 * Delete all timed-out call back entries (to be called periodically by file
1507 CleanupTimedOutCallBacks(void)
1510 CleanupTimedOutCallBacks_r();
1516 CleanupTimedOutCallBacks_r(void)
1518 afs_uint32 now = CBtime(FT_ApproxTime());
1519 register afs_uint32 *thead;
1520 register struct CallBack *cb;
1521 register int ntimedout = 0;
1524 while (tfirst <= now) {
1526 cbi = *(thead = THead(tfirst));
1532 ("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1533 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
1534 h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
1535 itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
1539 if (ntimedout > cbstuff.nblks) {
1540 ViceLog(0, ("CCB: Internal Error -- shutting down...\n"));
1541 DumpCallBackState();
1542 ShutDownAndCore(PANIC);
1544 } while (cbi != *thead);
1549 cbstuff.CBsTimedOut += ntimedout;
1550 ViceLog(7, ("CCB: deleted %d timed out callbacks\n", ntimedout));
1551 return (ntimedout > 0);
1554 static struct host *lih_host;
1555 static int lih_host_held = 0;
1558 lih_r(register struct host *host, register int held,
1559 register struct host *hostp)
1563 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1564 && (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
1574 /* This could be upgraded to get more space each time */
1575 /* first pass: find the oldest host which isn't held by anyone */
1576 /* second pass: find the oldest host who isn't "me" */
1577 /* always called with hostp unlocked */
1578 extern struct host *hostList;
1580 GetSomeSpace_r(struct host *hostp, int locked)
1582 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1585 cbstuff.GotSomeSpaces++;
1587 ("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1588 if (CleanupTimedOutCallBacks_r()) {
1594 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1598 if (!ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
1611 ("GSS: Try harder for longest inactive host cnt= %d\n",
1614 * Next time try getting callbacks from any host even if
1615 * it's deleted (that's actually great since we can freely
1616 * remove its callbacks) or it's held since the only other
1617 * option is starvation for the file server (i.e. until the
1618 * callback timeout arrives).
1624 * No choice to clear this host's callback state
1626 /* third pass: we still haven't gotten any space, so we free what we had
1627 * previously passed over. */
1632 ClearHostCallbacks_r(hostp, 1 /*already locked */ );
1639 /* locked - set if caller has already locked the host */
1641 ClearHostCallbacks_r(struct host *hp, int locked)
1646 struct rx_connection *cb_conn = NULL;
1649 ("GSS: Delete longest inactive host %s\n",
1650 afs_inet_ntoa_r(hp->host, hoststr)));
1651 if (!(held = h_Held_r(hp)))
1654 /** Try a non-blocking lock. If the lock is already held return
1655 * after releasing hold on hp
1658 if (h_NBLock_r(hp)) {
1664 if (hp->Console & 2) {
1666 * If the special console field is set it means that a thread
1667 * is waiting in AddCallBack1 after it set pointers to the
1668 * file entry and/or callback entry. Because of the bogus
1669 * usage of h_hold it won't prevent from another thread, this
1670 * one, to remove all the callbacks so just to be safe we keep
1671 * a reference. NOTE, on the last phase we'll free the calling
1672 * host's callbacks but that's ok...
1676 DeleteAllCallBacks_r(hp, 1);
1677 if (hp->hostFlags & VENUSDOWN) {
1678 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1680 /* host is up, try a call */
1681 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1682 cb_conn = hp->callback_rxcon;
1683 rx_GetConnection(hp->callback_rxcon);
1684 if (hp->interface) {
1687 RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
1690 code = RXAFSCB_InitCallBackState(cb_conn);
1692 rx_PutConnection(cb_conn);
1695 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1697 /* failed, mark host down and need reset */
1698 hp->hostFlags |= VENUSDOWN;
1699 hp->hostFlags &= ~RESETDONE;
1701 /* reset succeeded, we're done */
1702 hp->hostFlags |= RESETDONE;
1713 #endif /* INTERPRET_DUMP */
1717 PrintCallBackStats(void)
1720 "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1721 cbstuff.AddCallBacks, cbstuff.BreakCallBacks,
1722 cbstuff.DeleteCallBacks, cbstuff.DeleteFiles, cbstuff.CBsTimedOut,
1723 cbstuff.GotSomeSpaces, cbstuff.DeleteAllCallBacks);
1724 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1725 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs + cbstuff.nFEs,
1731 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1733 #ifndef INTERPRET_DUMP
1736 DumpCallBackState(void)
1739 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1741 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY | O_CREAT | O_TRUNC,
1745 ("Couldn't create callback dump file %s\n",
1746 AFSDIR_SERVER_CBKDUMP_FILEPATH));
1749 (void)write(fd, &magic, sizeof(magic));
1750 (void)write(fd, &now, sizeof(now));
1751 (void)write(fd, &cbstuff, sizeof(cbstuff));
1752 (void)write(fd, TimeOuts, sizeof(TimeOuts));
1753 (void)write(fd, timeout, sizeof(timeout));
1754 (void)write(fd, &tfirst, sizeof(tfirst));
1755 freelisthead = cbtoi((struct CallBack *)CBfree);
1756 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1757 freelisthead = fetoi((struct FileEntry *)FEfree);
1758 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1759 (void)write(fd, HashTable, sizeof(HashTable));
1760 (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1761 (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1769 #ifdef INTERPRET_DUMP
1771 /* This is only compiled in for the callback analyzer program */
1772 /* Returns the time of the dump */
1774 ReadDump(char *file)
1777 afs_uint32 magic, freelisthead;
1780 fd = open(file, O_RDONLY);
1782 fprintf(stderr, "Couldn't read dump file %s\n", file);
1785 read(fd, &magic, sizeof(magic));
1786 if (magic != MAGIC) {
1788 "Magic number of %s is invalid. You might be trying to\n",
1791 "run this program on a machine type with a different byte ordering.\n");
1794 read(fd, &now, sizeof(now));
1795 read(fd, &cbstuff, sizeof(cbstuff));
1796 read(fd, TimeOuts, sizeof(TimeOuts));
1797 read(fd, timeout, sizeof(timeout));
1798 read(fd, &tfirst, sizeof(tfirst));
1799 read(fd, &freelisthead, sizeof(freelisthead));
1800 CB = ((struct CallBack
1801 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1802 FE = ((struct FileEntry
1803 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1804 CBfree = (struct CallBack *)itocb(freelisthead);
1805 read(fd, &freelisthead, sizeof(freelisthead));
1806 FEfree = (struct FileEntry *)itofe(freelisthead);
1807 read(fd, HashTable, sizeof(HashTable));
1808 read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1809 read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1811 perror("Error reading dumpfile");
1817 #include "AFS_component_version_number.c"
1820 main(int argc, char **argv)
1822 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1824 register struct FileEntry *fe;
1825 register struct CallBack *cb;
1828 memset(&fid, 0, sizeof(fid));
1831 while (argc && **argv == '-') {
1834 if (!strcmp(*argv, "-host")) {
1840 cbi = atoi(*++argv);
1841 } else if (!strcmp(*argv, "-fid")) {
1847 fid.Volume = atoi(*++argv);
1848 fid.Vnode = atoi(*++argv);
1849 fid.Unique = atoi(*++argv);
1850 } else if (!strcmp(*argv, "-time")) {
1851 fprintf(stderr, "-time not supported\n");
1853 } else if (!strcmp(*argv, "-stats")) {
1855 } else if (!strcmp(*argv, "-all")) {
1857 } else if (!strcmp(*argv, "-raw")) {
1859 } else if (!strcmp(*argv, "-volume")) {
1865 vol = atoi(*++argv);
1870 if (err || argc != 1) {
1872 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
1874 "[cbid is shown for each host in the hosts.dump file]\n");
1877 now = ReadDump(*argv);
1878 if (stats || noptions == 0) {
1879 time_t uxtfirst = UXtime(tfirst);
1880 printf("The time of the dump was %u %s", now, ctime(&now));
1881 printf("The last time cleanup ran was %u %s", uxtfirst,
1883 PrintCallBackStats();
1887 register afs_uint32 *feip;
1888 register struct CallBack *cb;
1889 register struct FileEntry *fe;
1891 for (hash = 0; hash < VHASH; hash++) {
1892 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1893 if (!vol || (fe->volid == vol)) {
1894 register struct CallBack *cbnext;
1895 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1897 cbnext = itocb(cb->cnext);
1907 afs_uint32 cfirst = cbi;
1912 } while (cbi != cfirst);
1917 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1920 cb = itocb(fe->firstcb);
1923 cb = itocb(cb->cnext);
1927 struct FileEntry *fe;
1929 for (i = 1; i < cbstuff.nblks; i++) {
1930 p = (afs_int32 *) & FE[i];
1931 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1937 PrintCB(register struct CallBack *cb, afs_uint32 now)
1939 struct FileEntry *fe = itofe(cb->fhead);
1940 time_t expires = TIndexToTime(cb->thead);
1942 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1943 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
1944 expires - now, ctime(&expires));
1949 #if !defined(INTERPRET_DUMP)
1951 ** try breaking calbacks on afidp from host. Use multi_rx.
1952 ** return 0 on success, non-zero on failure
1955 MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1959 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1965 MultiBreakCallBackAlternateAddress_r(struct host *host,
1966 struct AFSCBFids *afidp)
1969 struct rx_connection **conns;
1970 struct rx_connection *connSuccess = 0;
1972 static struct rx_securityClass *sc = 0;
1973 static struct AFSCBs tc = { 0, 0 };
1976 /* nothing more can be done */
1977 if (!host->interface)
1978 return 1; /* failure */
1980 assert(host->interface->numberOfInterfaces > 0);
1982 /* the only address is the primary interface */
1983 if (host->interface->numberOfInterfaces == 1)
1984 return 1; /* failure */
1986 /* initialise a security object only once */
1988 sc = rxnull_NewClientSecurityObject();
1990 i = host->interface->numberOfInterfaces;
1991 addr = calloc(i, sizeof(afs_int32));
1992 conns = calloc(i, sizeof(struct rx_connection *));
1993 if (!addr || !conns) {
1995 ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
1999 /* initialize alternate rx connections */
2000 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2001 /* this is the current primary address */
2002 if (host->host == host->interface->addr[i])
2005 addr[j] = host->interface->addr[i];
2007 rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
2008 rx_SetConnDeadTime(conns[j], 2);
2009 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2013 assert(j); /* at least one alternate address */
2015 ("Starting multibreakcall back on all addr for host %s\n",
2016 afs_inet_ntoa_r(host->host, hoststr)));
2018 multi_Rx(conns, j) {
2019 multi_RXAFSCB_CallBack(afidp, &tc);
2023 if (host->callback_rxcon)
2024 rx_DestroyConnection(host->callback_rxcon);
2025 host->callback_rxcon = conns[multi_i];
2026 host->host = addr[multi_i];
2027 connSuccess = conns[multi_i];
2028 rx_SetConnDeadTime(host->callback_rxcon, 50);
2029 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2031 ("multibreakcall success with addr %s\n",
2032 afs_inet_ntoa_r(addr[multi_i], hoststr)));
2039 /* Destroy all connections except the one on which we succeeded */
2040 for (i = 0; i < j; i++)
2041 if (conns[i] != connSuccess)
2042 rx_DestroyConnection(conns[i]);
2048 return 0; /* success */
2050 return 1; /* failure */
2055 ** try multiRX probes to host.
2056 ** return 0 on success, non-zero on failure
2059 MultiProbeAlternateAddress_r(struct host *host)
2062 struct rx_connection **conns;
2063 struct rx_connection *connSuccess = 0;
2065 static struct rx_securityClass *sc = 0;
2068 /* nothing more can be done */
2069 if (!host->interface)
2070 return 1; /* failure */
2072 assert(host->interface->numberOfInterfaces > 0);
2074 /* the only address is the primary interface */
2075 if (host->interface->numberOfInterfaces == 1)
2076 return 1; /* failure */
2078 /* initialise a security object only once */
2080 sc = rxnull_NewClientSecurityObject();
2082 i = host->interface->numberOfInterfaces;
2083 addr = calloc(i, sizeof(afs_int32));
2084 conns = calloc(i, sizeof(struct rx_connection *));
2085 if (!addr || !conns) {
2086 ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
2090 /* initialize alternate rx connections */
2091 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2092 /* this is the current primary address */
2093 if (host->host == host->interface->addr[i])
2096 addr[j] = host->interface->addr[i];
2098 rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
2099 rx_SetConnDeadTime(conns[j], 2);
2100 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2104 assert(j); /* at least one alternate address */
2106 ("Starting multiprobe on all addr for host %s\n",
2107 afs_inet_ntoa_r(host->host, hoststr)));
2109 multi_Rx(conns, j) {
2110 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2114 if (host->callback_rxcon)
2115 rx_DestroyConnection(host->callback_rxcon);
2116 host->callback_rxcon = conns[multi_i];
2117 host->host = addr[multi_i];
2118 connSuccess = conns[multi_i];
2119 rx_SetConnDeadTime(host->callback_rxcon, 50);
2120 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2122 ("multiprobe success with addr %s\n",
2123 afs_inet_ntoa_r(addr[multi_i], hoststr)));
2130 /* Destroy all connections except the one on which we succeeded */
2131 for (i = 0; i < j; i++)
2132 if (conns[i] != connSuccess)
2133 rx_DestroyConnection(conns[i]);
2139 return 0; /* success */
2141 return 1; /* failure */
2144 #endif /* !defined(INTERPRET_DUMP) */