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 };
781 int multi_to_cba_map[MAX_CB_HOSTS];
783 assert(ncbas <= MAX_CB_HOSTS);
785 /* set up conns for multi-call */
786 for (i = 0, j = 0; i < ncbas; i++) {
787 struct host *thishost = cba[i].hp;
788 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
791 rx_GetConnection(thishost->callback_rxcon);
792 multi_to_cba_map[j] = i;
793 conns[j++] = thishost->callback_rxcon;
796 rx_SetConnDeadTime(thishost->callback_rxcon, 4);
797 rx_SetConnHardDeadTime(thishost->callback_rxcon, AFS_HARDDEADTIME);
801 if (j) { /* who knows what multi would do with 0 conns? */
805 multi_RXAFSCB_CallBack(afidp, &tc);
811 i = multi_to_cba_map[multi_i];
817 ("BCB: INTERNAL ERROR: hp=%x, cba=%x, thead=%u\n",
821 ** try breaking callbacks on alternate interface addresses
823 if (MultiBreakCallBackAlternateAddress(hp, afidp)) {
826 ("BCB: Failed on file %u.%u.%u, host %s:%d is down\n",
827 afidp->AFSCBFids_val->Volume,
828 afidp->AFSCBFids_val->Vnode,
829 afidp->AFSCBFids_val->Unique,
830 afs_inet_ntoa_r(hp->host, hoststr),
836 hp->hostFlags |= VENUSDOWN;
838 * We always go into AddCallBack1_r with the host locked
840 AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
853 for (i = 0; i < ncbas; i++) {
856 if (hp && xhost != hp) {
861 /* H_UNLOCK around this so h_FreeConnection does not deadlock.
862 h_FreeConnection should *never* be called on a callback connection,
863 but on 10/27/04 a deadlock occurred where it was, when we know why,
864 this should be reverted. -- shadow */
866 for (i = 0; i < j; i++) {
867 rx_PutConnection(conns[i]);
875 * Break all call backs for fid, except for the specified host (unless flag
876 * is true, in which case all get a callback message. Assumption: the specified
877 * host is h_Held, by the caller; the others aren't.
878 * Specified host may be bogus, that's ok. This used to check to see if the
879 * host was down in two places, once right after the host was h_held, and
880 * again after it was locked. That race condition is incredibly rare and
881 * relatively harmless even when it does occur, so we don't check for it now.
883 /* if flag is true, send a break callback msg to "host", too */
885 BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
887 struct FileEntry *fe;
888 struct CallBack *cb, *nextcb;
889 struct cbstruct cba[MAX_CB_HOSTS];
896 ("BCB: BreakCallBack(all but %s:%d, (%u,%u,%u))\n",
897 afs_inet_ntoa_r(xhost->host, hoststr), ntohs(xhost->port),
898 fid->Volume, fid->Vnode, fid->Unique));
901 cbstuff.BreakCallBacks++;
906 hostindex = h_htoi(xhost);
907 cb = itocb(fe->firstcb);
908 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
909 /* the most common case is what follows the || */
912 tf.AFSCBFids_len = 1;
913 tf.AFSCBFids_val = fid;
916 for (ncbas = 0; cb && ncbas < MAX_CB_HOSTS; cb = nextcb) {
917 nextcb = itocb(cb->cnext);
918 if ((cb->hhead != hostindex || flag)
919 && (cb->status == CB_BULK || cb->status == CB_NORMAL
920 || cb->status == CB_VOLUME)) {
921 struct host *thishost = h_itoh(cb->hhead);
923 ViceLog(0, ("BCB: BOGUS! cb->hhead is NULL!\n"));
924 } else if (thishost->hostFlags & VENUSDOWN) {
926 ("BCB: %s:%d is down; delaying break call back\n",
927 afs_inet_ntoa_r(thishost->host, hoststr),
928 ntohs(thishost->port)));
929 cb->status = CB_DELAYED;
932 cba[ncbas].hp = thishost;
933 cba[ncbas].thead = cb->thead;
937 CDel(cb, 1); /* Usually first; so this delete
938 * is reasonably inexpensive */
944 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
946 /* we need to to all these initializations again because MultiBreakCallBack may block */
951 cb = itocb(fe->firstcb);
952 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
953 /* the most common case is what follows the || */
964 /* Delete (do not break) single call back for fid */
966 DeleteCallBack(struct host *host, AFSFid * fid)
968 register struct FileEntry *fe;
969 register afs_uint32 *pcb;
972 cbstuff.DeleteCallBacks++;
981 ("DCB: No call backs for fid (%u, %u, %u)\n", fid->Volume,
982 fid->Vnode, fid->Unique));
985 pcb = FindCBPtr(fe, host);
988 ("DCB: No call back for host %s:%d, (%u, %u, %u)\n",
989 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port),
990 fid->Volume, fid->Vnode, fid->Unique));
1004 * Delete (do not break) all call backs for fid. This call doesn't
1005 * set all of the various host locks, but it shouldn't really matter
1006 * since we're not adding callbacks, but deleting them. I'm not sure
1007 * why it doesn't set the lock, however; perhaps it should.
1010 DeleteFileCallBacks(AFSFid * fid)
1012 register struct FileEntry *fe;
1013 register struct CallBack *cb;
1014 register afs_uint32 cbi;
1018 cbstuff.DeleteFiles++;
1023 ("DF: No fid (%u,%u,%u) to delete\n", fid->Volume, fid->Vnode,
1027 for (n = 0, cbi = fe->firstcb; cbi; n++) {
1039 /* Delete (do not break) all call backs for host. The host should be
1042 DeleteAllCallBacks_r(struct host *host, int deletefe)
1044 register struct CallBack *cb;
1045 register int cbi, first;
1047 cbstuff.DeleteAllCallBacks++;
1048 cbi = first = host->cblist;
1050 ViceLog(8, ("DV: no call backs\n"));
1058 } while (cbi != first);
1064 * Break all delayed call backs for host. Returns 1 if all call backs
1065 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1066 * Must be called with VenusDown set for this host
1069 BreakDelayedCallBacks(struct host *host)
1073 retVal = BreakDelayedCallBacks_r(host);
1079 BreakDelayedCallBacks_r(struct host *host)
1081 struct AFSFid fids[AFSCBMAX];
1082 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1083 int cbi, first, nfids;
1084 struct CallBack *cb;
1087 struct rx_connection *cb_conn;
1089 cbstuff.nbreakers++;
1090 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1091 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1092 cb_conn = host->callback_rxcon;
1093 rx_GetConnection(cb_conn);
1094 if (host->interface) {
1097 RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
1100 code = RXAFSCB_InitCallBackState(cb_conn);
1102 rx_PutConnection(cb_conn);
1105 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1109 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1110 afs_inet_ntoa_r(host->host, hoststr),
1111 ntohs(host->port)));
1113 host->hostFlags |= VENUSDOWN;
1116 ("InitCallBackState success on %s\n",
1117 afs_inet_ntoa_r(host->host, hoststr)));
1118 /* reset was done successfully */
1119 host->hostFlags |= RESETDONE;
1120 host->hostFlags &= ~VENUSDOWN;
1123 while (!(host->hostFlags & HOSTDELETED)) {
1125 host->hostFlags &= ~VENUSDOWN; /* presume up */
1126 cbi = first = host->cblist;
1130 first = host->cblist;
1133 if (cb->status == CB_DELAYED) {
1134 register struct FileEntry *fe = itofe(cb->fhead);
1135 thead[nfids] = cb->thead;
1136 fids[nfids].Volume = fe->volid;
1137 fids[nfids].Vnode = fe->vnode;
1138 fids[nfids].Unique = fe->unique;
1144 } while (cbi && cbi != first && nfids < AFSCBMAX);
1150 if (XCallBackBulk_r(host, fids, nfids)) {
1151 /* Failed, again: put them back, probably with old
1156 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1157 afs_inet_ntoa_r(host->host, hoststr),
1158 ntohs(host->port)));
1160 for (i = 0; i < nfids; i++) {
1163 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1164 afs_inet_ntoa_r(host->host, hoststr),
1165 ntohs(host->port), fids[i].Volume,
1166 fids[i].Vnode, fids[i].Unique));
1169 * AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1170 * * but it turns out to cause too many tricky locking problems.
1171 * * now, if break delayed fails, screw it. */
1173 host->hostFlags |= VENUSDOWN; /* Failed */
1174 ClearHostCallbacks_r(host, 1 /* locked */ );
1178 if (nfids < AFSCBMAX)
1182 cbstuff.nbreakers--;
1183 /* If we succeeded it's always ok to unset HFE_LATER */
1184 if (!host->hostFlags & VENUSDOWN)
1185 host->hostFlags &= ~HFE_LATER;
1186 return (host->hostFlags & VENUSDOWN);
1190 ** isheld is 0 if the host is held in h_Enumerate
1191 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1194 MultiBreakVolumeCallBack_r(struct host *host, int isheld,
1195 struct VCBParams *parms, int deletefe)
1200 return isheld; /* host is held only by h_Enumerate, do nothing */
1201 if (host->hostFlags & HOSTDELETED)
1202 return 0; /* host is deleted, release hold */
1204 if (host->hostFlags & VENUSDOWN) {
1206 if (host->hostFlags & HOSTDELETED) {
1208 return 0; /* Release hold */
1211 ("BVCB: volume call back for host %s:%d failed\n",
1212 afs_inet_ntoa_r(host->host, hoststr), ntohs(host->port)));
1215 ("CB: volume callback for host %s:%d failed\n",
1216 afs_inet_ntoa_r(host->host, hoststr),
1217 ntohs(host->port)));
1219 DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state
1220 * rather than attempting to
1221 * selectively remember to
1222 * delete the volume callbacks
1224 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1226 return 0; /* release hold */
1228 assert(parms->ncbas <= MAX_CB_HOSTS);
1230 /* Do not call MultiBreakCallBack on the current host structure
1231 ** because it would prematurely release the hold on the host
1233 if (parms->ncbas == MAX_CB_HOSTS) {
1234 struct AFSCBFids tf;
1236 tf.AFSCBFids_len = 1;
1237 tf.AFSCBFids_val = parms->fid;
1239 /* this releases all the hosts */
1240 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */ );
1244 parms->cba[parms->ncbas].hp = host;
1245 parms->cba[(parms->ncbas)++].thead = parms->thead;
1246 return 1; /* DON'T release hold, because we still need it. */
1250 ** isheld is 0 if the host is held in h_Enumerate
1251 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1254 MultiBreakVolumeCallBack(struct host *host, int isheld,
1255 struct VCBParams *parms)
1259 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
1265 ** isheld is 0 if the host is held in h_Enumerate
1266 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1269 MultiBreakVolumeLaterCallBack(struct host *host, int isheld,
1270 struct VCBParams *parms)
1274 retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
1280 * Break all call backs on a single volume. Don't call this with any
1281 * hosts h_held. Note that this routine clears the callbacks before
1282 * actually breaking them, and that the vnode isn't locked during this
1283 * operation, so that people might see temporary callback loss while
1284 * this function is executing. It is just a temporary state, however,
1285 * since the callback will be broken later by this same function.
1287 * Now uses multi-RX for CallBack RPC. Note that the
1288 * multiBreakCallBacks routine does not force a reset if the RPC
1289 * fails, unlike the previous version of this routine, but does create
1290 * a delayed callback. Resets will be forced if the host is
1291 * determined to be down before the RPC is executed.
1294 BreakVolumeCallBacks(afs_uint32 volume)
1299 struct CallBack *cb;
1300 struct FileEntry *fe;
1302 struct VCBParams henumParms;
1303 afs_uint32 tthead = 0; /* zero is illegal value */
1306 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1307 for (hash = 0; hash < VHASH; hash++) {
1308 for (feip = &HashTable[hash]; (fe = itofe(*feip));) {
1309 if (fe->volid == volume) {
1310 register struct CallBack *cbnext;
1311 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1312 host = h_itoh(cb->hhead);
1314 cbnext = itocb(cb->cnext);
1315 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1321 /* leave hold for MultiBreakVolumeCallBack to clear */
1332 /* didn't find any callbacks, so return right away. */
1336 henumParms.ncbas = 0;
1337 henumParms.fid = &fid;
1338 henumParms.thead = tthead;
1340 h_Enumerate(MultiBreakVolumeCallBack, (char *)&henumParms);
1342 if (henumParms.ncbas) { /* do left-overs */
1343 struct AFSCBFids tf;
1344 tf.AFSCBFids_len = 1;
1345 tf.AFSCBFids_val = &fid;
1347 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1349 henumParms.ncbas = 0;
1355 #ifdef AFS_PTHREAD_ENV
1356 extern pthread_cond_t fsync_cond;
1358 extern char fsync_wait[];
1362 BreakVolumeCallBacksLater(afs_uint32 volume)
1366 struct FileEntry *fe;
1367 struct CallBack *cb;
1371 ViceLog(25, ("Setting later on volume %u\n", volume));
1373 for (hash = 0; hash < VHASH; hash++) {
1374 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1375 if (fe->volid == volume) {
1376 register struct CallBack *cbnext;
1377 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1378 host = h_itoh(cb->hhead);
1379 host->hostFlags |= HFE_LATER;
1380 cb->status = CB_DELAYED;
1381 cbnext = itocb(cb->cnext);
1384 fe->status |= FE_LATER;
1393 /* didn't find any callbacks, so return right away. */
1397 ViceLog(25, ("Fsync thread wakeup\n"));
1398 #ifdef AFS_PTHREAD_ENV
1400 assert(pthread_cond_broadcast(&fsync_cond) == 0);
1403 LWP_NoYieldSignal(fsync_wait);
1409 BreakLaterCallBacks(void)
1414 struct CallBack *cb;
1415 struct FileEntry *fe = NULL;
1416 struct FileEntry *myfe = NULL;
1418 struct VCBParams henumParms;
1419 unsigned short tthead = 0; /* zero is illegal value */
1423 ViceLog(25, ("Looking for FileEntries to unchain\n"));
1426 /* Pick the first volume we see to clean up */
1427 fid.Volume = fid.Vnode = fid.Unique = 0;
1429 for (hash = 0; hash < VHASH; hash++) {
1430 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1431 if (fe && (fe->status & FE_LATER)
1432 && (fid.Volume == 0 || fid.Volume == fe->volid)) {
1433 /* Ugly, but used to avoid left side casting */
1434 struct object *tmpfe;
1436 ("Unchaining for %u:%u:%u\n", fe->vnode, fe->unique,
1438 fid.Volume = fe->volid;
1440 /* Works since volid is deeper than the largest pointer */
1441 tmpfe = (struct object *)fe;
1442 tmpfe->next = (struct object *)myfe;
1455 /* loop over FEs from myfe and free/break */
1457 for (fe = myfe; fe;) {
1458 register struct CallBack *cbnext;
1459 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1460 cbnext = itocb(cb->cnext);
1461 host = h_itoh(cb->hhead);
1462 if (cb->status == CB_DELAYED) {
1464 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1469 CDel(cb, 0); /* Don't let CDel clean up the fe */
1470 /* leave hold for MultiBreakVolumeCallBack to clear */
1473 ("Found host %s:%d non-DELAYED cb for %u:%u:%u\n",
1474 afs_inet_ntoa_r(host->host, hoststr),
1475 ntohs(host->port), fe->vnode, fe->unique, fe->volid));
1479 fe = (struct FileEntry *)((struct object *)fe)->next;
1484 ViceLog(125, ("Breaking volume %u\n", fid.Volume));
1485 henumParms.ncbas = 0;
1486 henumParms.fid = &fid;
1487 henumParms.thead = tthead;
1489 h_Enumerate(MultiBreakVolumeLaterCallBack, (char *)&henumParms);
1491 if (henumParms.ncbas) { /* do left-overs */
1492 struct AFSCBFids tf;
1493 tf.AFSCBFids_len = 1;
1494 tf.AFSCBFids_val = &fid;
1496 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0);
1497 henumParms.ncbas = 0;
1502 /* Arrange to be called again */
1507 * Delete all timed-out call back entries (to be called periodically by file
1511 CleanupTimedOutCallBacks(void)
1514 CleanupTimedOutCallBacks_r();
1520 CleanupTimedOutCallBacks_r(void)
1522 afs_uint32 now = CBtime(FT_ApproxTime());
1523 register afs_uint32 *thead;
1524 register struct CallBack *cb;
1525 register int ntimedout = 0;
1528 while (tfirst <= now) {
1530 cbi = *(thead = THead(tfirst));
1536 ("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1537 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr),
1538 h_itoh(cb->hhead)->port, itofe(cb->fhead)->volid,
1539 itofe(cb->fhead)->vnode, itofe(cb->fhead)->unique));
1543 if (ntimedout > cbstuff.nblks) {
1544 ViceLog(0, ("CCB: Internal Error -- shutting down...\n"));
1545 DumpCallBackState();
1546 ShutDownAndCore(PANIC);
1548 } while (cbi != *thead);
1553 cbstuff.CBsTimedOut += ntimedout;
1554 ViceLog(7, ("CCB: deleted %d timed out callbacks\n", ntimedout));
1555 return (ntimedout > 0);
1558 static struct host *lih_host;
1559 static int lih_host_held;
1562 lih_r(register struct host *host, register int held,
1563 register struct host *hostp)
1566 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1567 && (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
1568 if (lih_host != NULL && lih_host_held) {
1569 h_Release_r(lih_host);
1572 lih_host_held = !held;
1578 /* This version does not allow 'host' to be selected unless its ActiveCall
1579 * is newer than 'hostp' which is the host with the oldest ActiveCall from
1580 * the last pass (if it is provided). We filter out any hosts that are
1581 * are held by other threads.
1584 lih0_r(register struct host *host, register int held,
1585 register struct host *hostp)
1588 && (hostp && host != hostp)
1589 && (!held && !h_OtherHolds_r(host))
1590 && (!lih_host || host->ActiveCall < lih_host->ActiveCall)
1591 && (!hostp || host->ActiveCall > hostp->ActiveCall)) {
1592 if (lih_host != NULL && lih_host_held) {
1593 h_Release_r(lih_host);
1596 lih_host_held = !held;
1602 /* This version does not allow 'host' to be selected unless its ActiveCall
1603 * is newer than 'hostp' which is the host with the oldest ActiveCall from
1604 * the last pass (if it is provided). In this second varient, we do not
1605 * prevent held hosts from being selected.
1608 lih1_r(register struct host *host, register int held,
1609 register struct host *hostp)
1612 && (hostp && host != hostp)
1613 && (!lih_host || host->ActiveCall < lih_host->ActiveCall)
1614 && (!hostp || host->ActiveCall > hostp->ActiveCall)) {
1615 if (lih_host != NULL && lih_host_held) {
1616 h_Release_r(lih_host);
1619 lih_host_held = !held;
1625 /* This could be upgraded to get more space each time */
1626 /* first pass: sequentially find the oldest host which isn't held by
1627 anyone for which we can clear callbacks;
1629 /* second pass: sequentially find the oldest host regardless of
1630 whether or not the host is held; skipping 'hostp' */
1631 /* third pass: attempt to clear callbacks from 'hostp' */
1632 /* always called with hostp unlocked */
1634 /* Note: hostlist is ordered most recently created host first and
1635 * its order has no relationship to the most recently used. */
1636 extern struct host *hostList;
1638 GetSomeSpace_r(struct host *hostp, int locked)
1640 register struct host *hp, *hp1, *hp2;
1643 cbstuff.GotSomeSpaces++;
1645 ("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1646 if (CleanupTimedOutCallBacks_r()) {
1656 h_Enumerate_r(i == 0 ? lih0_r : lih1_r, hp2, (char *)hp1);
1659 /* set in lih_r! private copy before giving up H_LOCK */
1660 int lih_host_held2=lih_host_held;
1662 if ((hp != hostp) && !ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
1673 * Next time try getting callbacks from any host even if
1674 * it's deleted (that's actually great since we can freely
1675 * remove its callbacks) or it's held since the only other
1676 * option is starvation for the file server (i.e. until the
1677 * callback timeout arrives).
1684 ("GSS: Try harder for longest inactive host cnt= %d\n",
1689 /* Could not obtain space from other hosts, clear hostp's callback state */
1694 ClearHostCallbacks_r(hostp, 1 /*already locked */ );
1701 /* locked - set if caller has already locked the host */
1703 ClearHostCallbacks_r(struct host *hp, int locked)
1708 struct rx_connection *cb_conn = NULL;
1711 ("GSS: Delete longest inactive host %s\n",
1712 afs_inet_ntoa_r(hp->host, hoststr)));
1713 if (!(held = h_Held_r(hp)))
1716 /** Try a non-blocking lock. If the lock is already held return
1717 * after releasing hold on hp
1720 if (h_NBLock_r(hp)) {
1726 if (hp->Console & 2) {
1728 * If the special console field is set it means that a thread
1729 * is waiting in AddCallBack1 after it set pointers to the
1730 * file entry and/or callback entry. Because of the bogus
1731 * usage of h_hold it won't prevent from another thread, this
1732 * one, to remove all the callbacks so just to be safe we keep
1733 * a reference. NOTE, on the last phase we'll free the calling
1734 * host's callbacks but that's ok...
1738 DeleteAllCallBacks_r(hp, 1);
1739 if (hp->hostFlags & VENUSDOWN) {
1740 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1742 /* host is up, try a call */
1743 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1744 cb_conn = hp->callback_rxcon;
1745 rx_GetConnection(hp->callback_rxcon);
1746 if (hp->interface) {
1749 RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
1752 code = RXAFSCB_InitCallBackState(cb_conn);
1754 rx_PutConnection(cb_conn);
1757 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1759 /* failed, mark host down and need reset */
1760 hp->hostFlags |= VENUSDOWN;
1761 hp->hostFlags &= ~RESETDONE;
1763 /* reset succeeded, we're done */
1764 hp->hostFlags |= RESETDONE;
1775 #endif /* INTERPRET_DUMP */
1779 PrintCallBackStats(void)
1782 "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1783 cbstuff.AddCallBacks, cbstuff.BreakCallBacks,
1784 cbstuff.DeleteCallBacks, cbstuff.DeleteFiles, cbstuff.CBsTimedOut,
1785 cbstuff.GotSomeSpaces, cbstuff.DeleteAllCallBacks);
1786 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1787 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs + cbstuff.nFEs,
1793 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1795 #ifndef INTERPRET_DUMP
1798 DumpCallBackState(void)
1801 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1803 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY | O_CREAT | O_TRUNC,
1807 ("Couldn't create callback dump file %s\n",
1808 AFSDIR_SERVER_CBKDUMP_FILEPATH));
1811 (void)write(fd, &magic, sizeof(magic));
1812 (void)write(fd, &now, sizeof(now));
1813 (void)write(fd, &cbstuff, sizeof(cbstuff));
1814 (void)write(fd, TimeOuts, sizeof(TimeOuts));
1815 (void)write(fd, timeout, sizeof(timeout));
1816 (void)write(fd, &tfirst, sizeof(tfirst));
1817 freelisthead = cbtoi((struct CallBack *)CBfree);
1818 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1819 freelisthead = fetoi((struct FileEntry *)FEfree);
1820 (void)write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1821 (void)write(fd, HashTable, sizeof(HashTable));
1822 (void)write(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1823 (void)write(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1831 #ifdef INTERPRET_DUMP
1833 /* This is only compiled in for the callback analyzer program */
1834 /* Returns the time of the dump */
1836 ReadDump(char *file)
1839 afs_uint32 magic, freelisthead;
1842 fd = open(file, O_RDONLY);
1844 fprintf(stderr, "Couldn't read dump file %s\n", file);
1847 read(fd, &magic, sizeof(magic));
1848 if (magic != MAGIC) {
1850 "Magic number of %s is invalid. You might be trying to\n",
1853 "run this program on a machine type with a different byte ordering.\n");
1856 read(fd, &now, sizeof(now));
1857 read(fd, &cbstuff, sizeof(cbstuff));
1858 read(fd, TimeOuts, sizeof(TimeOuts));
1859 read(fd, timeout, sizeof(timeout));
1860 read(fd, &tfirst, sizeof(tfirst));
1861 read(fd, &freelisthead, sizeof(freelisthead));
1862 CB = ((struct CallBack
1863 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1864 FE = ((struct FileEntry
1865 *)(calloc(cbstuff.nblks, sizeof(struct FileEntry)))) - 1;
1866 CBfree = (struct CallBack *)itocb(freelisthead);
1867 read(fd, &freelisthead, sizeof(freelisthead));
1868 FEfree = (struct FileEntry *)itofe(freelisthead);
1869 read(fd, HashTable, sizeof(HashTable));
1870 read(fd, &CB[1], sizeof(CB[1]) * cbstuff.nblks); /* CB stuff */
1871 read(fd, &FE[1], sizeof(FE[1]) * cbstuff.nblks); /* FE stuff */
1873 perror("Error reading dumpfile");
1879 #include "AFS_component_version_number.c"
1882 main(int argc, char **argv)
1884 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1886 register struct FileEntry *fe;
1887 register struct CallBack *cb;
1890 memset(&fid, 0, sizeof(fid));
1893 while (argc && **argv == '-') {
1896 if (!strcmp(*argv, "-host")) {
1902 cbi = atoi(*++argv);
1903 } else if (!strcmp(*argv, "-fid")) {
1909 fid.Volume = atoi(*++argv);
1910 fid.Vnode = atoi(*++argv);
1911 fid.Unique = atoi(*++argv);
1912 } else if (!strcmp(*argv, "-time")) {
1913 fprintf(stderr, "-time not supported\n");
1915 } else if (!strcmp(*argv, "-stats")) {
1917 } else if (!strcmp(*argv, "-all")) {
1919 } else if (!strcmp(*argv, "-raw")) {
1921 } else if (!strcmp(*argv, "-volume")) {
1927 vol = atoi(*++argv);
1932 if (err || argc != 1) {
1934 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
1936 "[cbid is shown for each host in the hosts.dump file]\n");
1939 now = ReadDump(*argv);
1940 if (stats || noptions == 0) {
1941 time_t uxtfirst = UXtime(tfirst);
1942 printf("The time of the dump was %u %s", now, ctime(&now));
1943 printf("The last time cleanup ran was %u %s", uxtfirst,
1945 PrintCallBackStats();
1949 register afs_uint32 *feip;
1950 register struct CallBack *cb;
1951 register struct FileEntry *fe;
1953 for (hash = 0; hash < VHASH; hash++) {
1954 for (feip = &HashTable[hash]; fe = itofe(*feip);) {
1955 if (!vol || (fe->volid == vol)) {
1956 register struct CallBack *cbnext;
1957 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1959 cbnext = itocb(cb->cnext);
1969 afs_uint32 cfirst = cbi;
1974 } while (cbi != cfirst);
1979 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1982 cb = itocb(fe->firstcb);
1985 cb = itocb(cb->cnext);
1989 struct FileEntry *fe;
1991 for (i = 1; i < cbstuff.nblks; i++) {
1992 p = (afs_int32 *) & FE[i];
1993 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1999 PrintCB(register struct CallBack *cb, afs_uint32 now)
2001 struct FileEntry *fe = itofe(cb->fhead);
2002 time_t expires = TIndexToTime(cb->thead);
2007 printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s",
2008 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status, fe->status,
2009 expires - now, ctime(&expires));
2014 #if !defined(INTERPRET_DUMP)
2016 ** try breaking calbacks on afidp from host. Use multi_rx.
2017 ** return 0 on success, non-zero on failure
2020 MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
2024 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
2030 MultiBreakCallBackAlternateAddress_r(struct host *host,
2031 struct AFSCBFids *afidp)
2034 struct rx_connection **conns;
2035 struct rx_connection *connSuccess = 0;
2036 struct AddrPort *interfaces;
2037 static struct rx_securityClass *sc = 0;
2038 static struct AFSCBs tc = { 0, 0 };
2041 /* nothing more can be done */
2042 if (!host->interface)
2043 return 1; /* failure */
2045 assert(host->interface->numberOfInterfaces > 0);
2047 /* the only address is the primary interface */
2048 if (host->interface->numberOfInterfaces == 1)
2049 return 1; /* failure */
2051 /* initialise a security object only once */
2053 sc = rxnull_NewClientSecurityObject();
2055 i = host->interface->numberOfInterfaces;
2056 interfaces = calloc(i, sizeof(struct AddrPort));
2057 conns = calloc(i, sizeof(struct rx_connection *));
2058 if (!interfaces || !conns) {
2060 ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
2064 /* initialize alternate rx connections */
2065 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2066 /* this is the current primary address */
2067 if (host->host == host->interface->interface[i].addr &&
2068 host->port == host->interface->interface[i].port)
2071 interfaces[j] = host->interface->interface[i];
2073 rx_NewConnection(interfaces[j].addr,
2074 interfaces[j].port, 1, sc, 0);
2075 rx_SetConnDeadTime(conns[j], 2);
2076 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2080 assert(j); /* at least one alternate address */
2082 ("Starting multibreakcall back on all addr for host %s\n",
2083 afs_inet_ntoa_r(host->host, hoststr)));
2085 multi_Rx(conns, j) {
2086 multi_RXAFSCB_CallBack(afidp, &tc);
2090 if (host->callback_rxcon)
2091 rx_DestroyConnection(host->callback_rxcon);
2092 host->callback_rxcon = conns[multi_i];
2093 host->host = interfaces[multi_i].addr;
2094 host->port = interfaces[multi_i].port;
2095 connSuccess = conns[multi_i];
2096 rx_SetConnDeadTime(host->callback_rxcon, 50);
2097 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2099 ("multibreakcall success with addr %s\n",
2100 afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
2107 /* Destroy all connections except the one on which we succeeded */
2108 for (i = 0; i < j; i++)
2109 if (conns[i] != connSuccess)
2110 rx_DestroyConnection(conns[i]);
2116 return 0; /* success */
2118 return 1; /* failure */
2123 ** try multi_RX probes to host.
2124 ** return 0 on success, non-0 on failure
2127 MultiProbeAlternateAddress_r(struct host *host)
2130 struct rx_connection **conns;
2131 struct rx_connection *connSuccess = 0;
2132 struct AddrPort *interfaces;
2133 static struct rx_securityClass *sc = 0;
2136 /* nothing more can be done */
2137 if (!host->interface)
2138 return 1; /* failure */
2140 assert(host->interface->numberOfInterfaces > 0);
2142 /* the only address is the primary interface */
2143 if (host->interface->numberOfInterfaces == 1)
2144 return 1; /* failure */
2146 /* initialise a security object only once */
2148 sc = rxnull_NewClientSecurityObject();
2150 i = host->interface->numberOfInterfaces;
2151 interfaces = calloc(i, sizeof(struct AddrPort));
2152 conns = calloc(i, sizeof(struct rx_connection *));
2153 if (!interfaces || !conns) {
2154 ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
2158 /* initialize alternate rx connections */
2159 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2160 /* this is the current primary address */
2161 if (host->host == host->interface->interface[i].addr &&
2162 host->port == host->interface->interface[i].port)
2165 interfaces[j] = host->interface->interface[i];
2167 rx_NewConnection(interfaces[i].addr,
2168 interfaces[i].port, 1, sc, 0);
2169 rx_SetConnDeadTime(conns[j], 2);
2170 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
2174 assert(j); /* at least one alternate address */
2176 ("Starting multiprobe on all addr for host %s\n",
2177 afs_inet_ntoa_r(host->host, hoststr)));
2179 multi_Rx(conns, j) {
2180 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
2184 if (host->callback_rxcon)
2185 rx_DestroyConnection(host->callback_rxcon);
2186 host->callback_rxcon = conns[multi_i];
2187 host->host = interfaces[multi_i].addr;
2188 host->port = interfaces[multi_i].port;
2189 connSuccess = conns[multi_i];
2190 rx_SetConnDeadTime(host->callback_rxcon, 50);
2191 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
2193 ("multiprobe success with addr %s\n",
2194 afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
2199 ("multiprobe failure with addr %s\n",
2200 afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
2202 /* This is less than desirable but its the best we can do.
2203 * The AFS Cache Manager will return either 0 for a Uuid
2204 * match and a 1 for a non-match. If the error is 1 we
2205 * therefore know that our mapping of IP address to Uuid
2206 * is wrong. We should attempt to find the correct
2207 * Uuid and fix the host tables.
2209 if (multi_error == 1) {
2210 struct host * newhost;
2212 /* remove the current alternate address from this host */
2214 for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
2215 if (interfaces[multi_i].addr != host->interface->interface[i].addr &&
2216 interfaces[multi_i].port != host->interface->interface[i].port) {
2217 host->interface->interface[j] = host->interface->interface[i];
2221 host->interface->numberOfInterfaces--;
2228 /* Destroy all connections except the one on which we succeeded */
2229 for (i = 0; i < j; i++)
2230 if (conns[i] != connSuccess)
2231 rx_DestroyConnection(conns[i]);
2237 return 0; /* success */
2239 return 1; /* failure */
2242 #endif /* !defined(INTERPRET_DUMP) */