2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * NEW callback package callback.c (replaces vicecb.c)
12 * Updated call back routines, NOW with:
14 * Faster DeleteVenus (Now called DeleteAllCallBacks)
15 * Call back breaking for volumes
16 * Adaptive timeouts on call backs
17 * Architected for Multi RPC
18 * No locks (currently implicit vnode locks--these will go, to)
19 * Delayed call back when rpc connection down.
20 * Bulk break of delayed call backs when rpc connection
22 * Strict limit on number of call backs.
24 * InitCallBack(nblocks)
25 * Initialize: nblocks is max number # of file entries + # of callback entries
26 * nblocks must be < 65536
27 * Space used is nblocks*16 bytes
28 * Note that space will be reclaimed by breaking callbacks of old hosts
30 * time = AddCallBack(host, fid)
32 * Returns the expiration time at the workstation.
34 * BreakCallBack(host, fid)
35 * Break all call backs for fid, except for the specified host.
38 * BreakVolumeCallBacks(volume)
39 * Break all call backs on volume, using single call to each host
40 * Delete all the call backs.
42 * DeleteCallBack(host,fid)
43 * Delete (do not break) single call back for fid.
45 * DeleteFileCallBacks(fid)
46 * Delete (do not break) all call backs for fid.
48 * DeleteAllCallBacks(host)
49 * Delete (do not break) all call backs for host.
51 * CleanupTimedOutCallBacks()
52 * Delete all timed out call back entries
53 * Must be called periodically by file server.
55 * BreakDelayedCallBacks(host)
56 * Break all delayed call backs for host.
57 * Returns 1: one or more failed, 0: success.
59 * PrintCallBackStats()
60 * Print statistics about call backs to stdout.
62 * DumpCallBacks() ---wishful thinking---
63 * Dump call back state to /tmp/callback.state.
64 * This is separately interpretable by the program pcb.
66 * Notes: In general, if a call back to a host doesn't get through,
67 * then HostDown, supplied elsewhere, is called. BreakDelayedCallBacks,
68 * however, does not call HostDown, but instead returns an indication of
69 * success if all delayed call backs were finally broken.
71 * BreakDelayedCallBacks MUST be called at the first sign of activity
72 * from the host after HostDown has been called (or a previous
73 * BreakDelayedCallBacks failed). The BreakDelayedCallBacks must be
74 * allowed to complete before any requests from that host are handled.
75 * If BreakDelayedCallBacks fails, then the host should remain
76 * down (and the request should be failed).
78 * CleanupCallBacks MUST be called periodically by the file server for
79 * this package to work correctly. Every 5 minutes is suggested.
82 #include <afsconfig.h>
83 #include <afs/param.h>
88 #include <stdlib.h> /* for malloc() */
89 #include <time.h> /* ANSI standard location for time stuff */
100 #ifdef HAVE_STRINGS_H
104 #include <afs/assert.h>
106 #include <afs/stds.h>
108 #include <afs/nfs.h> /* yuck. This is an abomination. */
111 #include <afs/afscbint.h>
112 #include <afs/afsutil.h>
114 #include <afs/ihandle.h>
115 #include <afs/vnode.h>
116 #include <afs/volume.h>
119 #include <afs/ptclient.h> /* need definition of prlist for host.h */
123 extern int hostCount;
124 int ShowProblems = 1;
126 /* Maximum number of call backs to break at once, single fid */
127 /* There is some debate as to just how large this value should be */
128 /* Ideally, it would be very very large, but I am afraid that the */
129 /* cache managers will all send in their responses simultaneously, */
130 /* thereby swamping the file server. As a result, something like */
131 /* 10 or 15 might be a better bet. */
132 #define MAX_CB_HOSTS 10
134 /* max time to break a callback, otherwise client is dead or net is hosed */
137 #define u_short unsigned short
138 #define u_byte unsigned char
140 struct cbcounters cbstuff;
148 afs_uint32 vnode; /* XXX This was u_short XXX */
155 #if defined(AFS_ALPHA_ENV) || defined(AFS_ALPHA_LINUX20_ENV)
159 } *FE; /* Don't use FE[0] */
162 u_short cnext; /* Next call back entry */
163 u_short fhead; /* Head of this call back chain */
164 u_byte thead; /* Head of timeout chain */
165 u_byte status; /* Call back status; see definitions, below */
166 u_short hhead; /* Head of host table chain */
167 u_short tprev, tnext; /* Timeout chain */
168 u_short hprev, hnext; /* Chain from host table */
169 } *CB; /* Don't use CB[0] */
171 /* status bits 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 u_short 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 */
268 struct CallBack *CBfree = 0;
269 struct FileEntry *FEfree = 0;
271 static struct CallBack *iGetCB(register int *nused);
272 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
273 static struct FileEntry *iGetFE(register int *nused);
274 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
275 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
276 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
278 #define VHASH 512 /* Power of 2 */
279 static u_short HashTable[VHASH]; /* File entry hash table */
280 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
282 static struct FileEntry *FindFE (fid)
283 register AFSFid *fid;
288 register struct FileEntry *fe;
290 hash = VHash(fid->Volume, fid->Unique);
291 for (fei=HashTable[hash]; fei; fei = fe->fnext) {
293 if (fe->volid == fid->Volume && fe->unique == fid->Unique &&
294 fe->vnode == fid->Vnode)
302 #ifndef INTERPRET_DUMP
304 extern void ShutDown();
305 static CDelPtr(), FDel(), AddCallback1(), GetSomeSpace_r();
307 static struct CallBack *iGetCB(register int *nused)
309 register struct CallBack *ret;
311 if ((ret = CBfree)) {
312 CBfree = (struct CallBack *)(((struct object *)ret)->next);
320 static iFreeCB(cb, nused)
321 register struct CallBack *cb;
325 ((struct object *)cb)->next = (struct object *)CBfree;
331 static struct FileEntry *iGetFE(register int *nused)
333 register struct FileEntry *ret;
335 if ((ret = FEfree)) {
336 FEfree = (struct FileEntry *)(((struct object *)ret)->next);
344 static iFreeFE(fe, nused)
345 register struct FileEntry *fe;
349 ((struct object *)fe)->next = (struct object *)FEfree;
355 /* Add cb to end of specified timeout list */
356 static TAdd(cb, thead)
357 register struct CallBack *cb;
358 register u_short *thead;
362 (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
364 register struct CallBack *thp = itocb(*thead);
366 cb->tprev = thp->tprev;
370 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
372 thp->tprev = cbtoi(cb);
375 cb->thead = ttoi(thead);
380 /* Delete call back entry from timeout list */
382 register struct CallBack *cb;
385 register u_short *thead = itot(cb->thead);
387 if (*thead == cbtoi(cb))
388 *thead = (*thead == cb->tnext? 0: cb->tnext);
389 if (itocb(cb->tprev))
390 itocb(cb->tprev)->tnext = cb->tnext;
391 if (itocb(cb->tnext))
392 itocb(cb->tnext)->tprev = cb->tprev;
397 /* Add cb to end of specified host list */
398 static HAdd(cb, host)
399 register struct CallBack *cb;
400 register struct host *host;
403 cb->hhead = h_htoi(host);
405 host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
408 register struct CallBack *hhp = itocb(host->cblist);
410 cb->hprev = hhp->hprev;
411 cb->hnext = host->cblist;
412 hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
418 /* Delete call back entry from host list */
420 register struct CallBack *cb;
423 register u_short *hhead = &h_itoh(cb->hhead)->cblist;
425 if (*hhead == cbtoi(cb))
426 *hhead = (*hhead == cb->hnext? 0: cb->hnext);
427 itocb(cb->hprev)->hnext = cb->hnext;
428 itocb(cb->hnext)->hprev = cb->hprev;
433 /* Delete call back entry from fid's chain of cb's */
434 /* N.B. This one also deletes the CB, and also possibly parent FE, so
435 * make sure that it is not on any other list before calling this
442 struct FileEntry *fe = itofe(cb->fhead);
443 register u_short *cbp;
446 for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
447 cbp = &itocb(*cbp)->cnext, safety++) {
448 if (safety > cbstuff.nblks + 10) {
450 ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
460 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
461 * as well as file entry */
462 /* N.B. This one also deletes the CB, and also possibly parent FE, so
463 * make sure that it is not on any other list before calling this
465 int Ccdelpt=0, CcdelB=0;
467 static CDelPtr(fe, cbp)
468 register struct FileEntry *fe;
469 register u_short *cbp;
472 register struct CallBack *cb;
488 static u_short *FindCBPtr(fe, host)
489 struct FileEntry *fe;
493 register afs_uint32 hostindex = h_htoi(host);
494 register struct CallBack *cb;
495 register u_short *cbp;
498 for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
499 if (safety > cbstuff.nblks) {
500 ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
505 if (cb->hhead == hostindex)
514 /* Delete file entry from hash table */
516 register struct FileEntry *fe;
519 register int fei = fetoi(fe);
520 register unsigned short *p = &HashTable[VHash(fe->volid, fe->unique)];
522 while (*p && *p != fei)
523 p = &itofe(*p)->fnext;
537 tfirst = CBtime(FT_ApproxTime());
538 /* N.B. FE's, CB's share same free list. If the sizes of either change,
539 FE and CB will have to be separated. The "-1", below, is because
540 FE[0] and CB[0] are not used--and not allocated */
541 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*nblks)))-1;
542 cbstuff.nFEs = nblks;
544 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
545 CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
546 cbstuff.nCBs = nblks;
548 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
549 cbstuff.nblks = nblks;
550 cbstuff.nbreakers = 0;
556 afs_int32 XCallBackBulk_r(ahost, fids, nfids)
562 struct AFSCallBack tcbs[AFSCBMAX];
570 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
571 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
578 for(i=0;i<nfids && i < AFSCBMAX;i++) {
579 tcbs[i].CallBackVersion = CALLBACK_VERSION;
580 tcbs[i].ExpirationTime = 0;
581 tcbs[i].CallBackType = CB_DROPPED;
583 tf.AFSCBFids_len = i;
584 tf.AFSCBFids_val = &(fids[j]);
588 tc.AFSCBs_val = tcbs;
591 code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
599 /* the locked flag tells us if the host entry has already been locked
600 * by our parent. I don't think anybody actually calls us with the
601 * host locked, but here's how to make that work: GetSomeSpace has to
602 * change so that it doesn't attempt to lock any hosts < "host". That
603 * means that it might be unable to free any objects, so it has to
604 * return an exit status. If it fails, then AddCallBack1 might fail,
605 * as well. If so, the host->ResetDone should probably be set to 0,
606 * and we probably don't want to return a callback promise to the
607 * cache manager, either. */
609 AddCallBack1(host, fid, thead, type, locked)
621 retVal = AddCallBack1_r(host, fid, thead, type, 1);
631 AddCallBack1_r(host, fid, thead, type, locked)
638 struct FileEntry *fe;
639 struct CallBack *cb = 0, *lastcb = 0;
640 struct FileEntry *newfe = 0;
642 u_short *Thead = thead;
643 struct CallBack *newcb = 0;
648 /* allocate these guys first, since we can't call the allocator with
649 the host structure locked -- or we might deadlock. However, we have
650 to avoid races with FindFE... */
651 while (!(newcb = GetCB())) {
652 GetSomeSpace_r(host, locked);
654 while(!(newfe = GetFE())) { /* Get it now, so we don't have to call */
655 /* GetSomeSpace with the host locked, later. This might turn out to */
656 /* have been unneccessary, but that's actually kind of unlikely, since */
657 /* most files are not shared. */
658 GetSomeSpace_r(host, locked);
662 h_Lock_r(host); /* this can yield, so do it before we get any */
667 if (type == CB_NORMAL) {
668 time_out = TimeCeiling(FT_ApproxTime()+TimeOut(fe?fe->ncbs:0)+ServerBias);
669 Thead = THead(CBtime(time_out));
671 else if (type == CB_VOLUME) {
672 time_out = TimeCeiling((60*120+FT_ApproxTime())+ServerBias);
673 Thead = THead(CBtime(time_out));
675 else if (type == CB_BULK) {
676 /* bulk status can get so many callbacks all at once, and most of them
677 * are probably not for things that will be used for long.
679 time_out = TimeCeiling(FT_ApproxTime() + ServerBias
680 + TimeOut(22 + (fe?fe->ncbs:0)));
681 Thead = THead(CBtime(time_out));
687 register afs_uint32 hash;
692 fe->volid = fid->Volume;
693 fe->vnode = fid->Vnode;
694 fe->unique = fid->Unique;
696 hash = VHash(fid->Volume, fid->Unique);
697 fe->fnext = HashTable[hash];
698 HashTable[hash] = fetoi(fe);
700 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
701 lastcb = cb, cb = itocb(cb->cnext), safety++) {
702 if (safety > cbstuff.nblks) {
703 ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
707 if (cb->hhead == h_htoi(host))
710 if (cb) {/* Already have call back: move to new timeout list */
711 /* don't change delayed callbacks back to normal ones */
712 if (cb->status != CB_DELAYED)
714 /* Only move if new timeout is longer */
715 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
722 *(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
725 cb->fhead = fetoi(fe);
731 /* now free any still-unused callback or host entries */
732 if (newcb) FreeCB(newcb);
733 if (newfe) FreeFE(newfe);
735 if (!locked) /* freecb and freefe might(?) yield */
738 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK )
739 return time_out-ServerBias; /* Expires sooner at workstation */
745 /* Take an array full of hosts, all held. Break callbacks to them, and
746 * release the holds once you're done, except don't release xhost. xhost
747 * may be NULL. Currently only works for a single Fid in afidp array.
748 * If you want to make this work with multiple fids, you need to fix
749 * the error handling. One approach would be to force a reset if a
750 * multi-fid call fails, or you could add delayed callbacks for each
751 * fid. You probably also need to sort and remove duplicate hosts.
752 * When this is called from the BreakVolumeCallBacks path, it does NOT
753 * force a reset if the RPC fails, it just marks the host down and tries
754 * to create a delayed callback. */
755 /* N.B. be sure that code works when ncbas == 0 */
756 /* N.B. requires all the cba[*].hp pointers to be valid... */
757 /* This routine does not hold a lock on the host for the duration of
758 * the BreakCallBack RPC, which is a significant deviation from tradition.
759 * It _does_ get a lock on the host before setting VenusDown = 1,
760 * which is sufficient only if VenusDown = 0 only happens when the
761 * lock is held over the RPC and the subsequent VenusDown == 0
762 * wherever that is done. */
763 static void MultiBreakCallBack_r(cba, ncbas, afidp, xhost)
764 struct cbstruct cba[];
766 struct AFSCBFids *afidp;
770 struct rx_connection *conns[MAX_CB_HOSTS];
771 int opt_TO; /* secs, but internal adaptive parms are in ms */
772 static struct AFSCBs tc = {0,0};
774 assert(ncbas <= MAX_CB_HOSTS);
776 /* set up conns for multi-call */
777 for (i=0,j=0; i<ncbas; i++) {
778 struct host *thishost = cba[i].hp;
779 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
782 conns[j++] = thishost->callback_rxcon;
785 rx_SetConnDeadTime (thishost->callback_rxcon, 4);
786 rx_SetConnHardDeadTime (thishost->callback_rxcon, AFS_HARDDEADTIME);
790 if (j) { /* who knows what multi would do with 0 conns? */
794 multi_RXAFSCB_CallBack(afidp, &tc);
801 /* If there's an error, we have to hunt for the right host.
802 * The conns array _should_ correspond one-to-one to the cba
803 * array, except in some rare cases it might be missing one
804 * or more elements. So the optimistic case is almost
805 * always right. At worst, it's the starting point for the
807 for (hp=0,i=multi_i;i<j;i++) {
808 hp = cba[i].hp; /* optimistic, but usually right */
812 if (conns[multi_i] == hp->callback_rxcon) {
819 ViceLog(0, ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n",hp,cba));
823 ** try breaking callbacks on alternate interface addresses
825 if ( MultiBreakCallBackAlternateAddress(hp, afidp) )
829 ("BCB: Failed on file %u.%d.%d, host %s:%d is down\n",
830 afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
831 afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), hp->port));
836 hp->hostFlags |= VENUSDOWN;
838 * We always go into AddCallBack1_r with the host locked
840 AddCallBack1_r(hp,afidp->AFSCBFids_val,itot(idx), CB_DELAYED, 1);
851 for (i=0; i<ncbas; i++) {
854 if (hp && xhost != hp)
862 * Break all call backs for fid, except for the specified host (unless flag
863 * is true, in which case all get a callback message. Assumption: the specified
864 * host is h_Held, by the caller; the others aren't.
865 * Specified host may be bogus, that's ok. This used to check to see if the
866 * host was down in two places, once right after the host was h_held, and
867 * again after it was locked. That race condition is incredibly rare and
868 * relatively harmless even when it does occur, so we don't check for it now.
870 BreakCallBack(xhost, fid, flag)
872 int flag; /* if flag is true, send a break callback msg to "host", too */
875 struct FileEntry *fe;
876 struct CallBack *cb, *nextcb;
877 struct cbstruct cba[MAX_CB_HOSTS];
879 struct rx_connection *conns[MAX_CB_HOSTS];
884 ViceLog(7,("BCB: BreakCallBack(all but %s:%d, (%u,%d,%d))\n",
885 afs_inet_ntoa_r(xhost->host,hoststr), xhost->port, fid->Volume, fid->Vnode,
890 cbstuff.BreakCallBacks++;
895 hostindex = h_htoi(xhost);
896 cb = itocb(fe->firstcb);
897 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
898 /* the most common case is what follows the || */
901 tf.AFSCBFids_len = 1;
902 tf.AFSCBFids_val = fid;
905 for (ncbas=0; cb && ncbas<MAX_CB_HOSTS; cb=nextcb) {
906 nextcb = itocb(cb->cnext);
907 if ((cb->hhead != hostindex || flag)
908 && (cb->status == CB_BULK || cb->status == CB_NORMAL
909 || cb->status == CB_VOLUME) ) {
910 struct host *thishost = h_itoh(cb->hhead);
912 ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
914 else if (thishost->hostFlags & VENUSDOWN) {
915 ViceLog(7,("BCB: %s:%d is down; delaying break call back\n",
916 afs_inet_ntoa_r(thishost->host,hoststr), thishost->port));
917 cb->status = CB_DELAYED;
921 cba[ncbas].hp = thishost;
922 cba[ncbas].thead = cb->thead;
926 CDel(cb); /* Usually first; so this delete */
927 /* is reasonably inexpensive */
933 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
935 /* we need to to all these initializations again because MultiBreakCallBack may block */
940 cb = itocb(fe->firstcb);
941 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
942 /* the most common case is what follows the || */
954 /* Delete (do not break) single call back for fid */
955 DeleteCallBack(host, fid)
960 register struct FileEntry *fe;
961 register u_short *pcb;
964 cbstuff.DeleteCallBacks++;
972 ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
973 fid->Volume, fid->Vnode, fid->Unique));
976 pcb = FindCBPtr(fe, host);
978 ViceLog(8,("DCB: No call back for host %s:%d, (%u, %d, %d)\n",
979 afs_inet_ntoa_r(host->host,hoststr), host->port, fid->Volume, fid->Vnode, fid->Unique));
994 * Delete (do not break) all call backs for fid. This call doesn't
995 * set all of the various host locks, but it shouldn't really matter
996 * since we're not adding callbacks, but deleting them. I'm not sure
997 * why it doesn't set the lock, however; perhaps it should.
999 DeleteFileCallBacks(fid)
1002 register struct FileEntry *fe;
1003 register struct CallBack *cb;
1004 register afs_uint32 cbi;
1008 cbstuff.DeleteFiles++;
1012 ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
1013 fid->Volume, fid->Vnode, fid->Unique));
1016 for (n=0,cbi = fe->firstcb; cbi; n++) {
1026 } /*DeleteFileCallBacks*/
1029 /* Delete (do not break) all call backs for host. The host should be
1031 DeleteAllCallBacks(host)
1036 retVal = DeleteAllCallBacks_r(host);
1041 DeleteAllCallBacks_r(host)
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);
1061 } /*DeleteAllCallBacks*/
1065 * Break all delayed call backs for host. Returns 1 if all call backs
1066 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1067 * Must be called with VenusDown set for this host
1069 int BreakDelayedCallBacks(host)
1074 retVal = BreakDelayedCallBacks_r(host);
1079 extern afsUUID FS_HostUUID;
1081 int BreakDelayedCallBacks_r(host)
1084 struct AFSFid fids[AFSCBMAX];
1085 u_short thead[AFSCBMAX];
1086 int cbi, first, nfids;
1087 struct CallBack *cb;
1088 struct interfaceAddr interf;
1092 cbstuff.nbreakers++;
1093 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1094 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1095 if ( host->interface ) {
1097 code = RXAFSCB_InitCallBackState3(host->callback_rxcon,
1102 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
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), host->port));
1112 host->hostFlags |= VENUSDOWN;
1115 ViceLog(25,("InitCallBackState success on %s\n",afs_inet_ntoa_r(host->host,hoststr)));
1116 /* reset was done successfully */
1117 host->hostFlags |= RESETDONE;
1118 host->hostFlags &= ~VENUSDOWN;
1121 else while (!(host->hostFlags & HOSTDELETED)) {
1123 host->hostFlags &= ~VENUSDOWN; /* presume up */
1124 cbi = first = host->cblist;
1128 first = host->cblist;
1131 if (cb->status == CB_DELAYED) {
1132 register struct FileEntry *fe = itofe(cb->fhead);
1133 thead[nfids] = cb->thead;
1134 fids[nfids].Volume = fe->volid;
1135 fids[nfids].Vnode = fe->vnode;
1136 fids[nfids].Unique = fe->unique;
1142 } while (cbi && cbi != first && nfids < AFSCBMAX);
1148 if (XCallBackBulk_r(host, fids, nfids)) {
1149 /* Failed, again: put them back, probably with old
1154 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1155 afs_inet_ntoa_r(host->host,hoststr), host->port));
1157 for (i = 0; i<nfids; i++) {
1160 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1161 afs_inet_ntoa_r(host->host,hoststr), host->port,
1162 fids[i].Volume, fids[i].Vnode, fids[i].Unique));
1165 AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1166 * but it turns out to cause too many tricky locking problems.
1167 * now, if break delayed fails, screw it. */
1169 host->hostFlags |= VENUSDOWN; /* Failed */
1170 ClearHostCallbacks_r(host, 1/* locked */);
1174 if (nfids < AFSCBMAX)
1178 cbstuff.nbreakers--;
1179 return (host->hostFlags & VENUSDOWN);
1181 } /*BreakDelayedCallBacks*/
1185 struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
1187 unsigned short thead; /* head of timeout queue for youngest callback */
1192 ** isheld is 0 if the host is held in h_Enumerate
1193 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1195 static int MultiBreakVolumeCallBack_r (host, isheld, parms)
1198 struct VCBParams *parms;
1203 return isheld; /* host is held only by h_Enumerate, do nothing */
1204 if ( host->hostFlags & HOSTDELETED )
1205 return 0; /* host is deleted, release hold */
1207 if (host->hostFlags & VENUSDOWN) {
1209 if (host->hostFlags & HOSTDELETED) {
1211 return 0; /* Release hold */
1213 ViceLog(8,("BVCB: volume call back for host %s:%d failed\n",
1214 afs_inet_ntoa_r(host->host,hoststr),host->port));
1216 ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
1217 afs_inet_ntoa_r(host->host,hoststr), host->port));
1219 DeleteAllCallBacks_r(host); /* Delete all callback state rather than
1220 attempting to selectively remember to
1221 delete the volume callbacks later */
1222 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1224 return 0; /* release hold */
1226 assert(parms->ncbas <= MAX_CB_HOSTS);
1228 /* Do not call MultiBreakCallBack on the current host structure
1229 ** because it would prematurely release the hold on the host
1231 if ( parms->ncbas == MAX_CB_HOSTS ) {
1232 struct AFSCBFids tf;
1234 tf.AFSCBFids_len = 1;
1235 tf.AFSCBFids_val = parms->fid;
1237 /* this releases all the hosts */
1238 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */);
1242 parms->cba[parms->ncbas].hp = host;
1243 parms->cba[(parms->ncbas)++].thead = parms->thead;
1244 return 1; /* DON'T release hold, because we still need it. */
1248 ** isheld is 0 if the host is held in h_Enumerate
1249 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1251 static int MultiBreakVolumeCallBack (host, isheld, parms)
1254 struct VCBParams *parms;
1258 retval = MultiBreakVolumeCallBack_r(host, isheld, parms);
1264 * Break all call backs on a single volume. Don't call this with any
1265 * hosts h_held. Note that this routine clears the callbacks before
1266 * actually breaking them, and that the vnode isn't locked during this
1267 * operation, so that people might see temporary callback loss while
1268 * this function is executing. It is just a temporary state, however,
1269 * since the callback will be broken later by this same function.
1271 * Now uses multi-RX for CallBack RPC. Note that the
1272 * multiBreakCallBacks routine does not force a reset if the RPC
1273 * fails, unlike the previous version of this routine, but does create
1274 * a delayed callback. Resets will be forced if the host is
1275 * determined to be down before the RPC is executed.
1277 BreakVolumeCallBacks(volume)
1284 struct CallBack *cb;
1285 struct FileEntry *fe;
1287 struct VCBParams henumParms;
1288 unsigned short tthead = 0; /* zero is illegal value */
1291 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1292 for (hash=0; hash<VHASH; hash++) {
1293 for (feip = &HashTable[hash]; (fe = itofe(*feip)); ) {
1294 if (fe->volid == volume) {
1295 register struct CallBack *cbnext;
1296 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1297 host = h_itoh(cb->hhead);
1299 cbnext = itocb(cb->cnext);
1300 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1306 /* leave hold for MultiBreakVolumeCallBack to clear */
1317 /* didn't find any callbacks, so return right away. */
1321 henumParms.ncbas = 0;
1322 henumParms.fid = &fid;
1323 henumParms.thead = tthead;
1325 h_Enumerate(MultiBreakVolumeCallBack, (char *) &henumParms);
1328 if (henumParms.ncbas) { /* do left-overs */
1329 struct AFSCBFids tf;
1330 tf.AFSCBFids_len = 1;
1331 tf.AFSCBFids_val = &fid;
1333 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1335 henumParms.ncbas = 0;
1340 } /*BreakVolumeCallBacks*/
1344 * Delete all timed-out call back entries (to be called periodically by file
1347 CleanupTimedOutCallBacks()
1350 CleanupTimedOutCallBacks_r();
1354 CleanupTimedOutCallBacks_r()
1356 afs_uint32 now = CBtime(FT_ApproxTime());
1357 register u_short *thead;
1358 register struct CallBack *cb;
1359 register int ntimedout = 0;
1362 extern void ShutDown();
1364 while (tfirst <= now) {
1366 cbi = *(thead = THead(tfirst));
1371 ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1372 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port,
1373 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1374 itofe(cb->fhead)->unique));
1378 if (ntimedout > cbstuff.nblks) {
1379 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1380 DumpCallBackState();
1383 } while (cbi != *thead);
1388 cbstuff.CBsTimedOut += ntimedout;
1389 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1390 return (ntimedout > 0);
1392 } /*CleanupTimedOutCallBacks*/
1395 static struct host *lih_host;
1397 static int lih_r(host, held, hostp)
1398 register struct host *host, *hostp;
1403 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1404 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1412 /* This could be upgraded to get more space each time */
1413 /* first pass: find the oldest host which isn't held by anyone */
1414 /* second pass: find the oldest host who isn't "me" */
1415 /* always called with hostp unlocked */
1416 static int GetSomeSpace_r(hostp, locked)
1420 register struct host *hp, *hp1 = NULL;
1423 cbstuff.GotSomeSpaces++;
1424 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1425 if (CleanupTimedOutCallBacks_r()) {
1431 h_Enumerate_r(lih_r, (char *)hp1);
1435 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1441 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1443 * Next time try getting callbacks from any host even if
1444 * it's deleted (that's actually great since we can freely
1445 * remove its callbacks) or it's held since the only other
1446 * option is starvation for the file server (i.e. until the
1447 * callback timeout arrives).
1453 * No choice to clear this host's callback state
1455 /* third pass: we still haven't gotten any space, so we free what we had
1456 * previously passed over. */
1461 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1468 ClearHostCallbacks(hp, locked)
1470 int locked; /* set if caller has already locked the host */
1474 retVal = ClearHostCallbacks_r(hp, locked);
1479 int ClearHostCallbacks_r(hp, locked)
1481 int locked; /* set if caller has already locked the host */
1483 struct interfaceAddr interf;
1488 ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
1489 if ( !(held = h_Held_r(hp)) )
1492 /** Try a non-blocking lock. If the lock is already held return
1493 * after releasing hold on hp
1496 if ( h_NBLock_r(hp) ) {
1502 if (hp->Console & 2) {
1504 * If the special console field is set it means that a thread
1505 * is waiting in AddCallBack1 after it set pointers to the
1506 * file entry and/or callback entry. Because of the bogus
1507 * usage of h_hold it won't prevent from another thread, this
1508 * one, to remove all the callbacks so just to be safe we keep
1509 * a reference. NOTE, on the last phase we'll free the calling
1510 * host's callbacks but that's ok...
1514 DeleteAllCallBacks_r(hp);
1515 if (hp->hostFlags & VENUSDOWN) {
1516 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1518 /* host is up, try a call */
1519 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1520 if (hp->interface) {
1522 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1526 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1529 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1532 /* failed, mark host down and need reset */
1533 hp->hostFlags |= VENUSDOWN;
1534 hp->hostFlags &= ~RESETDONE;
1536 /* reset succeeded, we're done */
1537 hp->hostFlags |= RESETDONE;
1548 #endif /* INTERPRET_DUMP */
1551 PrintCallBackStats()
1554 fprintf(stderr, "%d add CB, %d break CB, %d del CB, %d del FE, %d CB's timed out, %d space reclaim, %d del host\n",
1555 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1556 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1557 cbstuff.DeleteAllCallBacks);
1558 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1559 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1561 } /*PrintCallBackStats*/
1564 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1566 #ifndef INTERPRET_DUMP
1573 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1575 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1577 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1580 write(fd, &magic, sizeof(magic));
1581 write(fd, &now, sizeof(now));
1582 write(fd, &cbstuff, sizeof(cbstuff));
1583 write(fd, TimeOuts, sizeof(TimeOuts));
1584 write(fd, timeout, sizeof(timeout));
1585 write(fd, &tfirst, sizeof(tfirst));
1586 freelisthead = cbtoi((struct CallBack *) CBfree);
1587 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1588 freelisthead = fetoi((struct FileEntry *) FEfree);
1589 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1590 write(fd, HashTable, sizeof(HashTable));
1591 write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1592 write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1595 } /*DumpCallBackState*/
1599 #ifdef INTERPRET_DUMP
1601 /* This is only compiled in for the callback analyzer program */
1602 /* Returns the time of the dump */
1603 time_t ReadDump(file)
1608 afs_uint32 magic, freelisthead;
1611 fd = open(file, O_RDONLY);
1613 fprintf(stderr, "Couldn't read dump file %s\n", file);
1616 read(fd, &magic, sizeof(magic));
1617 if (magic != MAGIC) {
1618 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1621 "run this program on a machine type with a different byte ordering.\n");
1624 read(fd, &now, sizeof(now));
1625 read(fd, &cbstuff, sizeof(cbstuff));
1626 read(fd, TimeOuts, sizeof(TimeOuts));
1627 read(fd, timeout, sizeof(timeout));
1628 read(fd, &tfirst, sizeof(tfirst));
1629 read(fd, &freelisthead, sizeof(freelisthead));
1630 CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1631 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1632 CBfree = (struct CallBack *) itocb(freelisthead);
1633 read(fd, &freelisthead, sizeof(freelisthead));
1634 FEfree = (struct FileEntry *) itofe(freelisthead);
1635 read(fd, HashTable, sizeof(HashTable));
1636 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1637 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1639 perror("Error reading dumpfile");
1647 #include "AFS_component_version_number.c"
1654 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1656 register struct FileEntry *fe;
1657 register struct CallBack *cb;
1660 memset(&fid, 0, sizeof(fid));
1662 while (argc && **argv == '-') {
1665 if (!strcmp(*argv, "-host")) {
1671 cbi = atoi(*++argv);
1673 else if (!strcmp(*argv, "-fid")) {
1679 fid.Volume = atoi(*++argv);
1680 fid.Vnode = atoi(*++argv);
1681 fid.Unique = atoi(*++argv);
1683 else if (!strcmp(*argv, "-time")) {
1684 fprintf(stderr, "-time not supported\n");
1687 else if (!strcmp(*argv, "-stats")) {
1690 else if (!strcmp(*argv, "-all")) {
1693 else if (!strcmp(*argv, "-raw")) {
1696 else if (!strcmp(*argv, "-volume")) {
1702 vol = atoi(*++argv);
1707 if (err || argc != 1) {
1709 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1710 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1713 now = ReadDump(*argv);
1714 if (stats || noptions == 0) {
1715 time_t uxtfirst = UXtime(tfirst);
1716 printf("The time of the dump was %u %s", now, ctime(&now));
1717 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1718 PrintCallBackStats();
1722 register u_short *feip;
1723 register struct CallBack *cb;
1724 register struct FileEntry *fe;
1726 for (hash=0; hash<VHASH; hash++) {
1727 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1728 if (!vol || (fe->volid == vol)) {
1729 register struct CallBack *cbnext;
1730 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1732 cbnext = itocb(cb->cnext);
1742 u_short cfirst = cbi;
1747 } while (cbi != cfirst);
1752 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1755 cb = itocb(fe->firstcb);
1758 cb = itocb(cb->cnext);
1762 struct FileEntry *fe;
1764 for (i=1; i < cbstuff.nblks; i++) {
1765 p = (afs_int32 *) &FE[i];
1766 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1772 register struct CallBack *cb;
1776 struct FileEntry *fe = itofe(cb->fhead);
1777 time_t expires = TIndexToTime(cb->thead);
1779 printf("vol=%u vn=%u cbs=%d hi=%d st=%d, exp in %d secs at %s",
1780 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1781 expires - now, ctime(&expires));
1788 #if !defined(INTERPRET_DUMP)
1790 ** try breaking calbacks on afidp from host. Use multi_rx.
1791 ** return 0 on success, non-zero on failure
1794 MultiBreakCallBackAlternateAddress(host, afidp)
1796 struct AFSCBFids* afidp;
1800 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1806 MultiBreakCallBackAlternateAddress_r(host, afidp)
1808 struct AFSCBFids* afidp;
1811 struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
1812 struct rx_connection* connSuccess = 0;
1813 afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
1814 static struct rx_securityClass *sc = 0;
1815 static struct AFSCBs tc = {0,0};
1818 /* nothing more can be done */
1819 if ( !host->interface ) return 1; /* failure */
1821 assert(host->interface->numberOfInterfaces > 0 );
1823 /* the only address is the primary interface */
1824 if ( host->interface->numberOfInterfaces == 1 )
1825 return 1; /* failure */
1827 /* initialise a security object only once */
1829 sc = rxnull_NewClientSecurityObject();
1831 /* initialize alternate rx connections */
1832 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1834 /* this is the current primary address */
1835 if ( host->host == host->interface->addr[i] )
1838 addr[j] = host->interface->addr[i];
1839 conns[j] = rx_NewConnection (host->interface->addr[i],
1840 host->port, 1, sc, 0);
1841 rx_SetConnDeadTime(conns[j], 2);
1842 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1846 assert(j); /* at least one alternate address */
1847 ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
1848 afs_inet_ntoa_r(host->host,hoststr)));
1852 multi_RXAFSCB_CallBack(afidp, &tc);
1857 if ( host->callback_rxcon )
1858 rx_DestroyConnection(host->callback_rxcon);
1859 host->callback_rxcon = conns[multi_i];
1860 host->host = addr[multi_i];
1861 connSuccess = conns[multi_i];
1862 rx_SetConnDeadTime(host->callback_rxcon, 50);
1863 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1864 ViceLog(125,("multibreakcall success with addr %s\n",
1865 afs_inet_ntoa_r(addr[multi_i],hoststr)));
1872 /* Destroy all connections except the one on which we succeeded */
1873 for ( i=0; i < j; i++)
1874 if ( conns[i] != connSuccess )
1875 rx_DestroyConnection(conns[i] );
1877 if ( connSuccess ) return 0; /* success */
1878 else return 1; /* failure */
1883 ** try multiRX probes to host.
1884 ** return 0 on success, non-zero on failure
1887 MultiProbeAlternateAddress_r(host)
1891 struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
1892 struct rx_connection* connSuccess = 0;
1893 afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
1894 static struct rx_securityClass *sc = 0;
1897 /* nothing more can be done */
1898 if ( !host->interface ) return 1; /* failure */
1900 assert(host->interface->numberOfInterfaces > 0 );
1902 /* the only address is the primary interface */
1903 if ( host->interface->numberOfInterfaces == 1 )
1904 return 1; /* failure */
1906 /* initialise a security object only once */
1908 sc = rxnull_NewClientSecurityObject();
1910 /* initialize alternate rx connections */
1911 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1913 /* this is the current primary address */
1914 if ( host->host == host->interface->addr[i] )
1917 addr[j] = host->interface->addr[i];
1918 conns[j] = rx_NewConnection (host->interface->addr[i],
1919 host->port, 1, sc, 0);
1920 rx_SetConnDeadTime(conns[j], 2);
1921 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1925 assert(j); /* at least one alternate address */
1926 ViceLog(125,("Starting multiprobe on all addr for host %s\n",
1927 afs_inet_ntoa_r(host->host,hoststr)));
1931 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
1936 if ( host->callback_rxcon )
1937 rx_DestroyConnection(host->callback_rxcon);
1938 host->callback_rxcon = conns[multi_i];
1939 host->host = addr[multi_i];
1940 connSuccess = conns[multi_i];
1941 rx_SetConnDeadTime(host->callback_rxcon, 50);
1942 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1943 ViceLog(125,("multiprobe success with addr %s\n",
1944 afs_inet_ntoa_r(addr[multi_i],hoststr)));
1951 /* Destroy all connections except the one on which we succeeded */
1952 for ( i=0; i < j; i++)
1953 if ( conns[i] != connSuccess )
1954 rx_DestroyConnection(conns[i] );
1956 if ( connSuccess ) return 0; /* success */
1957 else return 1; /* failure */
1960 #endif /* !defined(INTERPRET_DUMP) */