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 <afs/param.h>
84 #include <stdlib.h> /* for malloc() */
85 #include <time.h> /* ANSI standard location for time stuff */
93 #include <afs/assert.h>
97 #include <afs/nfs.h> /* yuck. This is an abomination. */
100 #include <afs/afscbint.h>
101 #include <afs/afsutil.h>
103 #include <afs/ihandle.h>
104 #include <afs/vnode.h>
105 #include <afs/volume.h>
108 #include <afs/ptclient.h> /* need definition of prlist for host.h */
112 extern int hostCount;
113 int ShowProblems = 1;
115 /* Maximum number of call backs to break at once, single fid */
116 /* There is some debate as to just how large this value should be */
117 /* Ideally, it would be very very large, but I am afraid that the */
118 /* cache managers will all send in their responses simultaneously, */
119 /* thereby swamping the file server. As a result, something like */
120 /* 10 or 15 might be a better bet. */
121 #define MAX_CB_HOSTS 10
123 /* max time to break a callback, otherwise client is dead or net is hosed */
126 #define u_short unsigned short
127 #define u_byte unsigned char
129 struct cbcounters cbstuff;
137 afs_uint32 vnode; /* XXX This was u_short XXX */
144 #if defined(AFS_ALPHA_ENV) || defined(AFS_ALPHA_LINUX20_ENV)
148 } *FE; /* Don't use FE[0] */
151 u_short cnext; /* Next call back entry */
152 u_short fhead; /* Head of this call back chain */
153 u_byte thead; /* Head of timeout chain */
154 u_byte status; /* Call back status; see definitions, below */
155 u_short hhead; /* Head of host table chain */
156 u_short tprev, tnext; /* Timeout chain */
157 u_short hprev, hnext; /* Chain from host table */
158 } *CB; /* Don't use CB[0] */
160 /* status bits for status field of CallBack structure */
161 #define CB_NORMAL 1 /* Normal call back */
162 #define CB_DELAYED 2 /* Delayed call back due to rpc problems.
163 The call back entry will be added back to the
164 host list at the END of the list, so that
165 searching backwards in the list will find all
166 the (consecutive)host. delayed call back entries */
167 #define CB_VOLUME 3 /* Callback for a volume */
168 #define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
170 /* call back indices to pointers, and vice-versa */
171 #define itocb(i) ((i)?CB+(i):0)
172 #define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
174 /* file entry indices to pointers, and vice-versa */
175 #define itofe(i) ((i)?FE+(i):0)
176 #define fetoi(fep) (!(fep)?0:(fep)-FE)
178 /* Timeouts: there are 128 possible timeout values in effect at any
179 * given time. Each timeout represents timeouts in an interval of 128
180 * seconds. So the maximum timeout for a call back is 128*128=16384
181 * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
182 * if space runs out or by the file server every 5 minutes. This 5
183 * minute slack should be allowed for--so a maximum time of 4 hours
186 * Timeouts must be chosen to correspond to an exact multiple
187 * of 128, because all times are truncated to a 128 multiple, and
188 * timed out if the current truncated time is <= to the truncated time
189 * corresponding to the timeout queue.
192 /* Unix time to Call Back time, and vice-versa. Call back time is
193 in units of 128 seconds, corresponding to time queues. */
194 #define CBtime(uxtime) ((uxtime)>>7)
195 #define UXtime(cbtime) ((cbtime)<<7)
197 /* Given a Unix time, compute the closest Unix time that corresponds to
198 a time queue, rounding up */
199 #define TimeCeiling(uxtime) (((uxtime)+127)&~127)
201 /* Time to live for call backs depends upon number of users of the file.
202 * TimeOuts is indexed by this number/8 (using TimeOut macro). Times
203 * in this table are for the workstation; server timeouts, add
206 static int TimeOuts[] = {
207 /* Note: don't make the first entry larger than 4 hours (see above) */
208 4*60*60, /* 0-7 users */
209 1*60*60, /* 8-15 users */
210 30*60, /* 16-23 users */
211 15*60, /* 24-31 users */
212 15*60, /* 32-39 users */
213 10*60, /* 40-47 users */
214 10*60, /* 48-55 users */
215 10*60, /* 56-63 users */
216 }; /* Anything more: MinTimeOut */
218 /* minimum time given for a call back */
219 static int MinTimeOut = (7*60);
221 #define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
222 #define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
224 /* time out at server is 3 minutes more than ws */
225 #define ServerBias (3*60)
227 /* Heads of CB queues; a timeout index is 1+index into this array */
228 static u_short timeout[128];
230 /* Convert cbtime to timeout queue index */
231 #define TIndex(cbtime) (((cbtime)&127)+1)
233 /* Convert cbtime to pointer to timeout queue head */
234 #define THead(cbtime) (&timeout[TIndex(cbtime)-1])
236 static afs_int32 tfirst; /* cbtime of oldest unexpired call back time queue */
238 /* Normalize index into timeout array so that two such indices will be
239 ordered correctly, so that they can be compared to see which times
240 sooner, or so that the difference in time out times between them
242 #define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
244 /* This converts a timeout index into the actual time it will expire */
245 #define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
248 /* Convert pointer to timeout queue head to index, and vice versa */
249 #define ttoi(t) ((t-timeout)+1)
250 #define itot(i) ((timeout)+(i-1))
252 /* 16 byte object get/free routines */
257 struct CallBack *CBfree = 0;
258 struct FileEntry *FEfree = 0;
260 static struct CallBack *iGetCB(register int *nused);
261 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
262 static struct FileEntry *iGetFE(register int *nused);
263 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
264 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
265 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
267 #define VHASH 512 /* Power of 2 */
268 static u_short HashTable[VHASH]; /* File entry hash table */
269 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
271 static struct FileEntry *FindFE (fid)
272 register AFSFid *fid;
277 register struct FileEntry *fe;
279 hash = VHash(fid->Volume, fid->Unique);
280 for (fei=HashTable[hash]; fei; fei = fe->fnext) {
282 if (fe->volid == fid->Volume && fe->unique == fid->Unique &&
283 fe->vnode == fid->Vnode)
291 #ifndef INTERPRET_DUMP
293 extern void ShutDown();
294 static CDelPtr(), FDel(), AddCallback1(), GetSomeSpace_r();
296 static struct CallBack *iGetCB(register int *nused)
298 register struct CallBack *ret;
301 CBfree = (struct CallBack *)(((struct object *)ret)->next);
309 static iFreeCB(cb, nused)
310 register struct CallBack *cb;
314 ((struct object *)cb)->next = (struct object *)CBfree;
320 static struct FileEntry *iGetFE(register int *nused)
322 register struct FileEntry *ret;
325 FEfree = (struct FileEntry *)(((struct object *)ret)->next);
333 static iFreeFE(fe, nused)
334 register struct FileEntry *fe;
338 ((struct object *)fe)->next = (struct object *)FEfree;
344 /* Add cb to end of specified timeout list */
345 static TAdd(cb, thead)
346 register struct CallBack *cb;
347 register u_short *thead;
351 (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
353 register struct CallBack *thp = itocb(*thead);
355 cb->tprev = thp->tprev;
357 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
359 cb->thead = ttoi(thead);
364 /* Delete call back entry from timeout list */
366 register struct CallBack *cb;
369 register u_short *thead = itot(cb->thead);
371 if (*thead == cbtoi(cb))
372 *thead = (*thead == cb->tnext? 0: cb->tnext);
373 itocb(cb->tprev)->tnext = cb->tnext;
374 itocb(cb->tnext)->tprev = cb->tprev;
379 /* Add cb to end of specified host list */
380 static HAdd(cb, host)
381 register struct CallBack *cb;
382 register struct host *host;
385 cb->hhead = h_htoi(host);
387 host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
390 register struct CallBack *hhp = itocb(host->cblist);
392 cb->hprev = hhp->hprev;
393 cb->hnext = host->cblist;
394 hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
400 /* Delete call back entry from host list */
402 register struct CallBack *cb;
405 register u_short *hhead = &h_itoh(cb->hhead)->cblist;
407 if (*hhead == cbtoi(cb))
408 *hhead = (*hhead == cb->hnext? 0: cb->hnext);
409 itocb(cb->hprev)->hnext = cb->hnext;
410 itocb(cb->hnext)->hprev = cb->hprev;
415 /* Delete call back entry from fid's chain of cb's */
416 /* N.B. This one also deletes the CB, and also possibly parent FE, so
417 * make sure that it is not on any other list before calling this
424 struct FileEntry *fe = itofe(cb->fhead);
425 register u_short *cbp;
428 for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
429 cbp = &itocb(*cbp)->cnext, safety++) {
430 if (safety > cbstuff.nblks + 10) {
432 ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
442 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
443 * as well as file entry */
444 /* N.B. This one also deletes the CB, and also possibly parent FE, so
445 * make sure that it is not on any other list before calling this
447 int Ccdelpt=0, CcdelB=0;
449 static CDelPtr(fe, cbp)
450 register struct FileEntry *fe;
451 register u_short *cbp;
454 register struct CallBack *cb;
470 static u_short *FindCBPtr(fe, host)
471 struct FileEntry *fe;
475 register afs_uint32 hostindex = h_htoi(host);
476 register struct CallBack *cb;
477 register u_short *cbp;
480 for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
481 if (safety > cbstuff.nblks) {
482 ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
487 if (cb->hhead == hostindex)
496 /* Delete file entry from hash table */
498 register struct FileEntry *fe;
501 register int fei = fetoi(fe);
502 register unsigned short *p = &HashTable[VHash(fe->volid, fe->unique)];
504 while (*p && *p != fei)
505 p = &itofe(*p)->fnext;
519 tfirst = CBtime(FT_ApproxTime());
520 /* N.B. FE's, CB's share same free list. If the sizes of either change,
521 FE and CB will have to be separated. The "-1", below, is because
522 FE[0] and CB[0] are not used--and not allocated */
523 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*nblks)))-1;
524 cbstuff.nFEs = nblks;
526 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
527 CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
528 cbstuff.nCBs = nblks;
530 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
531 cbstuff.nblks = nblks;
532 cbstuff.nbreakers = 0;
538 afs_int32 XCallBackBulk_r(ahost, fids, nfids)
544 struct AFSCallBack tcbs[AFSCBMAX];
552 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
553 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
560 for(i=0;i<nfids && i < AFSCBMAX;i++) {
561 tcbs[i].CallBackVersion = CALLBACK_VERSION;
562 tcbs[i].ExpirationTime = 0;
563 tcbs[i].CallBackType = CB_DROPPED;
565 tf.AFSCBFids_len = i;
566 tf.AFSCBFids_val = &(fids[j]);
570 tc.AFSCBs_val = tcbs;
573 code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
581 /* the locked flag tells us if the host entry has already been locked
582 * by our parent. I don't think anybody actually calls us with the
583 * host locked, but here's how to make that work: GetSomeSpace has to
584 * change so that it doesn't attempt to lock any hosts < "host". That
585 * means that it might be unable to free any objects, so it has to
586 * return an exit status. If it fails, then AddCallBack1 might fail,
587 * as well. If so, the host->ResetDone should probably be set to 0,
588 * and we probably don't want to return a callback promise to the
589 * cache manager, either. */
591 AddCallBack1(host, fid, thead, type, locked)
603 retVal = AddCallBack1_r(host, fid, thead, type, 1);
613 AddCallBack1_r(host, fid, thead, type, locked)
620 struct FileEntry *fe;
621 struct CallBack *cb = 0, *lastcb = 0;
622 struct FileEntry *newfe = 0;
624 u_short *Thead = thead;
625 struct CallBack *newcb = 0;
630 /* allocate these guys first, since we can't call the allocator with
631 the host structure locked -- or we might deadlock. However, we have
632 to avoid races with FindFE... */
633 while (!(newcb = GetCB())) {
634 GetSomeSpace_r(host, locked);
636 while(!(newfe = GetFE())) { /* Get it now, so we don't have to call */
637 /* GetSomeSpace with the host locked, later. This might turn out to */
638 /* have been unneccessary, but that's actually kind of unlikely, since */
639 /* most files are not shared. */
640 GetSomeSpace_r(host, locked);
644 h_Lock_r(host); /* this can yield, so do it before we get any */
649 if (type == CB_NORMAL) {
650 time_out = TimeCeiling(FT_ApproxTime()+TimeOut(fe?fe->ncbs:0)+ServerBias);
651 Thead = THead(CBtime(time_out));
653 else if (type == CB_VOLUME) {
654 time_out = TimeCeiling((60*120+FT_ApproxTime())+ServerBias);
655 Thead = THead(CBtime(time_out));
657 else if (type == CB_BULK) {
658 /* bulk status can get so many callbacks all at once, and most of them
659 * are probably not for things that will be used for long.
661 time_out = TimeCeiling(FT_ApproxTime() + ServerBias
662 + TimeOut(22 + (fe?fe->ncbs:0)));
663 Thead = THead(CBtime(time_out));
669 register afs_uint32 hash;
672 newfe = (struct FileEntry *) 0;
674 fe->volid = fid->Volume;
675 fe->vnode = fid->Vnode;
676 fe->unique = fid->Unique;
678 hash = VHash(fid->Volume, fid->Unique);
679 fe->fnext = HashTable[hash];
680 HashTable[hash] = fetoi(fe);
682 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
683 lastcb = cb, cb = itocb(cb->cnext), safety++) {
684 if (safety > cbstuff.nblks) {
685 ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
689 if (cb->hhead == h_htoi(host))
692 if (cb) {/* Already have call back: move to new timeout list */
693 /* don't change delayed callbacks back to normal ones */
694 if (cb->status != CB_DELAYED)
696 /* Only move if new timeout is longer */
697 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
703 newcb = (struct CallBack *) 0;
704 *(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
707 cb->fhead = fetoi(fe);
713 /* now free any still-unused callback or host entries */
714 if (newcb) FreeCB(newcb);
715 if (newfe) FreeFE(newfe);
717 if (!locked) /* freecb and freefe might(?) yield */
720 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK )
721 return time_out-ServerBias; /* Expires sooner at workstation */
727 /* Take an array full of hosts, all held. Break callbacks to them, and
728 * release the holds once you're done, except don't release xhost. xhost
729 * may be NULL. Currently only works for a single Fid in afidp array.
730 * If you want to make this work with multiple fids, you need to fix
731 * the error handling. One approach would be to force a reset if a
732 * multi-fid call fails, or you could add delayed callbacks for each
733 * fid. You probably also need to sort and remove duplicate hosts.
734 * When this is called from the BreakVolumeCallBacks path, it does NOT
735 * force a reset if the RPC fails, it just marks the host down and tries
736 * to create a delayed callback. */
737 /* N.B. be sure that code works when ncbas == 0 */
738 /* N.B. requires all the cba[*].hp pointers to be valid... */
739 /* This routine does not hold a lock on the host for the duration of
740 * the BreakCallBack RPC, which is a significant deviation from tradition.
741 * It _does_ get a lock on the host before setting VenusDown = 1,
742 * which is sufficient only if VenusDown = 0 only happens when the
743 * lock is held over the RPC and the subsequent VenusDown == 0
744 * wherever that is done. */
745 static void MultiBreakCallBack_r(cba, ncbas, afidp, xhost)
746 struct cbstruct cba[];
748 struct AFSCBFids *afidp;
752 struct rx_connection *conns[MAX_CB_HOSTS];
753 int opt_TO; /* secs, but internal adaptive parms are in ms */
754 static struct AFSCBs tc = {0,0};
756 assert(ncbas <= MAX_CB_HOSTS);
758 /* set up conns for multi-call */
759 for (i=0,j=0; i<ncbas; i++) {
760 struct host *thishost = cba[i].hp;
761 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
764 conns[j++] = thishost->callback_rxcon;
767 rx_SetConnDeadTime (thishost->callback_rxcon, 4);
768 rx_SetConnHardDeadTime (thishost->callback_rxcon, AFS_HARDDEADTIME);
772 if (j) { /* who knows what multi would do with 0 conns? */
776 multi_RXAFSCB_CallBack(afidp, &tc);
781 /* If there's an error, we have to hunt for the right host.
782 * The conns array _should_ correspond one-to-one to the cba
783 * array, except in some rare cases it might be missing one
784 * or more elements. So the optimistic case is almost
785 * always right. At worst, it's the starting point for the
787 for (hp=0,i=multi_i;i<j;i++) {
788 hp = cba[i].hp; /* optimistic, but usually right */
792 if (conns[multi_i] == hp->callback_rxcon) {
799 ViceLog(0, ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n",hp,cba));
803 ** try breaking callbacks on alternate interface addresses
805 if ( MultiBreakCallBackAlternateAddress(hp, afidp) )
809 ("BCB: Failed on file %u.%d.%d, host %x.%d is down\n",
810 afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
811 afidp->AFSCBFids_val->Unique, hp->host, hp->port));
816 hp->hostFlags |= VENUSDOWN;
818 * We always go into AddCallBack1_r with the host locked
820 AddCallBack1_r(hp,afidp->AFSCBFids_val,itot(idx), CB_DELAYED, 1);
831 for (i=0; i<ncbas; i++) {
834 if (hp && xhost != hp)
842 * Break all call backs for fid, except for the specified host (unless flag
843 * is true, in which case all get a callback message. Assumption: the specified
844 * host is h_Held, by the caller; the others aren't.
845 * Specified host may be bogus, that's ok. This used to check to see if the
846 * host was down in two places, once right after the host was h_held, and
847 * again after it was locked. That race condition is incredibly rare and
848 * relatively harmless even when it does occur, so we don't check for it now.
850 BreakCallBack(xhost, fid, flag)
852 int flag; /* if flag is true, send a break callback msg to "host", too */
855 struct FileEntry *fe;
856 struct CallBack *cb, *nextcb;
857 struct cbstruct cba[MAX_CB_HOSTS];
859 struct rx_connection *conns[MAX_CB_HOSTS];
863 ViceLog(7,("BCB: BreakCallBack(all but %x.%d, (%u,%d,%d))\n",
864 xhost->host, xhost->port, fid->Volume, fid->Vnode,
869 cbstuff.BreakCallBacks++;
874 hostindex = h_htoi(xhost);
875 cb = itocb(fe->firstcb);
876 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
877 /* the most common case is what follows the || */
880 tf.AFSCBFids_len = 1;
881 tf.AFSCBFids_val = fid;
884 for (ncbas=0; cb && ncbas<MAX_CB_HOSTS; cb=nextcb) {
885 nextcb = itocb(cb->cnext);
886 if ((cb->hhead != hostindex || flag)
887 && (cb->status == CB_BULK || cb->status == CB_NORMAL
888 || cb->status == CB_VOLUME) ) {
889 struct host *thishost = h_itoh(cb->hhead);
891 ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
893 else if (thishost->hostFlags & VENUSDOWN) {
894 ViceLog(7,("BCB: %x.%d is down; delaying break call back\n",
895 thishost->host, thishost->port));
896 cb->status = CB_DELAYED;
900 cba[ncbas].hp = thishost;
901 cba[ncbas].thead = cb->thead;
905 CDel(cb); /* Usually first; so this delete */
906 /* is reasonably inexpensive */
912 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
914 /* we need to to all these initializations again because MultiBreakCallBack may block */
919 cb = itocb(fe->firstcb);
920 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
921 /* the most common case is what follows the || */
933 /* Delete (do not break) single call back for fid */
934 DeleteCallBack(host, fid)
939 register struct FileEntry *fe;
940 register u_short *pcb;
941 cbstuff.DeleteCallBacks++;
949 ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
950 fid->Volume, fid->Vnode, fid->Unique));
953 pcb = FindCBPtr(fe, host);
955 ViceLog(8,("DCB: No call back for host %x.%d, (%u, %d, %d)\n",
956 host->host, host->port, fid->Volume, fid->Vnode, fid->Unique));
971 * Delete (do not break) all call backs for fid. This call doesn't
972 * set all of the various host locks, but it shouldn't really matter
973 * since we're not adding callbacks, but deleting them. I'm not sure
974 * why it doesn't set the lock, however; perhaps it should.
976 DeleteFileCallBacks(fid)
979 register struct FileEntry *fe;
980 register struct CallBack *cb;
981 register afs_uint32 cbi;
985 cbstuff.DeleteFiles++;
989 ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
990 fid->Volume, fid->Vnode, fid->Unique));
993 for (n=0,cbi = fe->firstcb; cbi; n++) {
1003 } /*DeleteFileCallBacks*/
1006 /* Delete (do not break) all call backs for host. The host should be
1008 DeleteAllCallBacks(host)
1013 retVal = DeleteAllCallBacks_r(host);
1018 DeleteAllCallBacks_r(host)
1021 register struct CallBack *cb;
1022 register int cbi, first;
1024 cbstuff.DeleteAllCallBacks++;
1025 cbi = first = host->cblist;
1027 ViceLog(8,("DV: no call backs\n"));
1035 } while (cbi != first);
1038 } /*DeleteAllCallBacks*/
1042 * Break all delayed call backs for host. Returns 1 if all call backs
1043 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1044 * Must be called with VenusDown set for this host
1046 int BreakDelayedCallBacks(host)
1051 retVal = BreakDelayedCallBacks_r(host);
1056 extern afsUUID FS_HostUUID;
1058 int BreakDelayedCallBacks_r(host)
1061 struct AFSFid fids[AFSCBMAX];
1062 u_short thead[AFSCBMAX];
1063 int cbi, first, nfids;
1064 struct CallBack *cb;
1065 struct interfaceAddr interf;
1068 cbstuff.nbreakers++;
1069 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1070 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1071 if ( host->interface ) {
1073 code = RXAFSCB_InitCallBackState3(host->callback_rxcon,
1078 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1081 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1085 ("CB: Call back connect back failed (in break delayed) for %x.%d\n",
1086 host->host, host->port));
1088 host->hostFlags |= VENUSDOWN;
1091 ViceLog(25,("InitCallBackState success on %x\n",host->host));
1092 /* reset was done successfully */
1093 host->hostFlags |= RESETDONE;
1094 host->hostFlags &= ~VENUSDOWN;
1097 else while (!(host->hostFlags & HOSTDELETED)) {
1099 host->hostFlags &= ~VENUSDOWN; /* presume up */
1100 cbi = first = host->cblist;
1104 first = host->cblist;
1107 if (cb->status == CB_DELAYED) {
1108 register struct FileEntry *fe = itofe(cb->fhead);
1109 thead[nfids] = cb->thead;
1110 fids[nfids].Volume = fe->volid;
1111 fids[nfids].Vnode = fe->vnode;
1112 fids[nfids].Unique = fe->unique;
1118 } while (cbi && cbi != first && nfids < AFSCBMAX);
1124 if (XCallBackBulk_r(host, fids, nfids)) {
1125 /* Failed, again: put them back, probably with old
1130 ("CB: XCallBackBulk failed, host=%x.%d; callback list follows:\n",
1131 host->host, host->port));
1133 for (i = 0; i<nfids; i++) {
1136 ("CB: Host %x.%d, file %u.%u.%u (part of bulk callback)\n",
1137 host->host, host->port,
1138 fids[i].Volume, fids[i].Vnode, fids[i].Unique));
1141 AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1142 * but it turns out to cause too many tricky locking problems.
1143 * now, if break delayed fails, screw it. */
1145 host->hostFlags |= VENUSDOWN; /* Failed */
1146 ClearHostCallbacks_r(host, 1/* locked */);
1150 if (nfids < AFSCBMAX)
1154 cbstuff.nbreakers--;
1155 return (host->hostFlags & VENUSDOWN);
1157 } /*BreakDelayedCallBacks*/
1161 struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
1163 unsigned short thead; /* head of timeout queue for youngest callback */
1168 ** isheld is 0 if the host is held in h_Enumerate
1169 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1171 static int MultiBreakVolumeCallBack_r (host, isheld, parms)
1174 struct VCBParams *parms;
1177 return isheld; /* host is held only by h_Enumerate, do nothing */
1178 if ( host->hostFlags & HOSTDELETED )
1179 return 0; /* host is deleted, release hold */
1181 if (host->hostFlags & VENUSDOWN) {
1183 if (host->hostFlags & HOSTDELETED) {
1185 return 0; /* Release hold */
1187 ViceLog(8,("BVCB: volume call back for host %x.%d failed\n",
1188 host->host,host->port));
1190 ViceLog(0, ("CB: volume callback for host %x.%d failed\n",
1191 host->host, host->port));
1193 DeleteAllCallBacks_r(host); /* Delete all callback state rather than
1194 attempting to selectively remember to
1195 delete the volume callbacks later */
1196 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1198 return 0; /* release hold */
1200 assert(parms->ncbas <= MAX_CB_HOSTS);
1202 /* Do not call MultiBreakCallBack on the current host structure
1203 ** because it would prematurely release the hold on the host
1205 if ( parms->ncbas == MAX_CB_HOSTS ) {
1206 struct AFSCBFids tf;
1208 tf.AFSCBFids_len = 1;
1209 tf.AFSCBFids_val = parms->fid;
1211 /* this releases all the hosts */
1212 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */);
1216 parms->cba[parms->ncbas].hp = host;
1217 parms->cba[(parms->ncbas)++].thead = parms->thead;
1218 return 1; /* DON'T release hold, because we still need it. */
1222 ** isheld is 0 if the host is held in h_Enumerate
1223 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1225 static int MultiBreakVolumeCallBack (host, isheld, parms)
1228 struct VCBParams *parms;
1232 retval = MultiBreakVolumeCallBack_r(host, isheld, parms);
1238 * Break all call backs on a single volume. Don't call this with any
1239 * hosts h_held. Note that this routine clears the callbacks before
1240 * actually breaking them, and that the vnode isn't locked during this
1241 * operation, so that people might see temporary callback loss while
1242 * this function is executing. It is just a temporary state, however,
1243 * since the callback will be broken later by this same function.
1245 * Now uses multi-RX for CallBack RPC. Note that the
1246 * multiBreakCallBacks routine does not force a reset if the RPC
1247 * fails, unlike the previous version of this routine, but does create
1248 * a delayed callback. Resets will be forced if the host is
1249 * determined to be down before the RPC is executed.
1251 BreakVolumeCallBacks(volume)
1258 struct CallBack *cb;
1259 struct FileEntry *fe;
1261 struct VCBParams henumParms;
1262 unsigned short tthead = 0; /* zero is illegal value */
1265 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1266 for (hash=0; hash<VHASH; hash++) {
1267 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1268 if (fe->volid == volume) {
1269 register struct CallBack *cbnext;
1270 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1271 host = h_itoh(cb->hhead);
1273 cbnext = itocb(cb->cnext);
1274 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1280 /* leave hold for MultiBreakVolumeCallBack to clear */
1291 /* didn't find any callbacks, so return right away. */
1295 henumParms.ncbas = 0;
1296 henumParms.fid = &fid;
1297 henumParms.thead = tthead;
1299 h_Enumerate(MultiBreakVolumeCallBack, (char *) &henumParms);
1302 if (henumParms.ncbas) { /* do left-overs */
1303 struct AFSCBFids tf;
1304 tf.AFSCBFids_len = 1;
1305 tf.AFSCBFids_val = &fid;
1307 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1309 henumParms.ncbas = 0;
1314 } /*BreakVolumeCallBacks*/
1318 * Delete all timed-out call back entries (to be called periodically by file
1321 CleanupTimedOutCallBacks()
1324 CleanupTimedOutCallBacks_r();
1328 CleanupTimedOutCallBacks_r()
1330 afs_uint32 now = CBtime(FT_ApproxTime());
1331 register u_short *thead;
1332 register struct CallBack *cb;
1333 register int ntimedout = 0;
1334 extern void ShutDown();
1336 while (tfirst <= now) {
1338 cbi = *(thead = THead(tfirst));
1343 ViceLog(8,("CCB: deleting timed out call back %x.%d, (%u,%u,%u)\n",
1344 h_itoh(cb->hhead)->host, h_itoh(cb->hhead)->port,
1345 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1346 itofe(cb->fhead)->unique));
1350 if (ntimedout > cbstuff.nblks) {
1351 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1352 DumpCallBackState();
1355 } while (cbi != *thead);
1360 cbstuff.CBsTimedOut += ntimedout;
1361 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1362 return (ntimedout > 0);
1364 } /*CleanupTimedOutCallBacks*/
1367 static struct host *lih_host;
1369 static int lih_r(host, held, hostp)
1370 register struct host *host, *hostp;
1375 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1376 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1384 /* This could be upgraded to get more space each time */
1385 /* first pass: find the oldest host which isn't held by anyone */
1386 /* second pass: find the oldest host who isn't "me" */
1387 /* always called with hostp unlocked */
1388 static int GetSomeSpace_r(hostp, locked)
1392 register struct host *hp, *hp1 = (struct host *)0;
1395 cbstuff.GotSomeSpaces++;
1396 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1397 if (CleanupTimedOutCallBacks_r()) {
1403 h_Enumerate_r(lih_r, (char *)hp1);
1407 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1412 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1414 * Next time try getting callbacks from any host even if
1415 * it's deleted (that's actually great since we can freely
1416 * remove its callbacks) or it's held since the only other
1417 * option is starvation for the file server (i.e. until the
1418 * callback timeout arrives).
1424 * No choice to clear this host's callback state
1426 /* third pass: we still haven't gotten any space, so we free what we had
1427 * previously passed over. */
1432 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1439 ClearHostCallbacks(hp, locked)
1441 int locked; /* set if caller has already locked the host */
1445 retVal = ClearHostCallbacks_r(hp, locked);
1450 int ClearHostCallbacks_r(hp, locked)
1452 int locked; /* set if caller has already locked the host */
1454 struct interfaceAddr interf;
1458 ViceLog(5,("GSS: Delete longest inactive host %x\n", hp->host));
1459 if ( !(held = h_Held_r(hp)) )
1462 /** Try a non-blocking lock. If the lock is already held return
1463 * after releasing hold on hp
1466 if ( h_NBLock_r(hp) ) {
1472 if (hp->Console & 2) {
1474 * If the special console field is set it means that a thread
1475 * is waiting in AddCallBack1 after it set pointers to the
1476 * file entry and/or callback entry. Because of the bogus
1477 * usage of h_hold it won't prevent from another thread, this
1478 * one, to remove all the callbacks so just to be safe we keep
1479 * a reference. NOTE, on the last phase we'll free the calling
1480 * host's callbacks but that's ok...
1484 DeleteAllCallBacks_r(hp);
1485 if (hp->hostFlags & VENUSDOWN) {
1486 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1488 /* host is up, try a call */
1489 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1490 if (hp->interface) {
1492 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1496 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1499 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1502 /* failed, mark host down and need reset */
1503 hp->hostFlags |= VENUSDOWN;
1504 hp->hostFlags &= ~RESETDONE;
1506 /* reset succeeded, we're done */
1507 hp->hostFlags |= RESETDONE;
1518 #endif /* INTERPRET_DUMP */
1521 PrintCallBackStats()
1524 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",
1525 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1526 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1527 cbstuff.DeleteAllCallBacks);
1528 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1529 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1531 } /*PrintCallBackStats*/
1534 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1536 #ifndef INTERPRET_DUMP
1543 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1545 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1547 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1550 write(fd, &magic, sizeof(magic));
1551 write(fd, &now, sizeof(now));
1552 write(fd, &cbstuff, sizeof(cbstuff));
1553 write(fd, TimeOuts, sizeof(TimeOuts));
1554 write(fd, timeout, sizeof(timeout));
1555 write(fd, &tfirst, sizeof(tfirst));
1556 freelisthead = cbtoi((struct CallBack *) CBfree);
1557 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1558 freelisthead = fetoi((struct FileEntry *) FEfree);
1559 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1560 write(fd, HashTable, sizeof(HashTable));
1561 write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1562 write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1565 } /*DumpCallBackState*/
1569 #ifdef INTERPRET_DUMP
1571 /* This is only compiled in for the callback analyzer program */
1572 /* Returns the time of the dump */
1573 time_t ReadDump(file)
1578 afs_uint32 magic, freelisthead;
1581 fd = open(file, O_RDONLY);
1583 fprintf(stderr, "Couldn't read dump file %s\n", file);
1586 read(fd, &magic, sizeof(magic));
1587 if (magic != MAGIC) {
1588 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1591 "run this program on a machine type with a different byte ordering.\n");
1594 read(fd, &now, sizeof(now));
1595 read(fd, &cbstuff, sizeof(cbstuff));
1596 read(fd, TimeOuts, sizeof(TimeOuts));
1597 read(fd, timeout, sizeof(timeout));
1598 read(fd, &tfirst, sizeof(tfirst));
1599 read(fd, &freelisthead, sizeof(freelisthead));
1600 CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1601 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1602 CBfree = (struct CallBack *) itocb(freelisthead);
1603 read(fd, &freelisthead, sizeof(freelisthead));
1604 FEfree = (struct FileEntry *) itofe(freelisthead);
1605 read(fd, HashTable, sizeof(HashTable));
1606 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1607 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1609 perror("Error reading dumpfile");
1617 #include "AFS_component_version_number.c"
1624 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1626 register struct FileEntry *fe;
1627 register struct CallBack *cb;
1630 bzero(&fid, sizeof(fid));
1632 while (argc && **argv == '-') {
1635 if (!strcmp(*argv, "-host")) {
1641 cbi = atoi(*++argv);
1643 else if (!strcmp(*argv, "-fid")) {
1649 fid.Volume = atoi(*++argv);
1650 fid.Vnode = atoi(*++argv);
1651 fid.Unique = atoi(*++argv);
1653 else if (!strcmp(*argv, "-time")) {
1654 fprintf(stderr, "-time not supported\n");
1657 else if (!strcmp(*argv, "-stats")) {
1660 else if (!strcmp(*argv, "-all")) {
1663 else if (!strcmp(*argv, "-raw")) {
1666 else if (!strcmp(*argv, "-volume")) {
1672 vol = atoi(*++argv);
1677 if (err || argc != 1) {
1679 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1680 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1683 now = ReadDump(*argv);
1684 if (stats || noptions == 0) {
1685 time_t uxtfirst = UXtime(tfirst);
1686 printf("The time of the dump was %u %s", now, ctime(&now));
1687 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1688 PrintCallBackStats();
1692 register u_short *feip;
1693 register struct CallBack *cb;
1694 register struct FileEntry *fe;
1696 for (hash=0; hash<VHASH; hash++) {
1697 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1698 if (!vol || (fe->volid == vol)) {
1699 register struct CallBack *cbnext;
1700 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1702 cbnext = itocb(cb->cnext);
1712 u_short cfirst = cbi;
1717 } while (cbi != cfirst);
1722 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1725 cb = itocb(fe->firstcb);
1728 cb = itocb(cb->cnext);
1732 struct FileEntry *fe;
1734 for (i=1; i < cbstuff.nblks; i++) {
1735 p = (afs_int32 *) &FE[i];
1736 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1742 register struct CallBack *cb;
1746 struct FileEntry *fe = itofe(cb->fhead);
1747 time_t expires = TIndexToTime(cb->thead);
1749 printf("vol=%u vn=%u cbs=%d hi=%d st=%d, exp in %d secs at %s",
1750 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1751 expires - now, ctime(&expires));
1758 #if !defined(INTERPRET_DUMP)
1760 ** try breaking calbacks on afidp from host. Use multi_rx.
1761 ** return 0 on success, non-zero on failure
1764 MultiBreakCallBackAlternateAddress(host, afidp)
1766 struct AFSCBFids* afidp;
1770 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1776 MultiBreakCallBackAlternateAddress_r(host, afidp)
1778 struct AFSCBFids* afidp;
1781 struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
1782 struct rx_connection* connSuccess = 0;
1783 afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
1784 static struct rx_securityClass *sc = 0;
1785 static struct AFSCBs tc = {0,0};
1787 /* nothing more can be done */
1788 if ( !host->interface ) return 1; /* failure */
1790 assert(host->interface->numberOfInterfaces > 0 );
1792 /* the only address is the primary interface */
1793 if ( host->interface->numberOfInterfaces == 1 )
1794 return 1; /* failure */
1796 /* initialise a security object only once */
1798 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
1800 /* initialize alternate rx connections */
1801 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1803 /* this is the current primary address */
1804 if ( host->host == host->interface->addr[i] )
1807 addr[j] = host->interface->addr[i];
1808 conns[j] = rx_NewConnection (host->interface->addr[i],
1809 host->port, 1, sc, 0);
1810 rx_SetConnDeadTime(conns[j], 2);
1811 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1815 assert(j); /* at least one alternate address */
1816 ViceLog(125,("Starting multibreakcall back on all addr for host:%x\n",
1821 multi_RXAFSCB_CallBack(afidp, &tc);
1826 if ( host->callback_rxcon )
1827 rx_DestroyConnection(host->callback_rxcon);
1828 host->callback_rxcon = conns[multi_i];
1829 host->host = addr[multi_i];
1830 connSuccess = conns[multi_i];
1831 rx_SetConnDeadTime(host->callback_rxcon, 50);
1832 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1833 ViceLog(125,("multibreakcall success with addr:%x\n",
1841 /* Destroy all connections except the one on which we succeeded */
1842 for ( i=0; i < j; i++)
1843 if ( conns[i] != connSuccess )
1844 rx_DestroyConnection(conns[i] );
1846 if ( connSuccess ) return 0; /* success */
1847 else return 1; /* failure */
1852 ** try multiRX probes to host.
1853 ** return 0 on success, non-zero on failure
1856 MultiProbeAlternateAddress_r(host)
1860 struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
1861 struct rx_connection* connSuccess = 0;
1862 afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
1863 static struct rx_securityClass *sc = 0;
1865 /* nothing more can be done */
1866 if ( !host->interface ) return 1; /* failure */
1868 assert(host->interface->numberOfInterfaces > 0 );
1870 /* the only address is the primary interface */
1871 if ( host->interface->numberOfInterfaces == 1 )
1872 return 1; /* failure */
1874 /* initialise a security object only once */
1876 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
1878 /* initialize alternate rx connections */
1879 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1881 /* this is the current primary address */
1882 if ( host->host == host->interface->addr[i] )
1885 addr[j] = host->interface->addr[i];
1886 conns[j] = rx_NewConnection (host->interface->addr[i],
1887 host->port, 1, sc, 0);
1888 rx_SetConnDeadTime(conns[j], 2);
1889 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1893 assert(j); /* at least one alternate address */
1894 ViceLog(125,("Starting multiprobe on all addr for host:%x\n",
1899 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
1904 if ( host->callback_rxcon )
1905 rx_DestroyConnection(host->callback_rxcon);
1906 host->callback_rxcon = conns[multi_i];
1907 host->host = addr[multi_i];
1908 connSuccess = conns[multi_i];
1909 rx_SetConnDeadTime(host->callback_rxcon, 50);
1910 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1911 ViceLog(125,("multiprobe success with addr:%x\n",
1919 /* Destroy all connections except the one on which we succeeded */
1920 for ( i=0; i < j; i++)
1921 if ( conns[i] != connSuccess )
1922 rx_DestroyConnection(conns[i] );
1924 if ( connSuccess ) return 0; /* success */
1925 else return 1; /* failure */
1928 #endif /* !defined(INTERPRET_DUMP) */