1 /* Copyright (C) 1998 Transarc Corporation - All rights reserved */
3 * For copyright information, see IPL which you accepted in order to
4 * download this software.
9 * NEW callback package callback.c (replaces vicecb.c)
10 * Updated call back routines, NOW with:
12 * Faster DeleteVenus (Now called DeleteAllCallBacks)
13 * Call back breaking for volumes
14 * Adaptive timeouts on call backs
15 * Architected for Multi RPC
16 * No locks (currently implicit vnode locks--these will go, to)
17 * Delayed call back when rpc connection down.
18 * Bulk break of delayed call backs when rpc connection
20 * Strict limit on number of call backs.
22 * InitCallBack(nblocks)
23 * Initialize: nblocks is max number # of file entries + # of callback entries
24 * nblocks must be < 65536
25 * Space used is nblocks*16 bytes
26 * Note that space will be reclaimed by breaking callbacks of old hosts
28 * time = AddCallBack(host, fid)
30 * Returns the expiration time at the workstation.
32 * BreakCallBack(host, fid)
33 * Break all call backs for fid, except for the specified host.
36 * BreakVolumeCallBacks(volume)
37 * Break all call backs on volume, using single call to each host
38 * Delete all the call backs.
40 * DeleteCallBack(host,fid)
41 * Delete (do not break) single call back for fid.
43 * DeleteFileCallBacks(fid)
44 * Delete (do not break) all call backs for fid.
46 * DeleteAllCallBacks(host)
47 * Delete (do not break) all call backs for host.
49 * CleanupTimedOutCallBacks()
50 * Delete all timed out call back entries
51 * Must be called periodically by file server.
53 * BreakDelayedCallBacks(host)
54 * Break all delayed call backs for host.
55 * Returns 1: one or more failed, 0: success.
57 * PrintCallBackStats()
58 * Print statistics about call backs to stdout.
60 * DumpCallBacks() ---wishful thinking---
61 * Dump call back state to /tmp/callback.state.
62 * This is separately interpretable by the program pcb.
64 * Notes: In general, if a call back to a host doesn't get through,
65 * then HostDown, supplied elsewhere, is called. BreakDelayedCallBacks,
66 * however, does not call HostDown, but instead returns an indication of
67 * success if all delayed call backs were finally broken.
69 * BreakDelayedCallBacks MUST be called at the first sign of activity
70 * from the host after HostDown has been called (or a previous
71 * BreakDelayedCallBacks failed). The BreakDelayedCallBacks must be
72 * allowed to complete before any requests from that host are handled.
73 * If BreakDelayedCallBacks fails, then the host should remain
74 * down (and the request should be failed).
76 * CleanupCallBacks MUST be called periodically by the file server for
77 * this package to work correctly. Every 5 minutes is suggested.
80 #include <afs/param.h>
82 #include <stdlib.h> /* for malloc() */
83 #include <time.h> /* ANSI standard location for time stuff */
91 #include <afs/assert.h>
95 #include <afs/nfs.h> /* yuck. This is an abomination. */
98 #include <afs/afscbint.h>
99 #include <afs/afsutil.h>
101 #include <afs/ihandle.h>
102 #include <afs/vnode.h>
103 #include <afs/volume.h>
106 #include <afs/ptclient.h> /* need definition of prlist for host.h */
110 extern int hostCount;
111 int ShowProblems = 1;
113 /* Maximum number of call backs to break at once, single fid */
114 /* There is some debate as to just how large this value should be */
115 /* Ideally, it would be very very large, but I am afraid that the */
116 /* cache managers will all send in their responses simultaneously, */
117 /* thereby swamping the file server. As a result, something like */
118 /* 10 or 15 might be a better bet. */
119 #define MAX_CB_HOSTS 10
121 /* max time to break a callback, otherwise client is dead or net is hosed */
124 #define u_short unsigned short
125 #define u_byte unsigned char
127 struct cbcounters cbstuff;
135 afs_uint32 vnode; /* XXX This was u_short XXX */
146 } *FE; /* Don't use FE[0] */
149 u_short cnext; /* Next call back entry */
150 u_short fhead; /* Head of this call back chain */
151 u_byte thead; /* Head of timeout chain */
152 u_byte status; /* Call back status; see definitions, below */
153 u_short hhead; /* Head of host table chain */
154 u_short tprev, tnext; /* Timeout chain */
155 u_short hprev, hnext; /* Chain from host table */
156 } *CB; /* Don't use CB[0] */
158 /* status bits for status field of CallBack structure */
159 #define CB_NORMAL 1 /* Normal call back */
160 #define CB_DELAYED 2 /* Delayed call back due to rpc problems.
161 The call back entry will be added back to the
162 host list at the END of the list, so that
163 searching backwards in the list will find all
164 the (consecutive)host. delayed call back entries */
165 #define CB_VOLUME 3 /* Callback for a volume */
166 #define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
168 /* call back indices to pointers, and vice-versa */
169 #define itocb(i) ((i)?CB+(i):0)
170 #define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
172 /* file entry indices to pointers, and vice-versa */
173 #define itofe(i) ((i)?FE+(i):0)
174 #define fetoi(fep) (!(fep)?0:(fep)-FE)
176 /* Timeouts: there are 128 possible timeout values in effect at any
177 * given time. Each timeout represents timeouts in an interval of 128
178 * seconds. So the maximum timeout for a call back is 128*128=16384
179 * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
180 * if space runs out or by the file server every 5 minutes. This 5
181 * minute slack should be allowed for--so a maximum time of 4 hours
184 * Timeouts must be chosen to correspond to an exact multiple
185 * of 128, because all times are truncated to a 128 multiple, and
186 * timed out if the current truncated time is <= to the truncated time
187 * corresponding to the timeout queue.
190 /* Unix time to Call Back time, and vice-versa. Call back time is
191 in units of 128 seconds, corresponding to time queues. */
192 #define CBtime(uxtime) ((uxtime)>>7)
193 #define UXtime(cbtime) ((cbtime)<<7)
195 /* Given a Unix time, compute the closest Unix time that corresponds to
196 a time queue, rounding up */
197 #define TimeCeiling(uxtime) (((uxtime)+127)&~127)
199 /* Time to live for call backs depends upon number of users of the file.
200 * TimeOuts is indexed by this number/8 (using TimeOut macro). Times
201 * in this table are for the workstation; server timeouts, add
204 static int TimeOuts[] = {
205 /* Note: don't make the first entry larger than 4 hours (see above) */
206 4*60*60, /* 0-7 users */
207 1*60*60, /* 8-15 users */
208 30*60, /* 16-23 users */
209 15*60, /* 24-31 users */
210 15*60, /* 32-39 users */
211 10*60, /* 40-47 users */
212 10*60, /* 48-55 users */
213 10*60, /* 56-63 users */
214 }; /* Anything more: MinTimeOut */
216 /* minimum time given for a call back */
217 static int MinTimeOut = (7*60);
219 #define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
220 #define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
222 /* time out at server is 3 minutes more than ws */
223 #define ServerBias (3*60)
225 /* Heads of CB queues; a timeout index is 1+index into this array */
226 static u_short timeout[128];
228 /* Convert cbtime to timeout queue index */
229 #define TIndex(cbtime) (((cbtime)&127)+1)
231 /* Convert cbtime to pointer to timeout queue head */
232 #define THead(cbtime) (&timeout[TIndex(cbtime)-1])
234 static afs_int32 tfirst; /* cbtime of oldest unexpired call back time queue */
236 /* Normalize index into timeout array so that two such indices will be
237 ordered correctly, so that they can be compared to see which times
238 sooner, or so that the difference in time out times between them
240 #define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
242 /* This converts a timeout index into the actual time it will expire */
243 #define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
246 /* Convert pointer to timeout queue head to index, and vice versa */
247 #define ttoi(t) ((t-timeout)+1)
248 #define itot(i) ((timeout)+(i-1))
250 /* 16 byte object get/free routines */
255 struct CallBack *CBfree = 0;
256 struct FileEntry *FEfree = 0;
258 static struct CallBack *iGetCB(register int *nused);
259 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
260 static struct FileEntry *iGetFE(register int *nused);
261 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
262 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
263 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
265 #define VHASH 512 /* Power of 2 */
266 static u_short HashTable[VHASH]; /* File entry hash table */
267 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
269 static struct FileEntry *FindFE (fid)
270 register AFSFid *fid;
275 register struct FileEntry *fe;
277 hash = VHash(fid->Volume, fid->Unique);
278 for (fei=HashTable[hash]; fei; fei = fe->fnext) {
280 if (fe->volid == fid->Volume && fe->unique == fid->Unique &&
281 fe->vnode == fid->Vnode)
289 #ifndef INTERPRET_DUMP
291 extern void ShutDown();
292 static CDelPtr(), FDel(), AddCallback1(), GetSomeSpace_r();
294 static struct CallBack *iGetCB(register int *nused)
296 register struct CallBack *ret;
299 CBfree = (struct CallBack *)(((struct object *)ret)->next);
307 static iFreeCB(cb, nused)
308 register struct CallBack *cb;
312 ((struct object *)cb)->next = (struct object *)CBfree;
318 static struct FileEntry *iGetFE(register int *nused)
320 register struct FileEntry *ret;
323 FEfree = (struct FileEntry *)(((struct object *)ret)->next);
331 static iFreeFE(fe, nused)
332 register struct FileEntry *fe;
336 ((struct object *)fe)->next = (struct object *)FEfree;
342 /* Add cb to end of specified timeout list */
343 static TAdd(cb, thead)
344 register struct CallBack *cb;
345 register u_short *thead;
349 (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
351 register struct CallBack *thp = itocb(*thead);
353 cb->tprev = thp->tprev;
355 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
357 cb->thead = ttoi(thead);
362 /* Delete call back entry from timeout list */
364 register struct CallBack *cb;
367 register u_short *thead = itot(cb->thead);
369 if (*thead == cbtoi(cb))
370 *thead = (*thead == cb->tnext? 0: cb->tnext);
371 itocb(cb->tprev)->tnext = cb->tnext;
372 itocb(cb->tnext)->tprev = cb->tprev;
377 /* Add cb to end of specified host list */
378 static HAdd(cb, host)
379 register struct CallBack *cb;
380 register struct host *host;
383 cb->hhead = h_htoi(host);
385 host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
388 register struct CallBack *hhp = itocb(host->cblist);
390 cb->hprev = hhp->hprev;
391 cb->hnext = host->cblist;
392 hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
398 /* Delete call back entry from host list */
400 register struct CallBack *cb;
403 register u_short *hhead = &h_itoh(cb->hhead)->cblist;
405 if (*hhead == cbtoi(cb))
406 *hhead = (*hhead == cb->hnext? 0: cb->hnext);
407 itocb(cb->hprev)->hnext = cb->hnext;
408 itocb(cb->hnext)->hprev = cb->hprev;
413 /* Delete call back entry from fid's chain of cb's */
414 /* N.B. This one also deletes the CB, and also possibly parent FE, so
415 * make sure that it is not on any other list before calling this
422 struct FileEntry *fe = itofe(cb->fhead);
423 register u_short *cbp;
426 for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
427 cbp = &itocb(*cbp)->cnext, safety++) {
428 if (safety > cbstuff.nblks + 10) {
430 ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
440 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
441 * as well as file entry */
442 /* N.B. This one also deletes the CB, and also possibly parent FE, so
443 * make sure that it is not on any other list before calling this
445 int Ccdelpt=0, CcdelB=0;
447 static CDelPtr(fe, cbp)
448 register struct FileEntry *fe;
449 register u_short *cbp;
452 register struct CallBack *cb;
468 static u_short *FindCBPtr(fe, host)
469 struct FileEntry *fe;
473 register afs_uint32 hostindex = h_htoi(host);
474 register struct CallBack *cb;
475 register u_short *cbp;
478 for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
479 if (safety > cbstuff.nblks) {
480 ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
485 if (cb->hhead == hostindex)
494 /* Delete file entry from hash table */
496 register struct FileEntry *fe;
499 register int fei = fetoi(fe);
500 register unsigned short *p = &HashTable[VHash(fe->volid, fe->unique)];
502 while (*p && *p != fei)
503 p = &itofe(*p)->fnext;
517 tfirst = CBtime(FT_ApproxTime());
518 /* N.B. FE's, CB's share same free list. If the sizes of either change,
519 FE and CB will have to be separated. The "-1", below, is because
520 FE[0] and CB[0] are not used--and not allocated */
521 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*nblks)))-1;
522 cbstuff.nFEs = nblks;
524 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
525 CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
526 cbstuff.nCBs = nblks;
528 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
529 cbstuff.nblks = nblks;
530 cbstuff.nbreakers = 0;
536 afs_int32 XCallBackBulk_r(ahost, fids, nfids)
542 struct AFSCallBack tcbs[AFSCBMAX];
550 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
551 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
558 for(i=0;i<nfids && i < AFSCBMAX;i++) {
559 tcbs[i].CallBackVersion = CALLBACK_VERSION;
560 tcbs[i].ExpirationTime = 0;
561 tcbs[i].CallBackType = CB_DROPPED;
563 tf.AFSCBFids_len = i;
564 tf.AFSCBFids_val = &(fids[j]);
568 tc.AFSCBs_val = tcbs;
571 code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
579 /* the locked flag tells us if the host entry has already been locked
580 * by our parent. I don't think anybody actually calls us with the
581 * host locked, but here's how to make that work: GetSomeSpace has to
582 * change so that it doesn't attempt to lock any hosts < "host". That
583 * means that it might be unable to free any objects, so it has to
584 * return an exit status. If it fails, then AddCallBack1 might fail,
585 * as well. If so, the host->ResetDone should probably be set to 0,
586 * and we probably don't want to return a callback promise to the
587 * cache manager, either. */
589 AddCallBack1(host, fid, thead, type, locked)
601 retVal = AddCallBack1_r(host, fid, thead, type, 1);
611 AddCallBack1_r(host, fid, thead, type, locked)
618 struct FileEntry *fe;
619 struct CallBack *cb = 0, *lastcb = 0;
620 struct FileEntry *newfe = 0;
622 u_short *Thead = thead;
623 struct CallBack *newcb = 0;
628 /* allocate these guys first, since we can't call the allocator with
629 the host structure locked -- or we might deadlock. However, we have
630 to avoid races with FindFE... */
631 while (!(newcb = GetCB())) {
632 GetSomeSpace_r(host, locked);
634 while(!(newfe = GetFE())) { /* Get it now, so we don't have to call */
635 /* GetSomeSpace with the host locked, later. This might turn out to */
636 /* have been unneccessary, but that's actually kind of unlikely, since */
637 /* most files are not shared. */
638 GetSomeSpace_r(host, locked);
642 h_Lock_r(host); /* this can yield, so do it before we get any */
647 if (type == CB_NORMAL) {
648 time_out = TimeCeiling(FT_ApproxTime()+TimeOut(fe?fe->ncbs:0)+ServerBias);
649 Thead = THead(CBtime(time_out));
651 else if (type == CB_VOLUME) {
652 time_out = TimeCeiling((60*120+FT_ApproxTime())+ServerBias);
653 Thead = THead(CBtime(time_out));
655 else if (type == CB_BULK) {
656 /* bulk status can get so many callbacks all at once, and most of them
657 * are probably not for things that will be used for long.
659 time_out = TimeCeiling(FT_ApproxTime() + ServerBias
660 + TimeOut(22 + (fe?fe->ncbs:0)));
661 Thead = THead(CBtime(time_out));
667 register afs_uint32 hash;
670 newfe = (struct FileEntry *) 0;
672 fe->volid = fid->Volume;
673 fe->vnode = fid->Vnode;
674 fe->unique = fid->Unique;
676 hash = VHash(fid->Volume, fid->Unique);
677 fe->fnext = HashTable[hash];
678 HashTable[hash] = fetoi(fe);
680 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
681 lastcb = cb, cb = itocb(cb->cnext), safety++) {
682 if (safety > cbstuff.nblks) {
683 ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
687 if (cb->hhead == h_htoi(host))
690 if (cb) {/* Already have call back: move to new timeout list */
691 /* don't change delayed callbacks back to normal ones */
692 if (cb->status != CB_DELAYED)
694 /* Only move if new timeout is longer */
695 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
701 newcb = (struct CallBack *) 0;
702 *(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
705 cb->fhead = fetoi(fe);
711 /* now free any still-unused callback or host entries */
712 if (newcb) FreeCB(newcb);
713 if (newfe) FreeFE(newfe);
715 if (!locked) /* freecb and freefe might(?) yield */
718 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK )
719 return time_out-ServerBias; /* Expires sooner at workstation */
725 /* Take an array full of hosts, all held. Break callbacks to them, and
726 * release the holds once you're done, except don't release xhost. xhost
727 * may be NULL. Currently only works for a single Fid in afidp array.
728 * If you want to make this work with multiple fids, you need to fix
729 * the error handling. One approach would be to force a reset if a
730 * multi-fid call fails, or you could add delayed callbacks for each
731 * fid. You probably also need to sort and remove duplicate hosts.
732 * When this is called from the BreakVolumeCallBacks path, it does NOT
733 * force a reset if the RPC fails, it just marks the host down and tries
734 * to create a delayed callback. */
735 /* N.B. be sure that code works when ncbas == 0 */
736 /* N.B. requires all the cba[*].hp pointers to be valid... */
737 /* This routine does not hold a lock on the host for the duration of
738 * the BreakCallBack RPC, which is a significant deviation from tradition.
739 * It _does_ get a lock on the host before setting VenusDown = 1,
740 * which is sufficient only if VenusDown = 0 only happens when the
741 * lock is held over the RPC and the subsequent VenusDown == 0
742 * wherever that is done. */
743 static void MultiBreakCallBack_r(cba, ncbas, afidp, xhost)
744 struct cbstruct cba[];
746 struct AFSCBFids *afidp;
750 struct rx_connection *conns[MAX_CB_HOSTS];
751 int opt_TO; /* secs, but internal adaptive parms are in ms */
752 static struct AFSCBs tc = {0,0};
754 assert(ncbas <= MAX_CB_HOSTS);
756 /* set up conns for multi-call */
757 for (i=0,j=0; i<ncbas; i++) {
758 struct host *thishost = cba[i].hp;
759 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
762 conns[j++] = thishost->callback_rxcon;
765 rx_SetConnDeadTime (thishost->callback_rxcon, 4);
766 rx_SetConnHardDeadTime (thishost->callback_rxcon, AFS_HARDDEADTIME);
770 if (j) { /* who knows what multi would do with 0 conns? */
774 multi_RXAFSCB_CallBack(afidp, &tc);
779 /* If there's an error, we have to hunt for the right host.
780 * The conns array _should_ correspond one-to-one to the cba
781 * array, except in some rare cases it might be missing one
782 * or more elements. So the optimistic case is almost
783 * always right. At worst, it's the starting point for the
785 for (hp=0,i=multi_i;i<j;i++) {
786 hp = cba[i].hp; /* optimistic, but usually right */
790 if (conns[multi_i] == hp->callback_rxcon) {
797 ViceLog(0, ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n",hp,cba));
801 ** try breaking callbacks on alternate interface addresses
803 if ( MultiBreakCallBackAlternateAddress(hp, afidp) )
807 ("BCB: Failed on file %u.%d.%d, host %x.%d is down\n",
808 afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
809 afidp->AFSCBFids_val->Unique, hp->host, hp->port));
814 hp->hostFlags |= VENUSDOWN;
816 * We always go into AddCallBack1_r with the host locked
818 AddCallBack1_r(hp,afidp->AFSCBFids_val,itot(idx), CB_DELAYED, 1);
829 for (i=0; i<ncbas; i++) {
832 if (hp && xhost != hp)
840 * Break all call backs for fid, except for the specified host (unless flag
841 * is true, in which case all get a callback message. Assumption: the specified
842 * host is h_Held, by the caller; the others aren't.
843 * Specified host may be bogus, that's ok. This used to check to see if the
844 * host was down in two places, once right after the host was h_held, and
845 * again after it was locked. That race condition is incredibly rare and
846 * relatively harmless even when it does occur, so we don't check for it now.
848 BreakCallBack(xhost, fid, flag)
850 int flag; /* if flag is true, send a break callback msg to "host", too */
853 struct FileEntry *fe;
854 struct CallBack *cb, *nextcb;
855 struct cbstruct cba[MAX_CB_HOSTS];
857 struct rx_connection *conns[MAX_CB_HOSTS];
861 ViceLog(7,("BCB: BreakCallBack(all but %x.%d, (%u,%d,%d))\n",
862 xhost->host, xhost->port, fid->Volume, fid->Vnode,
867 cbstuff.BreakCallBacks++;
872 hostindex = h_htoi(xhost);
873 cb = itocb(fe->firstcb);
874 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
875 /* the most common case is what follows the || */
878 tf.AFSCBFids_len = 1;
879 tf.AFSCBFids_val = fid;
882 for (ncbas=0; cb && ncbas<MAX_CB_HOSTS; cb=nextcb) {
883 nextcb = itocb(cb->cnext);
884 if ((cb->hhead != hostindex || flag)
885 && (cb->status == CB_BULK || cb->status == CB_NORMAL
886 || cb->status == CB_VOLUME) ) {
887 struct host *thishost = h_itoh(cb->hhead);
889 ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
891 else if (thishost->hostFlags & VENUSDOWN) {
892 ViceLog(7,("BCB: %x.%d is down; delaying break call back\n",
893 thishost->host, thishost->port));
894 cb->status = CB_DELAYED;
898 cba[ncbas].hp = thishost;
899 cba[ncbas].thead = cb->thead;
903 CDel(cb); /* Usually first; so this delete */
904 /* is reasonably inexpensive */
910 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
912 /* we need to to all these initializations again because MultiBreakCallBack may block */
917 cb = itocb(fe->firstcb);
918 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
919 /* the most common case is what follows the || */
931 /* Delete (do not break) single call back for fid */
932 DeleteCallBack(host, fid)
937 register struct FileEntry *fe;
938 register u_short *pcb;
939 cbstuff.DeleteCallBacks++;
947 ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
948 fid->Volume, fid->Vnode, fid->Unique));
951 pcb = FindCBPtr(fe, host);
953 ViceLog(8,("DCB: No call back for host %x.%d, (%u, %d, %d)\n",
954 host->host, host->port, fid->Volume, fid->Vnode, fid->Unique));
969 * Delete (do not break) all call backs for fid. This call doesn't
970 * set all of the various host locks, but it shouldn't really matter
971 * since we're not adding callbacks, but deleting them. I'm not sure
972 * why it doesn't set the lock, however; perhaps it should.
974 DeleteFileCallBacks(fid)
977 register struct FileEntry *fe;
978 register struct CallBack *cb;
979 register afs_uint32 cbi;
983 cbstuff.DeleteFiles++;
987 ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
988 fid->Volume, fid->Vnode, fid->Unique));
991 for (n=0,cbi = fe->firstcb; cbi; n++) {
1001 } /*DeleteFileCallBacks*/
1004 /* Delete (do not break) all call backs for host. The host should be
1006 DeleteAllCallBacks(host)
1011 retVal = DeleteAllCallBacks_r(host);
1016 DeleteAllCallBacks_r(host)
1019 register struct CallBack *cb;
1020 register int cbi, first;
1022 cbstuff.DeleteAllCallBacks++;
1023 cbi = first = host->cblist;
1025 ViceLog(8,("DV: no call backs\n"));
1033 } while (cbi != first);
1036 } /*DeleteAllCallBacks*/
1040 * Break all delayed call backs for host. Returns 1 if all call backs
1041 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1042 * Must be called with VenusDown set for this host
1044 int BreakDelayedCallBacks(host)
1049 retVal = BreakDelayedCallBacks_r(host);
1054 extern afsUUID FS_HostUUID;
1056 int BreakDelayedCallBacks_r(host)
1059 struct AFSFid fids[AFSCBMAX];
1060 u_short thead[AFSCBMAX];
1061 int cbi, first, nfids;
1062 struct CallBack *cb;
1063 struct interfaceAddr interf;
1066 cbstuff.nbreakers++;
1067 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1068 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1069 if ( host->interface ) {
1071 code = RXAFSCB_InitCallBackState3(host->callback_rxcon,
1076 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1079 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1083 ("CB: Call back connect back failed (in break delayed) for %x.%d\n",
1084 host->host, host->port));
1086 host->hostFlags |= VENUSDOWN;
1089 ViceLog(25,("InitCallBackState success on %x\n",host->host));
1090 /* reset was done successfully */
1091 host->hostFlags |= RESETDONE;
1092 host->hostFlags &= ~VENUSDOWN;
1095 else while (!(host->hostFlags & HOSTDELETED)) {
1097 host->hostFlags &= ~VENUSDOWN; /* presume up */
1098 cbi = first = host->cblist;
1102 first = host->cblist;
1105 if (cb->status == CB_DELAYED) {
1106 register struct FileEntry *fe = itofe(cb->fhead);
1107 thead[nfids] = cb->thead;
1108 fids[nfids].Volume = fe->volid;
1109 fids[nfids].Vnode = fe->vnode;
1110 fids[nfids].Unique = fe->unique;
1116 } while (cbi && cbi != first && nfids < AFSCBMAX);
1122 if (XCallBackBulk_r(host, fids, nfids)) {
1123 /* Failed, again: put them back, probably with old
1128 ("CB: XCallBackBulk failed, host=%x.%d; callback list follows:\n",
1129 host->host, host->port));
1131 for (i = 0; i<nfids; i++) {
1134 ("CB: Host %x.%d, file %u.%u.%u (part of bulk callback)\n",
1135 host->host, host->port,
1136 fids[i].Volume, fids[i].Vnode, fids[i].Unique));
1139 AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1140 * but it turns out to cause too many tricky locking problems.
1141 * now, if break delayed fails, screw it. */
1143 host->hostFlags |= VENUSDOWN; /* Failed */
1144 ClearHostCallbacks_r(host, 1/* locked */);
1148 if (nfids < AFSCBMAX)
1152 cbstuff.nbreakers--;
1153 return (host->hostFlags & VENUSDOWN);
1155 } /*BreakDelayedCallBacks*/
1159 struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
1161 unsigned short thead; /* head of timeout queue for youngest callback */
1166 ** isheld is 0 if the host is held in h_Enumerate
1167 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1169 static int MultiBreakVolumeCallBack_r (host, isheld, parms)
1172 struct VCBParams *parms;
1175 return isheld; /* host is held only by h_Enumerate, do nothing */
1176 if ( host->hostFlags & HOSTDELETED )
1177 return 0; /* host is deleted, release hold */
1179 if (host->hostFlags & VENUSDOWN) {
1181 if (host->hostFlags & HOSTDELETED) {
1183 return 0; /* Release hold */
1185 ViceLog(8,("BVCB: volume call back for host %x.%d failed\n",
1186 host->host,host->port));
1188 ViceLog(0, ("CB: volume callback for host %x.%d failed\n",
1189 host->host, host->port));
1191 DeleteAllCallBacks_r(host); /* Delete all callback state rather than
1192 attempting to selectively remember to
1193 delete the volume callbacks later */
1194 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1196 return 0; /* release hold */
1198 assert(parms->ncbas <= MAX_CB_HOSTS);
1200 /* Do not call MultiBreakCallBack on the current host structure
1201 ** because it would prematurely release the hold on the host
1203 if ( parms->ncbas == MAX_CB_HOSTS ) {
1204 struct AFSCBFids tf;
1206 tf.AFSCBFids_len = 1;
1207 tf.AFSCBFids_val = parms->fid;
1209 /* this releases all the hosts */
1210 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */);
1214 parms->cba[parms->ncbas].hp = host;
1215 parms->cba[(parms->ncbas)++].thead = parms->thead;
1216 return 1; /* DON'T release hold, because we still need it. */
1220 ** isheld is 0 if the host is held in h_Enumerate
1221 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1223 static int MultiBreakVolumeCallBack (host, isheld, parms)
1226 struct VCBParams *parms;
1230 retval = MultiBreakVolumeCallBack_r(host, isheld, parms);
1236 * Break all call backs on a single volume. Don't call this with any
1237 * hosts h_held. Note that this routine clears the callbacks before
1238 * actually breaking them, and that the vnode isn't locked during this
1239 * operation, so that people might see temporary callback loss while
1240 * this function is executing. It is just a temporary state, however,
1241 * since the callback will be broken later by this same function.
1243 * Now uses multi-RX for CallBack RPC. Note that the
1244 * multiBreakCallBacks routine does not force a reset if the RPC
1245 * fails, unlike the previous version of this routine, but does create
1246 * a delayed callback. Resets will be forced if the host is
1247 * determined to be down before the RPC is executed.
1249 BreakVolumeCallBacks(volume)
1256 struct CallBack *cb;
1257 struct FileEntry *fe;
1259 struct VCBParams henumParms;
1260 unsigned short tthead = 0; /* zero is illegal value */
1263 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1264 for (hash=0; hash<VHASH; hash++) {
1265 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1266 if (fe->volid == volume) {
1267 register struct CallBack *cbnext;
1268 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1269 host = h_itoh(cb->hhead);
1271 cbnext = itocb(cb->cnext);
1272 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1278 /* leave hold for MultiBreakVolumeCallBack to clear */
1289 /* didn't find any callbacks, so return right away. */
1293 henumParms.ncbas = 0;
1294 henumParms.fid = &fid;
1295 henumParms.thead = tthead;
1297 h_Enumerate(MultiBreakVolumeCallBack, (char *) &henumParms);
1300 if (henumParms.ncbas) { /* do left-overs */
1301 struct AFSCBFids tf;
1302 tf.AFSCBFids_len = 1;
1303 tf.AFSCBFids_val = &fid;
1305 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1307 henumParms.ncbas = 0;
1312 } /*BreakVolumeCallBacks*/
1316 * Delete all timed-out call back entries (to be called periodically by file
1319 CleanupTimedOutCallBacks()
1322 CleanupTimedOutCallBacks_r();
1326 CleanupTimedOutCallBacks_r()
1328 afs_uint32 now = CBtime(FT_ApproxTime());
1329 register u_short *thead;
1330 register struct CallBack *cb;
1331 register int ntimedout = 0;
1332 extern void ShutDown();
1334 while (tfirst <= now) {
1336 cbi = *(thead = THead(tfirst));
1341 ViceLog(8,("CCB: deleting timed out call back %x.%d, (%u,%u,%u)\n",
1342 h_itoh(cb->hhead)->host, h_itoh(cb->hhead)->port,
1343 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1344 itofe(cb->fhead)->unique));
1348 if (ntimedout > cbstuff.nblks) {
1349 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1350 DumpCallBackState();
1353 } while (cbi != *thead);
1358 cbstuff.CBsTimedOut += ntimedout;
1359 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1360 return (ntimedout > 0);
1362 } /*CleanupTimedOutCallBacks*/
1365 static struct host *lih_host;
1367 static int lih_r(host, held, hostp)
1368 register struct host *host, *hostp;
1373 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1374 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1382 /* This could be upgraded to get more space each time */
1383 /* first pass: find the oldest host which isn't held by anyone */
1384 /* second pass: find the oldest host who isn't "me" */
1385 /* always called with hostp unlocked */
1386 static int GetSomeSpace_r(hostp, locked)
1390 register struct host *hp, *hp1 = (struct host *)0;
1393 cbstuff.GotSomeSpaces++;
1394 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1395 if (CleanupTimedOutCallBacks_r()) {
1401 h_Enumerate_r(lih_r, (char *)hp1);
1405 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1410 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1412 * Next time try getting callbacks from any host even if
1413 * it's deleted (that's actually great since we can freely
1414 * remove its callbacks) or it's held since the only other
1415 * option is starvation for the file server (i.e. until the
1416 * callback timeout arrives).
1422 * No choice to clear this host's callback state
1424 /* third pass: we still haven't gotten any space, so we free what we had
1425 * previously passed over. */
1430 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1437 ClearHostCallbacks(hp, locked)
1439 int locked; /* set if caller has already locked the host */
1443 retVal = ClearHostCallbacks_r(hp, locked);
1448 int ClearHostCallbacks_r(hp, locked)
1450 int locked; /* set if caller has already locked the host */
1452 struct interfaceAddr interf;
1456 ViceLog(5,("GSS: Delete longest inactive host %x\n", hp->host));
1457 if ( !(held = h_Held_r(hp)) )
1460 /** Try a non-blocking lock. If the lock is already held return
1461 * after releasing hold on hp
1464 if ( h_NBLock_r(hp) ) {
1470 if (hp->Console & 2) {
1472 * If the special console field is set it means that a thread
1473 * is waiting in AddCallBack1 after it set pointers to the
1474 * file entry and/or callback entry. Because of the bogus
1475 * usage of h_hold it won't prevent from another thread, this
1476 * one, to remove all the callbacks so just to be safe we keep
1477 * a reference. NOTE, on the last phase we'll free the calling
1478 * host's callbacks but that's ok...
1482 DeleteAllCallBacks_r(hp);
1483 if (hp->hostFlags & VENUSDOWN) {
1484 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1486 /* host is up, try a call */
1487 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1488 if (hp->interface) {
1490 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1494 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1497 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1500 /* failed, mark host down and need reset */
1501 hp->hostFlags |= VENUSDOWN;
1502 hp->hostFlags &= ~RESETDONE;
1504 /* reset succeeded, we're done */
1505 hp->hostFlags |= RESETDONE;
1516 #endif /* INTERPRET_DUMP */
1519 PrintCallBackStats()
1522 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",
1523 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1524 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1525 cbstuff.DeleteAllCallBacks);
1526 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1527 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1529 } /*PrintCallBackStats*/
1532 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1534 #ifndef INTERPRET_DUMP
1541 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1543 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1545 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1548 write(fd, &magic, sizeof(magic));
1549 write(fd, &now, sizeof(now));
1550 write(fd, &cbstuff, sizeof(cbstuff));
1551 write(fd, TimeOuts, sizeof(TimeOuts));
1552 write(fd, timeout, sizeof(timeout));
1553 write(fd, &tfirst, sizeof(tfirst));
1554 freelisthead = cbtoi((struct CallBack *) CBfree);
1555 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1556 freelisthead = fetoi((struct FileEntry *) FEfree);
1557 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1558 write(fd, HashTable, sizeof(HashTable));
1559 write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1560 write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1563 } /*DumpCallBackState*/
1567 #ifdef INTERPRET_DUMP
1569 /* This is only compiled in for the callback analyzer program */
1570 /* Returns the time of the dump */
1571 time_t ReadDump(file)
1576 afs_uint32 magic, freelisthead;
1579 fd = open(file, O_RDONLY);
1581 fprintf(stderr, "Couldn't read dump file %s\n", file);
1584 read(fd, &magic, sizeof(magic));
1585 if (magic != MAGIC) {
1586 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1589 "run this program on a machine type with a different byte ordering.\n");
1592 read(fd, &now, sizeof(now));
1593 read(fd, &cbstuff, sizeof(cbstuff));
1594 read(fd, TimeOuts, sizeof(TimeOuts));
1595 read(fd, timeout, sizeof(timeout));
1596 read(fd, &tfirst, sizeof(tfirst));
1597 read(fd, &freelisthead, sizeof(freelisthead));
1598 CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1599 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1600 CBfree = (struct CallBack *) itocb(freelisthead);
1601 read(fd, &freelisthead, sizeof(freelisthead));
1602 FEfree = (struct FileEntry *) itofe(freelisthead);
1603 read(fd, HashTable, sizeof(HashTable));
1604 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1605 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1607 perror("Error reading dumpfile");
1615 #include "AFS_component_version_number.c"
1622 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1624 register struct FileEntry *fe;
1625 register struct CallBack *cb;
1628 bzero(&fid, sizeof(fid));
1630 while (argc && **argv == '-') {
1633 if (!strcmp(*argv, "-host")) {
1639 cbi = atoi(*++argv);
1641 else if (!strcmp(*argv, "-fid")) {
1647 fid.Volume = atoi(*++argv);
1648 fid.Vnode = atoi(*++argv);
1649 fid.Unique = atoi(*++argv);
1651 else if (!strcmp(*argv, "-time")) {
1652 fprintf(stderr, "-time not supported\n");
1655 else if (!strcmp(*argv, "-stats")) {
1658 else if (!strcmp(*argv, "-all")) {
1661 else if (!strcmp(*argv, "-raw")) {
1664 else if (!strcmp(*argv, "-volume")) {
1670 vol = atoi(*++argv);
1675 if (err || argc != 1) {
1677 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1678 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1681 now = ReadDump(*argv);
1682 if (stats || noptions == 0) {
1683 time_t uxtfirst = UXtime(tfirst);
1684 printf("The time of the dump was %u %s", now, ctime(&now));
1685 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1686 PrintCallBackStats();
1690 register u_short *feip;
1691 register struct CallBack *cb;
1692 register struct FileEntry *fe;
1694 for (hash=0; hash<VHASH; hash++) {
1695 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1696 if (!vol || (fe->volid == vol)) {
1697 register struct CallBack *cbnext;
1698 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1700 cbnext = itocb(cb->cnext);
1710 u_short cfirst = cbi;
1715 } while (cbi != cfirst);
1720 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1723 cb = itocb(fe->firstcb);
1726 cb = itocb(cb->cnext);
1730 struct FileEntry *fe;
1732 for (i=1; i < cbstuff.nblks; i++) {
1733 p = (afs_int32 *) &FE[i];
1734 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1740 register struct CallBack *cb;
1744 struct FileEntry *fe = itofe(cb->fhead);
1745 time_t expires = TIndexToTime(cb->thead);
1747 printf("vol=%u vn=%u cbs=%d hi=%d st=%d, exp in %d secs at %s",
1748 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1749 expires - now, ctime(&expires));
1756 #if !defined(INTERPRET_DUMP)
1758 ** try breaking calbacks on afidp from host. Use multi_rx.
1759 ** return 0 on success, non-zero on failure
1762 MultiBreakCallBackAlternateAddress(host, afidp)
1764 struct AFSCBFids* afidp;
1768 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1774 MultiBreakCallBackAlternateAddress_r(host, afidp)
1776 struct AFSCBFids* afidp;
1779 struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
1780 struct rx_connection* connSuccess = 0;
1781 afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
1782 static struct rx_securityClass *sc = 0;
1783 static struct AFSCBs tc = {0,0};
1785 /* nothing more can be done */
1786 if ( !host->interface ) return 1; /* failure */
1788 assert(host->interface->numberOfInterfaces > 0 );
1790 /* the only address is the primary interface */
1791 if ( host->interface->numberOfInterfaces == 1 )
1792 return 1; /* failure */
1794 /* initialise a security object only once */
1796 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
1798 /* initialize alternate rx connections */
1799 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1801 /* this is the current primary address */
1802 if ( host->host == host->interface->addr[i] )
1805 addr[j] = host->interface->addr[i];
1806 conns[j] = rx_NewConnection (host->interface->addr[i],
1807 host->port, 1, sc, 0);
1808 rx_SetConnDeadTime(conns[j], 2);
1809 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1813 assert(j); /* at least one alternate address */
1814 ViceLog(125,("Starting multibreakcall back on all addr for host:%x\n",
1819 multi_RXAFSCB_CallBack(afidp, &tc);
1824 if ( host->callback_rxcon )
1825 rx_DestroyConnection(host->callback_rxcon);
1826 host->callback_rxcon = conns[multi_i];
1827 host->host = addr[multi_i];
1828 connSuccess = conns[multi_i];
1829 rx_SetConnDeadTime(host->callback_rxcon, 50);
1830 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1831 ViceLog(125,("multibreakcall success with addr:%x\n",
1839 /* Destroy all connections except the one on which we succeeded */
1840 for ( i=0; i < j; i++)
1841 if ( conns[i] != connSuccess )
1842 rx_DestroyConnection(conns[i] );
1844 if ( connSuccess ) return 0; /* success */
1845 else return 1; /* failure */
1850 ** try multiRX probes to host.
1851 ** return 0 on success, non-zero on failure
1854 MultiProbeAlternateAddress_r(host)
1858 struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
1859 struct rx_connection* connSuccess = 0;
1860 afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
1861 static struct rx_securityClass *sc = 0;
1863 /* nothing more can be done */
1864 if ( !host->interface ) return 1; /* failure */
1866 assert(host->interface->numberOfInterfaces > 0 );
1868 /* the only address is the primary interface */
1869 if ( host->interface->numberOfInterfaces == 1 )
1870 return 1; /* failure */
1872 /* initialise a security object only once */
1874 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
1876 /* initialize alternate rx connections */
1877 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1879 /* this is the current primary address */
1880 if ( host->host == host->interface->addr[i] )
1883 addr[j] = host->interface->addr[i];
1884 conns[j] = rx_NewConnection (host->interface->addr[i],
1885 host->port, 1, sc, 0);
1886 rx_SetConnDeadTime(conns[j], 2);
1887 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1891 assert(j); /* at least one alternate address */
1892 ViceLog(125,("Starting multiprobe on all addr for host:%x\n",
1897 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
1902 if ( host->callback_rxcon )
1903 rx_DestroyConnection(host->callback_rxcon);
1904 host->callback_rxcon = conns[multi_i];
1905 host->host = addr[multi_i];
1906 connSuccess = conns[multi_i];
1907 rx_SetConnDeadTime(host->callback_rxcon, 50);
1908 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1909 ViceLog(125,("multiprobe success with addr:%x\n",
1917 /* Destroy all connections except the one on which we succeeded */
1918 for ( i=0; i < j; i++)
1919 if ( conns[i] != connSuccess )
1920 rx_DestroyConnection(conns[i] );
1922 if ( connSuccess ) return 0; /* success */
1923 else return 1; /* failure */
1926 #endif /* !defined(INTERPRET_DUMP) */