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 && (fe->status & FE_LATER) != FE_LATER)
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;
701 hash = VHash(fid->Volume, fid->Unique);
702 fe->fnext = HashTable[hash];
703 HashTable[hash] = fetoi(fe);
705 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
706 lastcb = cb, cb = itocb(cb->cnext), safety++) {
707 if (safety > cbstuff.nblks) {
708 ViceLog(0, ("AddCallBack1: Internal Error -- shutting down.\n"));
710 ShutDownAndCore(PANIC);
712 if (cb->hhead == h_htoi(host))
715 if (cb) { /* Already have call back: move to new timeout list */
716 /* don't change delayed callbacks back to normal ones */
717 if (cb->status != CB_DELAYED)
719 /* Only move if new timeout is longer */
720 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
724 if (newfe == NULL) { /* we are using the new FE */
725 fe->firstcb = cbtoi(cb);
727 cb->fhead = fetoi(fe);
732 *(lastcb ? &lastcb->cnext : &fe->firstcb) = cbtoi(cb);
735 cb->fhead = fetoi(fe);
741 /* now free any still-unused callback or host entries */
747 if (!locked) /* freecb and freefe might(?) yield */
750 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK)
751 return time_out - ServerBias; /* Expires sooner at workstation */
756 /* Take an array full of hosts, all held. Break callbacks to them, and
757 * release the holds once you're done, except don't release xhost. xhost
758 * may be NULL. Currently only works for a single Fid in afidp array.
759 * If you want to make this work with multiple fids, you need to fix
760 * the error handling. One approach would be to force a reset if a
761 * multi-fid call fails, or you could add delayed callbacks for each
762 * fid. You probably also need to sort and remove duplicate hosts.
763 * When this is called from the BreakVolumeCallBacks path, it does NOT
764 * force a reset if the RPC fails, it just marks the host down and tries
765 * to create a delayed callback. */
766 /* N.B. be sure that code works when ncbas == 0 */
767 /* N.B. requires all the cba[*].hp pointers to be valid... */
768 /* This routine does not hold a lock on the host for the duration of
769 * the BreakCallBack RPC, which is a significant deviation from tradition.
770 * It _does_ get a lock on the host before setting VenusDown = 1,
771 * which is sufficient only if VenusDown = 0 only happens when the
772 * lock is held over the RPC and the subsequent VenusDown == 0
773 * wherever that is done. */
775 MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
776 struct AFSCBFids *afidp, struct host *xhost)
779 struct rx_connection *conns[MAX_CB_HOSTS];
780 static struct AFSCBs tc = { 0, 0 };
782 assert(ncbas <= MAX_CB_HOSTS);
784 /* set up conns for multi-call */
785 for (i = 0, j = 0; i < ncbas; i++) {
786 struct host *thishost = cba[i].hp;
787 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
790 rx_GetConnection(thishost->callback_rxcon);
791 conns[j++] = thishost->callback_rxcon;
794 rx_SetConnDeadTime(thishost->callback_rxcon, 4);
795 rx_SetConnHardDeadTime(thishost->callback_rxcon, AFS_HARDDEADTIME);
799 if (j) { /* who knows what multi would do with 0 conns? */
803 multi_RXAFSCB_CallBack(afidp, &tc);
810 /* If there's an error, we have to hunt for the right host.
811 * The conns array _should_ correspond one-to-one to the cba
812 * array, except in some rare cases it might be missing one
813 * or more elements. So the optimistic case is almost
814 * always right. At worst, it's the starting point for the
816 for (hp = 0, i = multi_i; i < j; i++) {
817 hp = cba[i].hp; /* optimistic, but usually right */
821 if (conns[multi_i] == hp->callback_rxcon) {
829 ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n", hp,
833 ** try breaking callbacks on alternate interface addresses
835 if (MultiBreakCallBackAlternateAddress(hp, afidp)) {
838 ("BCB: Failed on file %u.%u.%u, host %s:%d is down\n",
839 afidp->AFSCBFids_val->Volume,
840 afidp->AFSCBFids_val->Vnode,
841 afidp->AFSCBFids_val->Unique,
842 afs_inet_ntoa_r(hp->host, hoststr),
848 hp->hostFlags |= VENUSDOWN;
850 * We always go into AddCallBack1_r with the host locked
852 AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
865 for (i = 0; i < ncbas; i++) {
868 if (hp && xhost != hp) {
873 /* H_UNLOCK around this so h_FreeConnection does not deadlock.
874 h_FreeConnection should *never* be called on a callback connection,
875 but on 10/27/04 a deadlock occurred where it was, when we know why,
876 this should be reverted. -- shadow */
878 for (i = 0; i < j; i++) {
879 rx_PutConnection(conns[i]);
887 * Break all call backs for fid, except for the specified host (unless flag
888 * is true, in which case all get a callback message. Assumption: the specified
889 * host is h_Held, by the caller; the others aren't.
890 * Specified host may be bogus, that's ok. This used to check to see if the
891 * host was down in two places, once right after the host was h_held, and
892 * again after it was locked. That race condition is incredibly rare and
893 * relatively harmless even when it does occur, so we don't check for it now.
895 /* if flag is true, send a break callback msg to "host", too */
897 BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
899 struct FileEntry *fe;
900 struct CallBack *cb, *nextcb;
901 struct cbstruct cba[MAX_CB_HOSTS];
908 ("BCB: BreakCallBack(all but %s:%d, (%u,%u,%u))\n",
909 afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
910 fid->Volume, fid->Vnode, fid->Unique));
913 cbstuff.BreakCallBacks++;
918 hostindex = h_htoi(xhost);
919 cb = itocb(fe->firstcb);
920 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
921 /* the most common case is what follows the || */
924 tf.AFSCBFids_len = 1;
925 tf.AFSCBFids_val = fid;
928 for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
929 nextcb = itocb(cb->cnext);
930 if ((cb->hhead != hostindex || flag)
931 && (cb->status == CB_BULK || cb->status == CB_NORMAL
932 || cb->status == CB_VOLUME)) {
933 struct host *thishost = h_itoh(cb->hhead);
935 ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
936 } else if (thishost->hostFlags & VENUSDOWN) {
938 ("BCB: %s:%d is down; delaying break call back\n",
939 afs_inet_ntoa_r(thishost->host, hoststr),
940 ntohs(thishost->port)));
941 cb->status = CB_DELAYED;
944 cba[ncbas].hp = thishost;
945 cba[ncbas].thead = cb->thead;
949 CDel(cb, 1); /* Usually first; so this delete
950 * is reasonably inexpensive */
956 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
958 /* we need to to all these initializations again because MultiBreakCallBack may block */
963 cb = itocb(fe->firstcb);
964 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
965 /* the most common case is what follows the || */
976 /* Delete (do not break) single call back for fid */
978 DeleteCallBack(struct host *host, AFSFid * fid)
980 register struct FileEntry *fe;
981 register afs_uint32 *pcb;
984 cbstuff.DeleteCallBacks++;
993 ("DCB: No call backs for fid (%u, %u, %u)\n", fid->Volume,
994 fid->Vnode, fid->Unique));
997 pcb = FindCBPtr(fe, host);
1000 ("DCB: No call back for host %s:%d, (%u, %u, %u)\n",
1001 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
1002 fid->Volume, fid->Vnode, fid->Unique));
1009 CDelPtr(fe, pcb, 1);
1016 * Delete (do not break) all call backs for fid. This call doesn't
1017 * set all of the various host locks, but it shouldn't really matter
1018 * since we're not adding callbacks, but deleting them. I'm not sure
1019 * why it doesn't set the lock, however; perhaps it should.
1022 DeleteFileCallBacks(AFSFid * fid)
1024 register struct FileEntry *fe;
1025 register struct CallBack *cb;
1026 register afs_uint32 cbi;
1030 cbstuff.DeleteFiles++;
1035 ("DF: No fid (%u,%u,%u) to delete\n", fid->Volume, fid->Vnode,
1039 for (n = 0, cbi = fe->firstcb; cbi; n++) {
1051 /* Delete (do not break) all call backs for host. The host should be
1054 DeleteAllCallBacks_r(struct host *host, int deletefe)
1056 register struct CallBack *cb;
1057 register int cbi, first;
1059 cbstuff.DeleteAllCallBacks++;
1060 cbi = first = host->cblist;
1062 ViceLog(8, ("DV: no call backs\n"));
1070 } while (cbi != first);
1076 * Break all delayed call backs for host. Returns 1 if all call backs
1077 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1078 * Must be called with VenusDown set for this host
1081 BreakDelayedCallBacks(struct host *host)
1085 retVal = BreakDelayedCallBacks_r(host);
1091 BreakDelayedCallBacks_r(struct host *host)
1093 struct AFSFid fids[AFSCBMAX];
1094 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1095 int cbi, first, nfids;
1096 struct CallBack *cb;
1099 struct rx_connection *cb_conn;
1101 cbstuff.nbreakers++;
1102 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1103 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1104 cb_conn = host->callback_rxcon;
1105 rx_GetConnection(cb_conn);
1106 if (host->interface) {
1109 RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
1112 code = RXAFSCB_InitCallBackState(cb_conn);
1114 rx_PutConnection(cb_conn);
1117 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1121 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1122 afs_inet_ntoa_r(host->host, hoststr),
1123 ntohs(host->port)));
1125 host->hostFlags |= VENUSDOWN;
1128 ("InitCallBackState success on %s\n",
1129 afs_inet_ntoa_r(host->host, hoststr)));
1130 /* reset was done successfully */
1131 host->hostFlags |= RESETDONE;
1132 host->hostFlags &= ~VENUSDOWN;
1135 while (!(host->hostFlags & HOSTDELETED)) {
1137 host->hostFlags &= ~VENUSDOWN; /* presume up */
1138 cbi = first = host->cblist;
1142 first = host->cblist;
1145 if (cb->status == CB_DELAYED) {
1146 register struct FileEntry *fe = itofe(cb->fhead);
1147 thead[nfids] = cb->thead;
1148 fids[nfids].Volume = fe->volid;
1149 fids[nfids].Vnode = fe->vnode;
1150 fids[nfids].Unique = fe->unique;
1156 } while (cbi && cbi != first && nfids < AFSCBMAX);
1162 if (XCallBackBulk_r(host, fids, nfids)) {
1163 /* Failed, again: put them back, probably with old
1168 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1169 afs_inet_ntoa_r(host->host, hoststr),
1170 ntohs(host->port)));
1172 for (i = 0; i < nfids; i++) {
1175 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1176 afs_inet_ntoa_r(host->host, hoststr),
1177 ntohs(host->port), fids[i].Volume,
1178 fids[i].Vnode, fids[i].Unique));
1181 * AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1182 * * but it turns out to cause too many tricky locking problems.
1183 * * now, if break delayed fails, screw it. */
1185 host->hostFlags |= VENUSDOWN; /* Failed */
1186 ClearHostCallbacks_r(host, 1 /* locked */ );
1190 if (nfids < AFSCBMAX)
1194 cbstuff.nbreakers--;
1195 /* If we succeeded it's always ok to unset HFE_LATER */
1196 if (!host->hostFlags & VENUSDOWN)
1197 host->hostFlags &= ~HFE_LATER;
1198 return (host->hostFlags & VENUSDOWN);
1202 ** isheld is 0 if the host is held in h_Enumerate
1203 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1206 MultiBreakVolumeCallBack_r(struct host *host, int isheld,
1207 struct VCBParams *parms, int deletefe)
1212 return isheld; /* host is held only by h_Enumerate, do nothing */
1213 if (host->hostFlags & HOSTDELETED)
1214 return 0; /* host is deleted, release hold */
1216 if (host->hostFlags & VENUSDOWN) {
1218 if (host->hostFlags & HOSTDELETED) {
1220 return 0; /* Release hold */
1223 ("BVCB: volume call back for host %s:%d failed\n",
1224 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1227 ("CB: volume callback for host %s:%d failed\n",
1228 afs_inet_ntoa_r(host->host, hoststr),
1229 ntohs(host->port)));
1231 DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state
1232 * rather than attempting to
1233 * selectively remember to
1234 * delete the volume callbacks
1236 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1238 return 0; /* release hold */
1240 assert(parms->ncbas <= MAX_CB_HOSTS);
1242 /* Do not call MultiBreakCallBack on the current host structure
1243 ** because it would prematurely release the hold on the host
1245 if (parms->ncbas == MAX_CB_HOSTS) {
1246 struct AFSCBFids tf;
1248 tf.AFSCBFids_len = 1;
1249 tf.AFSCBFids_val = parms->fid;
1251 /* this releases all the hosts */
1252 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */ );
1256 parms->cba[parms->ncbas].hp = host;
1257 parms->cba[(parms->ncbas)++].thead = parms->thead;
1258 return 1; /* DON'T release hold, because we still need it. */
1262 ** isheld is 0 if the host is held in h_Enumerate
1263 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1266 MultiBreakVolumeCallBack(struct host *host, int isheld,
1267 struct VCBParams *parms)
1271 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1277 ** isheld is 0 if the host is held in h_Enumerate
1278 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1281 MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1282 struct VCBParams *parms)
1286 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1292 * Break all call backs on a single volume. Don't call this with any
1293 * hosts h_held. Note that this routine clears the callbacks before
1294 * actually breaking them, and that the vnode isn't locked during this
1295 * operation, so that people might see temporary callback loss while
1296 * this function is executing. It is just a temporary state, however,
1297 * since the callback will be broken later by this same function.
1299 * Now uses multi-RX for CallBack RPC. Note that the
1300 * multiBreakCallBacks routine does not force a reset if the RPC
1301 * fails, unlike the previous version of this routine, but does create
1302 * a delayed callback. Resets will be forced if the host is
1303 * determined to be down before the RPC is executed.
1306 BreakVolumeCallBacks(afs_uint32 volume)
1311 struct CallBack *cb;
1312 struct FileEntry *fe;
1314 struct VCBParams henumParms;
1315 afs_uint32 tthead = 0; /* zero is illegal value */
1318 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1319 for (hash = 0; hash < VHASH; hash++) {
1320 for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
1321 if (fe->volid == volume) {
1322 register struct CallBack *cbnext;
1323 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1324 host = h_itoh(cb->hhead);
1326 cbnext = itocb(cb->cnext);
1327 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1333 /* leave hold for MultiBreakVolumeCallBack to clear */
1344 /* didn't find any callbacks, so return right away. */
1348 henumParms.ncbas = 0;
1349 henumParms.fid = &fid;
1350 henumParms.thead = tthead;
1352 h_Enumerate(MultiBreakVolumeCallBack, (char *)&henumParms);
1354 if (henumParms.ncbas) { /* do left-overs */
1355 struct AFSCBFids tf;
1356 tf.AFSCBFids_len = 1;
1357 tf.AFSCBFids_val = &fid;
1359 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1361 henumParms.ncbas = 0;
1367 #ifdef AFS_PTHREAD_ENV
1368 extern pthread_cond_t fsync_cond;
1370 extern char fsync_wait[];
1374 BreakVolumeCallBacksLater(afs_uint32 volume)
1378 struct FileEntry *fe;
1379 struct CallBack *cb;
1383 ViceLog(25, ("Setting later on volume %u\n", volume));
1385 for (hash = 0; hash < VHASH; hash++) {
1386 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1387 if (fe->volid == volume) {
1388 register struct CallBack *cbnext;
1389 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1390 host = h_itoh(cb->hhead);
1391 host->hostFlags |= HFE_LATER;
1392 cb->status = CB_DELAYED;
1393 cbnext = itocb(cb->cnext);
1396 fe->status |= FE_LATER;
1405 /* didn't find any callbacks, so return right away. */
1409 ViceLog(25, ("Fsync thread wakeup\n"));
1410 #ifdef AFS_PTHREAD_ENV
1412 assert(pthread_cond_broadcast(&fsync_cond) == 0);
1415 LWP_NoYieldSignal(fsync_wait);
1421 BreakLaterCallBacks(void)
1426 struct CallBack *cb;
1427 struct FileEntry *fe = NULL;
1428 struct FileEntry *myfe = NULL;
1430 struct VCBParams henumParms;
1431 unsigned short tthead = 0; /* zero is illegal value */
1435 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1438 /* Pick the first volume we see to clean up */
1439 fid.Volume = fid.Vnode = fid.Unique = 0;
1441 for (hash = 0; hash < VHASH; hash++) {
1442 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1443 if (fe && (fe->status & FE_LATER)
1444 && (fid.Volume == 0 || fid.Volume == fe->volid)) {
1445 /* Ugly, but used to avoid left side casting */
1446 struct object *tmpfe;
1448 ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
1450 fid.Volume = fe->volid;
1452 /* Works since volid is deeper than the largest pointer */
1453 tmpfe = (struct object *)fe;
1454 tmpfe->next = (struct object *)myfe;
1467 /* loop over FEs from myfe and free/break */
1469 for (fe = myfe; fe;) {
1470 register struct CallBack *cbnext;
1471 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1472 cbnext = itocb(cb->cnext);
1473 host = h_itoh(cb->hhead);
1474 if (cb->status == CB_DELAYED) {
1476 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1481 CDel(cb, 0); /* Don't let CDel clean up the fe */
1482 /* leave hold for MultiBreakVolumeCallBack to clear */
1485 ("Found host %s:%d non-DELAYED cb for %u:%u:%u\n",
1486 afs_inet_ntoa_r(host->host, hoststr),
1487 ntohs(host->port), fe->vnode, fe->unique, fe->volid));
1491 fe = (struct FileEntry *)((struct object *)fe)->next;
1496 ViceLog(125, ("Breaking volume %u\n", fid.Volume));
1497 henumParms.ncbas = 0;
1498 henumParms.fid = &fid;
1499 henumParms.thead = tthead;
1501 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *)&henumParms);
1503 if (henumParms.ncbas) { /* do left-overs */
1504 struct AFSCBFids tf;
1505 tf.AFSCBFids_len = 1;
1506 tf.AFSCBFids_val = &fid;
1508 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1509 henumParms.ncbas = 0;
1514 /* Arrange to be called again */
1519 * Delete all timed-out call back entries (to be called periodically by file
1523 CleanupTimedOutCallBacks(void)
1526 CleanupTimedOutCallBacks_r();
1532 CleanupTimedOutCallBacks_r(void)
1534 afs_uint32 now = CBtime(FT_ApproxTime());
1535 register afs_uint32 *thead;
1536 register struct CallBack *cb;
1537 register int ntimedout = 0;
1540 while (tfirst <= now) {
1542 cbi = *(thead = THead(tfirst));
1548 ("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1549 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
1550 h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
1551 itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
1555 if (ntimedout > cbstuff.nblks) {
1556 ViceLog(0, ("CCB: Internal Error -- shutting down...\n"));
1557 DumpCallBackState();
1558 ShutDownAndCore(PANIC);
1560 } while (cbi != *thead);
1565 cbstuff.CBsTimedOut += ntimedout;
1566 ViceLog(7, ("CCB: deleted %d timed out callbacks\n", ntimedout));
1567 return (ntimedout > 0);
1570 static struct host *lih_host;
1571 static int lih_host_held;
1574 lih_r(register struct host *host, register int held,
1575 register struct host *hostp)
1578 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1579 && (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
1580 if (lih_host != NULL && lih_host_held) {
1581 h_Release_r(lih_host);
1584 lih_host_held = !held;
1590 /* This could be upgraded to get more space each time */
1591 /* first pass: find the oldest host which isn't held by anyone */
1592 /* second pass: find the oldest host who isn't "me" */
1593 /* always called with hostp unlocked */
1594 extern struct host *hostList;
1596 GetSomeSpace_r(struct host *hostp, int locked)
1598 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1601 cbstuff.GotSomeSpaces++;
1603 ("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1604 if (CleanupTimedOutCallBacks_r()) {
1610 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1613 /* set in lih_r! private copy before giving up H_LOCK */
1614 int lih_host_held2=lih_host_held;
1616 if (!ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
1629 ("GSS: Try harder for longest inactive host cnt= %d\n",
1632 * Next time try getting callbacks from any host even if
1633 * it's deleted (that's actually great since we can freely
1634 * remove its callbacks) or it's held since the only other
1635 * option is starvation for the file server (i.e. until the
1636 * callback timeout arrives).
1642 * No choice to clear this host's callback state
1644 /* third pass: we still haven't gotten any space, so we free what we had
1645 * previously passed over. */
1650 ClearHostCallbacks_r(hostp, 1 /*already locked */ );
1657 /* locked - set if caller has already locked the host */
1659 ClearHostCallbacks_r(struct host *hp, int locked)
1664 struct rx_connection *cb_conn = NULL;
1667 ("GSS: Delete longest inactive host %s\n",
1668 afs_inet_ntoa_r(hp->host, hoststr)));
1669 if (!(held = h_Held_r(hp)))
1672 /** Try a non-blocking lock. If the lock is already held return
1673 * after releasing hold on hp
1676 if (h_NBLock_r(hp)) {
1682 if (hp->Console & 2) {
1684 * If the special console field is set it means that a thread
1685 * is waiting in AddCallBack1 after it set pointers to the
1686 * file entry and/or callback entry. Because of the bogus
1687 * usage of h_hold it won't prevent from another thread, this
1688 * one, to remove all the callbacks so just to be safe we keep
1689 * a reference. NOTE, on the last phase we'll free the calling
1690 * host's callbacks but that's ok...
1694 DeleteAllCallBacks_r(hp, 1);
1695 if (hp->hostFlags & VENUSDOWN) {
1696 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1698 /* host is up, try a call */
1699 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1700 cb_conn = hp->callback_rxcon;
1701 rx_GetConnection(hp->callback_rxcon);
1702 if (hp->interface) {
1705 RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
1708 code = RXAFSCB_InitCallBackState(cb_conn);
1710 rx_PutConnection(cb_conn);
1713 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1715 /* failed, mark host down and need reset */
1716 hp->hostFlags |= VENUSDOWN;
1717 hp->hostFlags &= ~RESETDONE;
1719 /* reset succeeded, we're done */
1720 hp->hostFlags |= RESETDONE;
1731 #endif /* INTERPRET_DUMP */
1735 PrintCallBackStats(void)
1738 "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1739 cbstuff.AddCallBacks, cbstuff.BreakCallBacks,
1740 cbstuff.DeleteCallBacks, cbstuff.DeleteFiles, cbstuff.CBsTimedOut,
1741 cbstuff.GotSomeSpaces, cbstuff.DeleteAllCallBacks);
1742 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1743 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs + cbstuff.nFEs,
1749 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1751 #ifndef INTERPRET_DUMP
1754 DumpCallBackState(void)
1757 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1759 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY | O_CREAT | O_TRUNC,
1763 ("Couldn't create callback dump file %s\n",
1764 AFSDIR_SERVER_CBKDUMP_FILEPATH));
1767 (void)write(fd, &magic, sizeof(magic));
1768 (void)write(fd, &now, sizeof(now));
1769 (void)write(fd, &cbstuff, sizeof(cbstuff));
1770 (void)write(fd, TimeOuts, sizeof(TimeOuts));
1771 (void)write(fd, timeout, sizeof(timeout));
1772 (void)write(fd, &tfirst, sizeof(tfirst));
1773 freelisthead = cbtoi((struct CallBack *)CBfree);
1774 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1775 freelisthead = fetoi((struct FileEntry *)FEfree);
1776 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1777 (void)write(fd, HashTable, sizeof(HashTable));
1778 (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1779 (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1787 #ifdef INTERPRET_DUMP
1789 /* This is only compiled in for the callback analyzer program */
1790 /* Returns the time of the dump */
1792 ReadDump(char *file)
1795 afs_uint32 magic, freelisthead;
1798 fd = open(file, O_RDONLY);
1800 fprintf(stderr, "Couldn't read dump file %s\n", file);
1803 read(fd, &magic, sizeof(magic));
1804 if (magic != MAGIC) {
1806 "Magic number of %s is invalid. You might be trying to\n",
1809 "run this program on a machine type with a different byte ordering.\n");
1812 read(fd, &now, sizeof(now));
1813 read(fd, &cbstuff, sizeof(cbstuff));
1814 read(fd, TimeOuts, sizeof(TimeOuts));
1815 read(fd, timeout, sizeof(timeout));
1816 read(fd, &tfirst, sizeof(tfirst));
1817 read(fd, &freelisthead, sizeof(freelisthead));
1818 CB = ((struct CallBack
1819 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1820 FE = ((struct FileEntry
1821 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1822 CBfree = (struct CallBack *)itocb(freelisthead);
1823 read(fd, &freelisthead, sizeof(freelisthead));
1824 FEfree = (struct FileEntry *)itofe(freelisthead);
1825 read(fd, HashTable, sizeof(HashTable));
1826 read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1827 read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1829 perror("Error reading dumpfile");
1835 #include "AFS_component_version_number.c"
1838 main(int argc, char **argv)
1840 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1842 register struct FileEntry *fe;
1843 register struct CallBack *cb;
1846 memset(&fid, 0, sizeof(fid));
1849 while (argc && **argv == '-') {
1852 if (!strcmp(*argv, "-host")) {
1858 cbi = atoi(*++argv);
1859 } else if (!strcmp(*argv, "-fid")) {
1865 fid.Volume = atoi(*++argv);
1866 fid.Vnode = atoi(*++argv);
1867 fid.Unique = atoi(*++argv);
1868 } else if (!strcmp(*argv, "-time")) {
1869 fprintf(stderr, "-time not supported\n");
1871 } else if (!strcmp(*argv, "-stats")) {
1873 } else if (!strcmp(*argv, "-all")) {
1875 } else if (!strcmp(*argv, "-raw")) {
1877 } else if (!strcmp(*argv, "-volume")) {
1883 vol = atoi(*++argv);
1888 if (err || argc != 1) {
1890 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
1892 "[cbid is shown for each host in the hosts.dump file]\n");
1895 now = ReadDump(*argv);
1896 if (stats || noptions == 0) {
1897 time_t uxtfirst = UXtime(tfirst);
1898 printf("The time of the dump was %u %s", now, ctime(&now));
1899 printf("The last time cleanup ran was %u %s", uxtfirst,
1901 PrintCallBackStats();
1905 register afs_uint32 *feip;
1906 register struct CallBack *cb;
1907 register struct FileEntry *fe;
1909 for (hash = 0; hash < VHASH; hash++) {
1910 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1911 if (!vol || (fe->volid == vol)) {
1912 register struct CallBack *cbnext;
1913 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1915 cbnext = itocb(cb->cnext);
1925 afs_uint32 cfirst = cbi;
1930 } while (cbi != cfirst);
1935 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1938 cb = itocb(fe->firstcb);
1941 cb = itocb(cb->cnext);
1945 struct FileEntry *fe;
1947 for (i = 1; i < cbstuff.nblks; i++) {
1948 p = (afs_int32 *) & FE[i];
1949 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1955 PrintCB(register struct CallBack *cb, afs_uint32 now)
1957 struct FileEntry *fe = itofe(cb->fhead);
1958 time_t expires = TIndexToTime(cb->thead);
1963 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
1964 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
1965 expires - now, ctime(&expires));
1970 #if !defined(INTERPRET_DUMP)
1972 ** try breaking calbacks on afidp from host. Use multi_rx.
1973 ** return 0 on success, non-zero on failure
1976 MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1980 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1986 MultiBreakCallBackAlternateAddress_r(struct host *host,
1987 struct AFSCBFids *afidp)
1990 struct rx_connection **conns;
1991 struct rx_connection *connSuccess = 0;
1992 struct AddrPort *interfaces;
1993 static struct rx_securityClass *sc = 0;
1994 static struct AFSCBs tc = { 0, 0 };
1997 /* nothing more can be done */
1998 if (!host->interface)
1999 return 1; /* failure */
2001 assert(host->interface->numberOfInterfaces > 0);
2003 /* the only address is the primary interface */
2004 if (host->interface->numberOfInterfaces == 1)
2005 return 1; /* failure */
2007 /* initialise a security object only once */
2009 sc = rxnull_NewClientSecurityObject();
2011 i = host->interface->numberOfInterfaces;
2012 interfaces = calloc(i, sizeof(struct AddrPort));
2013 conns = calloc(i, sizeof(struct rx_connection *));
2014 if (!interfaces || !conns) {
2016 ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
2020 /* initialize alternate rx connections */
2021 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2022 /* this is the current primary address */
2023 if (host->host == host->interface->interface[i].addr &&
2024 host->port == host->interface->interface[i].port)
2027 interfaces[j] = host->interface->interface[i];
2029 rx_NewConnection(interfaces[j].addr,
2030 interfaces[j].port, 1, sc, 0);
2031 rx_SetConnDeadTime(conns[j], 2);
2032 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2036 assert(j); /* at least one alternate address */
2038 ("Starting multibreakcall back on all addr for host %s\n",
2039 afs_inet_ntoa_r(host->host, hoststr)));
2041 multi_Rx(conns, j) {
2042 multi_RXAFSCB_CallBack(afidp, &tc);
2046 if (host->callback_rxcon)
2047 rx_DestroyConnection(host->callback_rxcon);
2048 host->callback_rxcon = conns[multi_i];
2049 host->host = interfaces[multi_i].addr;
2050 host->port = interfaces[multi_i].port;
2051 connSuccess = conns[multi_i];
2052 rx_SetConnDeadTime(host->callback_rxcon, 50);
2053 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2055 ("multibreakcall success with addr %s\n",
2056 afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
2063 /* Destroy all connections except the one on which we succeeded */
2064 for (i = 0; i < j; i++)
2065 if (conns[i] != connSuccess)
2066 rx_DestroyConnection(conns[i]);
2072 return 0; /* success */
2074 return 1; /* failure */
2079 ** try multi_RX probes to host.
2080 ** return 0 on success, non-0 on failure
2083 MultiProbeAlternateAddress_r(struct host *host)
2086 struct rx_connection **conns;
2087 struct rx_connection *connSuccess = 0;
2088 struct AddrPort *interfaces;
2089 static struct rx_securityClass *sc = 0;
2092 /* nothing more can be done */
2093 if (!host->interface)
2094 return 1; /* failure */
2096 assert(host->interface->numberOfInterfaces > 0);
2098 /* the only address is the primary interface */
2099 if (host->interface->numberOfInterfaces == 1)
2100 return 1; /* failure */
2102 /* initialise a security object only once */
2104 sc = rxnull_NewClientSecurityObject();
2106 i = host->interface->numberOfInterfaces;
2107 interfaces = calloc(i, sizeof(struct AddrPort));
2108 conns = calloc(i, sizeof(struct rx_connection *));
2109 if (!interfaces || !conns) {
2110 ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
2114 /* initialize alternate rx connections */
2115 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2116 /* this is the current primary address */
2117 if (host->host == host->interface->interface[i].addr &&
2118 host->port == host->interface->interface[i].port)
2121 interfaces[j] = host->interface->interface[i];
2123 rx_NewConnection(interfaces[i].addr,
2124 interfaces[i].port, 1, sc, 0);
2125 rx_SetConnDeadTime(conns[j], 2);
2126 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2130 assert(j); /* at least one alternate address */
2132 ("Starting multiprobe on all addr for host %s\n",
2133 afs_inet_ntoa_r(host->host, hoststr)));
2135 multi_Rx(conns, j) {
2136 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2140 if (host->callback_rxcon)
2141 rx_DestroyConnection(host->callback_rxcon);
2142 host->callback_rxcon = conns[multi_i];
2143 host->host = interfaces[multi_i].addr;
2144 host->port = interfaces[multi_i].port;
2145 connSuccess = conns[multi_i];
2146 rx_SetConnDeadTime(host->callback_rxcon, 50);
2147 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2149 ("multiprobe success with addr %s\n",
2150 afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
2155 ("multiprobe failure with addr %s\n",
2156 afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
2158 /* This is less than desirable but its the best we can do.
2159 * The AFS Cache Manager will return either 0 for a Uuid
2160 * match and a 1 for a non-match. If the error is 1 we
2161 * therefore know that our mapping of IP address to Uuid
2162 * is wrong. We should attempt to find the correct
2163 * Uuid and fix the host tables.
2165 if (multi_error == 1) {
2166 struct host * newhost;
2168 /* remove the current alternate address from this host */
2170 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2171 if (interfaces[multi_i].addr != host->interface->interface[i].addr &&
2172 interfaces[multi_i].port != host->interface->interface[i].port) {
2173 host->interface->interface[j] = host->interface->interface[i];
2177 host->interface->numberOfInterfaces--;
2184 /* Destroy all connections except the one on which we succeeded */
2185 for (i = 0; i < j; i++)
2186 if (conns[i] != connSuccess)
2187 rx_DestroyConnection(conns[i]);
2193 return 0; /* success */
2195 return 1; /* failure */
2198 #endif /* !defined(INTERPRET_DUMP) */