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>
83 #include <afsconfig.h>
88 #include <stdlib.h> /* for malloc() */
89 #include <time.h> /* ANSI standard location for time stuff */
97 #include <afs/assert.h>
101 #include <afs/nfs.h> /* yuck. This is an abomination. */
104 #include <afs/afscbint.h>
105 #include <afs/afsutil.h>
107 #include <afs/ihandle.h>
108 #include <afs/vnode.h>
109 #include <afs/volume.h>
112 #include <afs/ptclient.h> /* need definition of prlist for host.h */
116 extern int hostCount;
117 int ShowProblems = 1;
119 /* Maximum number of call backs to break at once, single fid */
120 /* There is some debate as to just how large this value should be */
121 /* Ideally, it would be very very large, but I am afraid that the */
122 /* cache managers will all send in their responses simultaneously, */
123 /* thereby swamping the file server. As a result, something like */
124 /* 10 or 15 might be a better bet. */
125 #define MAX_CB_HOSTS 10
127 /* max time to break a callback, otherwise client is dead or net is hosed */
130 #define u_short unsigned short
131 #define u_byte unsigned char
133 struct cbcounters cbstuff;
141 afs_uint32 vnode; /* XXX This was u_short XXX */
148 #if defined(AFS_ALPHA_ENV) || defined(AFS_ALPHA_LINUX20_ENV)
152 } *FE; /* Don't use FE[0] */
155 u_short cnext; /* Next call back entry */
156 u_short fhead; /* Head of this call back chain */
157 u_byte thead; /* Head of timeout chain */
158 u_byte status; /* Call back status; see definitions, below */
159 u_short hhead; /* Head of host table chain */
160 u_short tprev, tnext; /* Timeout chain */
161 u_short hprev, hnext; /* Chain from host table */
162 } *CB; /* Don't use CB[0] */
164 /* status bits for status field of CallBack structure */
165 #define CB_NORMAL 1 /* Normal call back */
166 #define CB_DELAYED 2 /* Delayed call back due to rpc problems.
167 The call back entry will be added back to the
168 host list at the END of the list, so that
169 searching backwards in the list will find all
170 the (consecutive)host. delayed call back entries */
171 #define CB_VOLUME 3 /* Callback for a volume */
172 #define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
174 /* call back indices to pointers, and vice-versa */
175 #define itocb(i) ((i)?CB+(i):0)
176 #define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
178 /* file entry indices to pointers, and vice-versa */
179 #define itofe(i) ((i)?FE+(i):0)
180 #define fetoi(fep) (!(fep)?0:(fep)-FE)
182 /* Timeouts: there are 128 possible timeout values in effect at any
183 * given time. Each timeout represents timeouts in an interval of 128
184 * seconds. So the maximum timeout for a call back is 128*128=16384
185 * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
186 * if space runs out or by the file server every 5 minutes. This 5
187 * minute slack should be allowed for--so a maximum time of 4 hours
190 * Timeouts must be chosen to correspond to an exact multiple
191 * of 128, because all times are truncated to a 128 multiple, and
192 * timed out if the current truncated time is <= to the truncated time
193 * corresponding to the timeout queue.
196 /* Unix time to Call Back time, and vice-versa. Call back time is
197 in units of 128 seconds, corresponding to time queues. */
198 #define CBtime(uxtime) ((uxtime)>>7)
199 #define UXtime(cbtime) ((cbtime)<<7)
201 /* Given a Unix time, compute the closest Unix time that corresponds to
202 a time queue, rounding up */
203 #define TimeCeiling(uxtime) (((uxtime)+127)&~127)
205 /* Time to live for call backs depends upon number of users of the file.
206 * TimeOuts is indexed by this number/8 (using TimeOut macro). Times
207 * in this table are for the workstation; server timeouts, add
210 static int TimeOuts[] = {
211 /* Note: don't make the first entry larger than 4 hours (see above) */
212 4*60*60, /* 0-7 users */
213 1*60*60, /* 8-15 users */
214 30*60, /* 16-23 users */
215 15*60, /* 24-31 users */
216 15*60, /* 32-39 users */
217 10*60, /* 40-47 users */
218 10*60, /* 48-55 users */
219 10*60, /* 56-63 users */
220 }; /* Anything more: MinTimeOut */
222 /* minimum time given for a call back */
223 static int MinTimeOut = (7*60);
225 #define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
226 #define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
228 /* time out at server is 3 minutes more than ws */
229 #define ServerBias (3*60)
231 /* Heads of CB queues; a timeout index is 1+index into this array */
232 static u_short timeout[128];
234 /* Convert cbtime to timeout queue index */
235 #define TIndex(cbtime) (((cbtime)&127)+1)
237 /* Convert cbtime to pointer to timeout queue head */
238 #define THead(cbtime) (&timeout[TIndex(cbtime)-1])
240 static afs_int32 tfirst; /* cbtime of oldest unexpired call back time queue */
242 /* Normalize index into timeout array so that two such indices will be
243 ordered correctly, so that they can be compared to see which times
244 sooner, or so that the difference in time out times between them
246 #define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
248 /* This converts a timeout index into the actual time it will expire */
249 #define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
252 /* Convert pointer to timeout queue head to index, and vice versa */
253 #define ttoi(t) ((t-timeout)+1)
254 #define itot(i) ((timeout)+(i-1))
256 /* 16 byte object get/free routines */
261 struct CallBack *CBfree = 0;
262 struct FileEntry *FEfree = 0;
264 static struct CallBack *iGetCB(register int *nused);
265 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
266 static struct FileEntry *iGetFE(register int *nused);
267 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
268 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
269 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
271 #define VHASH 512 /* Power of 2 */
272 static u_short HashTable[VHASH]; /* File entry hash table */
273 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
275 static struct FileEntry *FindFE (fid)
276 register AFSFid *fid;
281 register struct FileEntry *fe;
283 hash = VHash(fid->Volume, fid->Unique);
284 for (fei=HashTable[hash]; fei; fei = fe->fnext) {
286 if (fe->volid == fid->Volume && fe->unique == fid->Unique &&
287 fe->vnode == fid->Vnode)
295 #ifndef INTERPRET_DUMP
297 extern void ShutDown();
298 static CDelPtr(), FDel(), AddCallback1(), GetSomeSpace_r();
300 static struct CallBack *iGetCB(register int *nused)
302 register struct CallBack *ret;
305 CBfree = (struct CallBack *)(((struct object *)ret)->next);
313 static iFreeCB(cb, nused)
314 register struct CallBack *cb;
318 ((struct object *)cb)->next = (struct object *)CBfree;
324 static struct FileEntry *iGetFE(register int *nused)
326 register struct FileEntry *ret;
329 FEfree = (struct FileEntry *)(((struct object *)ret)->next);
337 static iFreeFE(fe, nused)
338 register struct FileEntry *fe;
342 ((struct object *)fe)->next = (struct object *)FEfree;
348 /* Add cb to end of specified timeout list */
349 static TAdd(cb, thead)
350 register struct CallBack *cb;
351 register u_short *thead;
355 (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
357 register struct CallBack *thp = itocb(*thead);
359 cb->tprev = thp->tprev;
361 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
363 cb->thead = ttoi(thead);
368 /* Delete call back entry from timeout list */
370 register struct CallBack *cb;
373 register u_short *thead = itot(cb->thead);
375 if (*thead == cbtoi(cb))
376 *thead = (*thead == cb->tnext? 0: cb->tnext);
377 itocb(cb->tprev)->tnext = cb->tnext;
378 itocb(cb->tnext)->tprev = cb->tprev;
383 /* Add cb to end of specified host list */
384 static HAdd(cb, host)
385 register struct CallBack *cb;
386 register struct host *host;
389 cb->hhead = h_htoi(host);
391 host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
394 register struct CallBack *hhp = itocb(host->cblist);
396 cb->hprev = hhp->hprev;
397 cb->hnext = host->cblist;
398 hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
404 /* Delete call back entry from host list */
406 register struct CallBack *cb;
409 register u_short *hhead = &h_itoh(cb->hhead)->cblist;
411 if (*hhead == cbtoi(cb))
412 *hhead = (*hhead == cb->hnext? 0: cb->hnext);
413 itocb(cb->hprev)->hnext = cb->hnext;
414 itocb(cb->hnext)->hprev = cb->hprev;
419 /* Delete call back entry from fid's chain of cb's */
420 /* N.B. This one also deletes the CB, and also possibly parent FE, so
421 * make sure that it is not on any other list before calling this
428 struct FileEntry *fe = itofe(cb->fhead);
429 register u_short *cbp;
432 for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
433 cbp = &itocb(*cbp)->cnext, safety++) {
434 if (safety > cbstuff.nblks + 10) {
436 ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
446 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
447 * as well as file entry */
448 /* N.B. This one also deletes the CB, and also possibly parent FE, so
449 * make sure that it is not on any other list before calling this
451 int Ccdelpt=0, CcdelB=0;
453 static CDelPtr(fe, cbp)
454 register struct FileEntry *fe;
455 register u_short *cbp;
458 register struct CallBack *cb;
474 static u_short *FindCBPtr(fe, host)
475 struct FileEntry *fe;
479 register afs_uint32 hostindex = h_htoi(host);
480 register struct CallBack *cb;
481 register u_short *cbp;
484 for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
485 if (safety > cbstuff.nblks) {
486 ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
491 if (cb->hhead == hostindex)
500 /* Delete file entry from hash table */
502 register struct FileEntry *fe;
505 register int fei = fetoi(fe);
506 register unsigned short *p = &HashTable[VHash(fe->volid, fe->unique)];
508 while (*p && *p != fei)
509 p = &itofe(*p)->fnext;
523 tfirst = CBtime(FT_ApproxTime());
524 /* N.B. FE's, CB's share same free list. If the sizes of either change,
525 FE and CB will have to be separated. The "-1", below, is because
526 FE[0] and CB[0] are not used--and not allocated */
527 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*nblks)))-1;
528 cbstuff.nFEs = nblks;
530 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
531 CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
532 cbstuff.nCBs = nblks;
534 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
535 cbstuff.nblks = nblks;
536 cbstuff.nbreakers = 0;
542 afs_int32 XCallBackBulk_r(ahost, fids, nfids)
548 struct AFSCallBack tcbs[AFSCBMAX];
556 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
557 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
564 for(i=0;i<nfids && i < AFSCBMAX;i++) {
565 tcbs[i].CallBackVersion = CALLBACK_VERSION;
566 tcbs[i].ExpirationTime = 0;
567 tcbs[i].CallBackType = CB_DROPPED;
569 tf.AFSCBFids_len = i;
570 tf.AFSCBFids_val = &(fids[j]);
574 tc.AFSCBs_val = tcbs;
577 code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
585 /* the locked flag tells us if the host entry has already been locked
586 * by our parent. I don't think anybody actually calls us with the
587 * host locked, but here's how to make that work: GetSomeSpace has to
588 * change so that it doesn't attempt to lock any hosts < "host". That
589 * means that it might be unable to free any objects, so it has to
590 * return an exit status. If it fails, then AddCallBack1 might fail,
591 * as well. If so, the host->ResetDone should probably be set to 0,
592 * and we probably don't want to return a callback promise to the
593 * cache manager, either. */
595 AddCallBack1(host, fid, thead, type, locked)
607 retVal = AddCallBack1_r(host, fid, thead, type, 1);
617 AddCallBack1_r(host, fid, thead, type, locked)
624 struct FileEntry *fe;
625 struct CallBack *cb = 0, *lastcb = 0;
626 struct FileEntry *newfe = 0;
628 u_short *Thead = thead;
629 struct CallBack *newcb = 0;
634 /* allocate these guys first, since we can't call the allocator with
635 the host structure locked -- or we might deadlock. However, we have
636 to avoid races with FindFE... */
637 while (!(newcb = GetCB())) {
638 GetSomeSpace_r(host, locked);
640 while(!(newfe = GetFE())) { /* Get it now, so we don't have to call */
641 /* GetSomeSpace with the host locked, later. This might turn out to */
642 /* have been unneccessary, but that's actually kind of unlikely, since */
643 /* most files are not shared. */
644 GetSomeSpace_r(host, locked);
648 h_Lock_r(host); /* this can yield, so do it before we get any */
653 if (type == CB_NORMAL) {
654 time_out = TimeCeiling(FT_ApproxTime()+TimeOut(fe?fe->ncbs:0)+ServerBias);
655 Thead = THead(CBtime(time_out));
657 else if (type == CB_VOLUME) {
658 time_out = TimeCeiling((60*120+FT_ApproxTime())+ServerBias);
659 Thead = THead(CBtime(time_out));
661 else if (type == CB_BULK) {
662 /* bulk status can get so many callbacks all at once, and most of them
663 * are probably not for things that will be used for long.
665 time_out = TimeCeiling(FT_ApproxTime() + ServerBias
666 + TimeOut(22 + (fe?fe->ncbs:0)));
667 Thead = THead(CBtime(time_out));
673 register afs_uint32 hash;
676 newfe = (struct FileEntry *) 0;
678 fe->volid = fid->Volume;
679 fe->vnode = fid->Vnode;
680 fe->unique = fid->Unique;
682 hash = VHash(fid->Volume, fid->Unique);
683 fe->fnext = HashTable[hash];
684 HashTable[hash] = fetoi(fe);
686 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
687 lastcb = cb, cb = itocb(cb->cnext), safety++) {
688 if (safety > cbstuff.nblks) {
689 ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
693 if (cb->hhead == h_htoi(host))
696 if (cb) {/* Already have call back: move to new timeout list */
697 /* don't change delayed callbacks back to normal ones */
698 if (cb->status != CB_DELAYED)
700 /* Only move if new timeout is longer */
701 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
707 newcb = (struct CallBack *) 0;
708 *(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
711 cb->fhead = fetoi(fe);
717 /* now free any still-unused callback or host entries */
718 if (newcb) FreeCB(newcb);
719 if (newfe) FreeFE(newfe);
721 if (!locked) /* freecb and freefe might(?) yield */
724 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK )
725 return time_out-ServerBias; /* Expires sooner at workstation */
731 /* Take an array full of hosts, all held. Break callbacks to them, and
732 * release the holds once you're done, except don't release xhost. xhost
733 * may be NULL. Currently only works for a single Fid in afidp array.
734 * If you want to make this work with multiple fids, you need to fix
735 * the error handling. One approach would be to force a reset if a
736 * multi-fid call fails, or you could add delayed callbacks for each
737 * fid. You probably also need to sort and remove duplicate hosts.
738 * When this is called from the BreakVolumeCallBacks path, it does NOT
739 * force a reset if the RPC fails, it just marks the host down and tries
740 * to create a delayed callback. */
741 /* N.B. be sure that code works when ncbas == 0 */
742 /* N.B. requires all the cba[*].hp pointers to be valid... */
743 /* This routine does not hold a lock on the host for the duration of
744 * the BreakCallBack RPC, which is a significant deviation from tradition.
745 * It _does_ get a lock on the host before setting VenusDown = 1,
746 * which is sufficient only if VenusDown = 0 only happens when the
747 * lock is held over the RPC and the subsequent VenusDown == 0
748 * wherever that is done. */
749 static void MultiBreakCallBack_r(cba, ncbas, afidp, xhost)
750 struct cbstruct cba[];
752 struct AFSCBFids *afidp;
756 struct rx_connection *conns[MAX_CB_HOSTS];
757 int opt_TO; /* secs, but internal adaptive parms are in ms */
758 static struct AFSCBs tc = {0,0};
760 assert(ncbas <= MAX_CB_HOSTS);
762 /* set up conns for multi-call */
763 for (i=0,j=0; i<ncbas; i++) {
764 struct host *thishost = cba[i].hp;
765 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
768 conns[j++] = thishost->callback_rxcon;
771 rx_SetConnDeadTime (thishost->callback_rxcon, 4);
772 rx_SetConnHardDeadTime (thishost->callback_rxcon, AFS_HARDDEADTIME);
776 if (j) { /* who knows what multi would do with 0 conns? */
780 multi_RXAFSCB_CallBack(afidp, &tc);
785 /* If there's an error, we have to hunt for the right host.
786 * The conns array _should_ correspond one-to-one to the cba
787 * array, except in some rare cases it might be missing one
788 * or more elements. So the optimistic case is almost
789 * always right. At worst, it's the starting point for the
791 for (hp=0,i=multi_i;i<j;i++) {
792 hp = cba[i].hp; /* optimistic, but usually right */
796 if (conns[multi_i] == hp->callback_rxcon) {
803 ViceLog(0, ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n",hp,cba));
807 ** try breaking callbacks on alternate interface addresses
809 if ( MultiBreakCallBackAlternateAddress(hp, afidp) )
813 ("BCB: Failed on file %u.%d.%d, host %x.%d is down\n",
814 afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
815 afidp->AFSCBFids_val->Unique, hp->host, hp->port));
820 hp->hostFlags |= VENUSDOWN;
822 * We always go into AddCallBack1_r with the host locked
824 AddCallBack1_r(hp,afidp->AFSCBFids_val,itot(idx), CB_DELAYED, 1);
835 for (i=0; i<ncbas; i++) {
838 if (hp && xhost != hp)
846 * Break all call backs for fid, except for the specified host (unless flag
847 * is true, in which case all get a callback message. Assumption: the specified
848 * host is h_Held, by the caller; the others aren't.
849 * Specified host may be bogus, that's ok. This used to check to see if the
850 * host was down in two places, once right after the host was h_held, and
851 * again after it was locked. That race condition is incredibly rare and
852 * relatively harmless even when it does occur, so we don't check for it now.
854 BreakCallBack(xhost, fid, flag)
856 int flag; /* if flag is true, send a break callback msg to "host", too */
859 struct FileEntry *fe;
860 struct CallBack *cb, *nextcb;
861 struct cbstruct cba[MAX_CB_HOSTS];
863 struct rx_connection *conns[MAX_CB_HOSTS];
867 ViceLog(7,("BCB: BreakCallBack(all but %x.%d, (%u,%d,%d))\n",
868 xhost->host, xhost->port, fid->Volume, fid->Vnode,
873 cbstuff.BreakCallBacks++;
878 hostindex = h_htoi(xhost);
879 cb = itocb(fe->firstcb);
880 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
881 /* the most common case is what follows the || */
884 tf.AFSCBFids_len = 1;
885 tf.AFSCBFids_val = fid;
888 for (ncbas=0; cb && ncbas<MAX_CB_HOSTS; cb=nextcb) {
889 nextcb = itocb(cb->cnext);
890 if ((cb->hhead != hostindex || flag)
891 && (cb->status == CB_BULK || cb->status == CB_NORMAL
892 || cb->status == CB_VOLUME) ) {
893 struct host *thishost = h_itoh(cb->hhead);
895 ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
897 else if (thishost->hostFlags & VENUSDOWN) {
898 ViceLog(7,("BCB: %x.%d is down; delaying break call back\n",
899 thishost->host, thishost->port));
900 cb->status = CB_DELAYED;
904 cba[ncbas].hp = thishost;
905 cba[ncbas].thead = cb->thead;
909 CDel(cb); /* Usually first; so this delete */
910 /* is reasonably inexpensive */
916 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
918 /* we need to to all these initializations again because MultiBreakCallBack may block */
923 cb = itocb(fe->firstcb);
924 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
925 /* the most common case is what follows the || */
937 /* Delete (do not break) single call back for fid */
938 DeleteCallBack(host, fid)
943 register struct FileEntry *fe;
944 register u_short *pcb;
945 cbstuff.DeleteCallBacks++;
953 ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
954 fid->Volume, fid->Vnode, fid->Unique));
957 pcb = FindCBPtr(fe, host);
959 ViceLog(8,("DCB: No call back for host %x.%d, (%u, %d, %d)\n",
960 host->host, host->port, fid->Volume, fid->Vnode, fid->Unique));
975 * Delete (do not break) all call backs for fid. This call doesn't
976 * set all of the various host locks, but it shouldn't really matter
977 * since we're not adding callbacks, but deleting them. I'm not sure
978 * why it doesn't set the lock, however; perhaps it should.
980 DeleteFileCallBacks(fid)
983 register struct FileEntry *fe;
984 register struct CallBack *cb;
985 register afs_uint32 cbi;
989 cbstuff.DeleteFiles++;
993 ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
994 fid->Volume, fid->Vnode, fid->Unique));
997 for (n=0,cbi = fe->firstcb; cbi; n++) {
1007 } /*DeleteFileCallBacks*/
1010 /* Delete (do not break) all call backs for host. The host should be
1012 DeleteAllCallBacks(host)
1017 retVal = DeleteAllCallBacks_r(host);
1022 DeleteAllCallBacks_r(host)
1025 register struct CallBack *cb;
1026 register int cbi, first;
1028 cbstuff.DeleteAllCallBacks++;
1029 cbi = first = host->cblist;
1031 ViceLog(8,("DV: no call backs\n"));
1039 } while (cbi != first);
1042 } /*DeleteAllCallBacks*/
1046 * Break all delayed call backs for host. Returns 1 if all call backs
1047 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1048 * Must be called with VenusDown set for this host
1050 int BreakDelayedCallBacks(host)
1055 retVal = BreakDelayedCallBacks_r(host);
1060 extern afsUUID FS_HostUUID;
1062 int BreakDelayedCallBacks_r(host)
1065 struct AFSFid fids[AFSCBMAX];
1066 u_short thead[AFSCBMAX];
1067 int cbi, first, nfids;
1068 struct CallBack *cb;
1069 struct interfaceAddr interf;
1072 cbstuff.nbreakers++;
1073 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1074 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1075 if ( host->interface ) {
1077 code = RXAFSCB_InitCallBackState3(host->callback_rxcon,
1082 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1085 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1089 ("CB: Call back connect back failed (in break delayed) for %x.%d\n",
1090 host->host, host->port));
1092 host->hostFlags |= VENUSDOWN;
1095 ViceLog(25,("InitCallBackState success on %x\n",host->host));
1096 /* reset was done successfully */
1097 host->hostFlags |= RESETDONE;
1098 host->hostFlags &= ~VENUSDOWN;
1101 else while (!(host->hostFlags & HOSTDELETED)) {
1103 host->hostFlags &= ~VENUSDOWN; /* presume up */
1104 cbi = first = host->cblist;
1108 first = host->cblist;
1111 if (cb->status == CB_DELAYED) {
1112 register struct FileEntry *fe = itofe(cb->fhead);
1113 thead[nfids] = cb->thead;
1114 fids[nfids].Volume = fe->volid;
1115 fids[nfids].Vnode = fe->vnode;
1116 fids[nfids].Unique = fe->unique;
1122 } while (cbi && cbi != first && nfids < AFSCBMAX);
1128 if (XCallBackBulk_r(host, fids, nfids)) {
1129 /* Failed, again: put them back, probably with old
1134 ("CB: XCallBackBulk failed, host=%x.%d; callback list follows:\n",
1135 host->host, host->port));
1137 for (i = 0; i<nfids; i++) {
1140 ("CB: Host %x.%d, file %u.%u.%u (part of bulk callback)\n",
1141 host->host, host->port,
1142 fids[i].Volume, fids[i].Vnode, fids[i].Unique));
1145 AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1146 * but it turns out to cause too many tricky locking problems.
1147 * now, if break delayed fails, screw it. */
1149 host->hostFlags |= VENUSDOWN; /* Failed */
1150 ClearHostCallbacks_r(host, 1/* locked */);
1154 if (nfids < AFSCBMAX)
1158 cbstuff.nbreakers--;
1159 return (host->hostFlags & VENUSDOWN);
1161 } /*BreakDelayedCallBacks*/
1165 struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
1167 unsigned short thead; /* head of timeout queue for youngest callback */
1172 ** isheld is 0 if the host is held in h_Enumerate
1173 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1175 static int MultiBreakVolumeCallBack_r (host, isheld, parms)
1178 struct VCBParams *parms;
1181 return isheld; /* host is held only by h_Enumerate, do nothing */
1182 if ( host->hostFlags & HOSTDELETED )
1183 return 0; /* host is deleted, release hold */
1185 if (host->hostFlags & VENUSDOWN) {
1187 if (host->hostFlags & HOSTDELETED) {
1189 return 0; /* Release hold */
1191 ViceLog(8,("BVCB: volume call back for host %x.%d failed\n",
1192 host->host,host->port));
1194 ViceLog(0, ("CB: volume callback for host %x.%d failed\n",
1195 host->host, host->port));
1197 DeleteAllCallBacks_r(host); /* Delete all callback state rather than
1198 attempting to selectively remember to
1199 delete the volume callbacks later */
1200 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1202 return 0; /* release hold */
1204 assert(parms->ncbas <= MAX_CB_HOSTS);
1206 /* Do not call MultiBreakCallBack on the current host structure
1207 ** because it would prematurely release the hold on the host
1209 if ( parms->ncbas == MAX_CB_HOSTS ) {
1210 struct AFSCBFids tf;
1212 tf.AFSCBFids_len = 1;
1213 tf.AFSCBFids_val = parms->fid;
1215 /* this releases all the hosts */
1216 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */);
1220 parms->cba[parms->ncbas].hp = host;
1221 parms->cba[(parms->ncbas)++].thead = parms->thead;
1222 return 1; /* DON'T release hold, because we still need it. */
1226 ** isheld is 0 if the host is held in h_Enumerate
1227 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1229 static int MultiBreakVolumeCallBack (host, isheld, parms)
1232 struct VCBParams *parms;
1236 retval = MultiBreakVolumeCallBack_r(host, isheld, parms);
1242 * Break all call backs on a single volume. Don't call this with any
1243 * hosts h_held. Note that this routine clears the callbacks before
1244 * actually breaking them, and that the vnode isn't locked during this
1245 * operation, so that people might see temporary callback loss while
1246 * this function is executing. It is just a temporary state, however,
1247 * since the callback will be broken later by this same function.
1249 * Now uses multi-RX for CallBack RPC. Note that the
1250 * multiBreakCallBacks routine does not force a reset if the RPC
1251 * fails, unlike the previous version of this routine, but does create
1252 * a delayed callback. Resets will be forced if the host is
1253 * determined to be down before the RPC is executed.
1255 BreakVolumeCallBacks(volume)
1262 struct CallBack *cb;
1263 struct FileEntry *fe;
1265 struct VCBParams henumParms;
1266 unsigned short tthead = 0; /* zero is illegal value */
1269 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1270 for (hash=0; hash<VHASH; hash++) {
1271 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1272 if (fe->volid == volume) {
1273 register struct CallBack *cbnext;
1274 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1275 host = h_itoh(cb->hhead);
1277 cbnext = itocb(cb->cnext);
1278 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1284 /* leave hold for MultiBreakVolumeCallBack to clear */
1295 /* didn't find any callbacks, so return right away. */
1299 henumParms.ncbas = 0;
1300 henumParms.fid = &fid;
1301 henumParms.thead = tthead;
1303 h_Enumerate(MultiBreakVolumeCallBack, (char *) &henumParms);
1306 if (henumParms.ncbas) { /* do left-overs */
1307 struct AFSCBFids tf;
1308 tf.AFSCBFids_len = 1;
1309 tf.AFSCBFids_val = &fid;
1311 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1313 henumParms.ncbas = 0;
1318 } /*BreakVolumeCallBacks*/
1322 * Delete all timed-out call back entries (to be called periodically by file
1325 CleanupTimedOutCallBacks()
1328 CleanupTimedOutCallBacks_r();
1332 CleanupTimedOutCallBacks_r()
1334 afs_uint32 now = CBtime(FT_ApproxTime());
1335 register u_short *thead;
1336 register struct CallBack *cb;
1337 register int ntimedout = 0;
1338 extern void ShutDown();
1340 while (tfirst <= now) {
1342 cbi = *(thead = THead(tfirst));
1347 ViceLog(8,("CCB: deleting timed out call back %x.%d, (%u,%u,%u)\n",
1348 h_itoh(cb->hhead)->host, h_itoh(cb->hhead)->port,
1349 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1350 itofe(cb->fhead)->unique));
1354 if (ntimedout > cbstuff.nblks) {
1355 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1356 DumpCallBackState();
1359 } while (cbi != *thead);
1364 cbstuff.CBsTimedOut += ntimedout;
1365 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1366 return (ntimedout > 0);
1368 } /*CleanupTimedOutCallBacks*/
1371 static struct host *lih_host;
1373 static int lih_r(host, held, hostp)
1374 register struct host *host, *hostp;
1379 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1380 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1388 /* This could be upgraded to get more space each time */
1389 /* first pass: find the oldest host which isn't held by anyone */
1390 /* second pass: find the oldest host who isn't "me" */
1391 /* always called with hostp unlocked */
1392 static int GetSomeSpace_r(hostp, locked)
1396 register struct host *hp, *hp1 = (struct host *)0;
1399 cbstuff.GotSomeSpaces++;
1400 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1401 if (CleanupTimedOutCallBacks_r()) {
1407 h_Enumerate_r(lih_r, (char *)hp1);
1411 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1416 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1418 * Next time try getting callbacks from any host even if
1419 * it's deleted (that's actually great since we can freely
1420 * remove its callbacks) or it's held since the only other
1421 * option is starvation for the file server (i.e. until the
1422 * callback timeout arrives).
1428 * No choice to clear this host's callback state
1430 /* third pass: we still haven't gotten any space, so we free what we had
1431 * previously passed over. */
1436 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1443 ClearHostCallbacks(hp, locked)
1445 int locked; /* set if caller has already locked the host */
1449 retVal = ClearHostCallbacks_r(hp, locked);
1454 int ClearHostCallbacks_r(hp, locked)
1456 int locked; /* set if caller has already locked the host */
1458 struct interfaceAddr interf;
1462 ViceLog(5,("GSS: Delete longest inactive host %x\n", hp->host));
1463 if ( !(held = h_Held_r(hp)) )
1466 /** Try a non-blocking lock. If the lock is already held return
1467 * after releasing hold on hp
1470 if ( h_NBLock_r(hp) ) {
1476 if (hp->Console & 2) {
1478 * If the special console field is set it means that a thread
1479 * is waiting in AddCallBack1 after it set pointers to the
1480 * file entry and/or callback entry. Because of the bogus
1481 * usage of h_hold it won't prevent from another thread, this
1482 * one, to remove all the callbacks so just to be safe we keep
1483 * a reference. NOTE, on the last phase we'll free the calling
1484 * host's callbacks but that's ok...
1488 DeleteAllCallBacks_r(hp);
1489 if (hp->hostFlags & VENUSDOWN) {
1490 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1492 /* host is up, try a call */
1493 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1494 if (hp->interface) {
1496 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1500 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1503 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1506 /* failed, mark host down and need reset */
1507 hp->hostFlags |= VENUSDOWN;
1508 hp->hostFlags &= ~RESETDONE;
1510 /* reset succeeded, we're done */
1511 hp->hostFlags |= RESETDONE;
1522 #endif /* INTERPRET_DUMP */
1525 PrintCallBackStats()
1528 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",
1529 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1530 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1531 cbstuff.DeleteAllCallBacks);
1532 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1533 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1535 } /*PrintCallBackStats*/
1538 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1540 #ifndef INTERPRET_DUMP
1547 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1549 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1551 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1554 write(fd, &magic, sizeof(magic));
1555 write(fd, &now, sizeof(now));
1556 write(fd, &cbstuff, sizeof(cbstuff));
1557 write(fd, TimeOuts, sizeof(TimeOuts));
1558 write(fd, timeout, sizeof(timeout));
1559 write(fd, &tfirst, sizeof(tfirst));
1560 freelisthead = cbtoi((struct CallBack *) CBfree);
1561 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1562 freelisthead = fetoi((struct FileEntry *) FEfree);
1563 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1564 write(fd, HashTable, sizeof(HashTable));
1565 write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1566 write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1569 } /*DumpCallBackState*/
1573 #ifdef INTERPRET_DUMP
1575 /* This is only compiled in for the callback analyzer program */
1576 /* Returns the time of the dump */
1577 time_t ReadDump(file)
1582 afs_uint32 magic, freelisthead;
1585 fd = open(file, O_RDONLY);
1587 fprintf(stderr, "Couldn't read dump file %s\n", file);
1590 read(fd, &magic, sizeof(magic));
1591 if (magic != MAGIC) {
1592 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1595 "run this program on a machine type with a different byte ordering.\n");
1598 read(fd, &now, sizeof(now));
1599 read(fd, &cbstuff, sizeof(cbstuff));
1600 read(fd, TimeOuts, sizeof(TimeOuts));
1601 read(fd, timeout, sizeof(timeout));
1602 read(fd, &tfirst, sizeof(tfirst));
1603 read(fd, &freelisthead, sizeof(freelisthead));
1604 CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1605 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1606 CBfree = (struct CallBack *) itocb(freelisthead);
1607 read(fd, &freelisthead, sizeof(freelisthead));
1608 FEfree = (struct FileEntry *) itofe(freelisthead);
1609 read(fd, HashTable, sizeof(HashTable));
1610 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1611 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1613 perror("Error reading dumpfile");
1621 #include "AFS_component_version_number.c"
1628 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1630 register struct FileEntry *fe;
1631 register struct CallBack *cb;
1634 bzero(&fid, sizeof(fid));
1636 while (argc && **argv == '-') {
1639 if (!strcmp(*argv, "-host")) {
1645 cbi = atoi(*++argv);
1647 else if (!strcmp(*argv, "-fid")) {
1653 fid.Volume = atoi(*++argv);
1654 fid.Vnode = atoi(*++argv);
1655 fid.Unique = atoi(*++argv);
1657 else if (!strcmp(*argv, "-time")) {
1658 fprintf(stderr, "-time not supported\n");
1661 else if (!strcmp(*argv, "-stats")) {
1664 else if (!strcmp(*argv, "-all")) {
1667 else if (!strcmp(*argv, "-raw")) {
1670 else if (!strcmp(*argv, "-volume")) {
1676 vol = atoi(*++argv);
1681 if (err || argc != 1) {
1683 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1684 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1687 now = ReadDump(*argv);
1688 if (stats || noptions == 0) {
1689 time_t uxtfirst = UXtime(tfirst);
1690 printf("The time of the dump was %u %s", now, ctime(&now));
1691 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1692 PrintCallBackStats();
1696 register u_short *feip;
1697 register struct CallBack *cb;
1698 register struct FileEntry *fe;
1700 for (hash=0; hash<VHASH; hash++) {
1701 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1702 if (!vol || (fe->volid == vol)) {
1703 register struct CallBack *cbnext;
1704 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1706 cbnext = itocb(cb->cnext);
1716 u_short cfirst = cbi;
1721 } while (cbi != cfirst);
1726 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1729 cb = itocb(fe->firstcb);
1732 cb = itocb(cb->cnext);
1736 struct FileEntry *fe;
1738 for (i=1; i < cbstuff.nblks; i++) {
1739 p = (afs_int32 *) &FE[i];
1740 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1746 register struct CallBack *cb;
1750 struct FileEntry *fe = itofe(cb->fhead);
1751 time_t expires = TIndexToTime(cb->thead);
1753 printf("vol=%u vn=%u cbs=%d hi=%d st=%d, exp in %d secs at %s",
1754 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1755 expires - now, ctime(&expires));
1762 #if !defined(INTERPRET_DUMP)
1764 ** try breaking calbacks on afidp from host. Use multi_rx.
1765 ** return 0 on success, non-zero on failure
1768 MultiBreakCallBackAlternateAddress(host, afidp)
1770 struct AFSCBFids* afidp;
1774 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1780 MultiBreakCallBackAlternateAddress_r(host, afidp)
1782 struct AFSCBFids* afidp;
1785 struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
1786 struct rx_connection* connSuccess = 0;
1787 afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
1788 static struct rx_securityClass *sc = 0;
1789 static struct AFSCBs tc = {0,0};
1791 /* nothing more can be done */
1792 if ( !host->interface ) return 1; /* failure */
1794 assert(host->interface->numberOfInterfaces > 0 );
1796 /* the only address is the primary interface */
1797 if ( host->interface->numberOfInterfaces == 1 )
1798 return 1; /* failure */
1800 /* initialise a security object only once */
1802 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
1804 /* initialize alternate rx connections */
1805 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1807 /* this is the current primary address */
1808 if ( host->host == host->interface->addr[i] )
1811 addr[j] = host->interface->addr[i];
1812 conns[j] = rx_NewConnection (host->interface->addr[i],
1813 host->port, 1, sc, 0);
1814 rx_SetConnDeadTime(conns[j], 2);
1815 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1819 assert(j); /* at least one alternate address */
1820 ViceLog(125,("Starting multibreakcall back on all addr for host:%x\n",
1825 multi_RXAFSCB_CallBack(afidp, &tc);
1830 if ( host->callback_rxcon )
1831 rx_DestroyConnection(host->callback_rxcon);
1832 host->callback_rxcon = conns[multi_i];
1833 host->host = addr[multi_i];
1834 connSuccess = conns[multi_i];
1835 rx_SetConnDeadTime(host->callback_rxcon, 50);
1836 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1837 ViceLog(125,("multibreakcall success with addr:%x\n",
1845 /* Destroy all connections except the one on which we succeeded */
1846 for ( i=0; i < j; i++)
1847 if ( conns[i] != connSuccess )
1848 rx_DestroyConnection(conns[i] );
1850 if ( connSuccess ) return 0; /* success */
1851 else return 1; /* failure */
1856 ** try multiRX probes to host.
1857 ** return 0 on success, non-zero on failure
1860 MultiProbeAlternateAddress_r(host)
1864 struct rx_connection* conns[AFS_MAX_INTERFACE_ADDR];
1865 struct rx_connection* connSuccess = 0;
1866 afs_int32 addr[AFS_MAX_INTERFACE_ADDR];
1867 static struct rx_securityClass *sc = 0;
1869 /* nothing more can be done */
1870 if ( !host->interface ) return 1; /* failure */
1872 assert(host->interface->numberOfInterfaces > 0 );
1874 /* the only address is the primary interface */
1875 if ( host->interface->numberOfInterfaces == 1 )
1876 return 1; /* failure */
1878 /* initialise a security object only once */
1880 sc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
1882 /* initialize alternate rx connections */
1883 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1885 /* this is the current primary address */
1886 if ( host->host == host->interface->addr[i] )
1889 addr[j] = host->interface->addr[i];
1890 conns[j] = rx_NewConnection (host->interface->addr[i],
1891 host->port, 1, sc, 0);
1892 rx_SetConnDeadTime(conns[j], 2);
1893 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1897 assert(j); /* at least one alternate address */
1898 ViceLog(125,("Starting multiprobe on all addr for host:%x\n",
1903 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
1908 if ( host->callback_rxcon )
1909 rx_DestroyConnection(host->callback_rxcon);
1910 host->callback_rxcon = conns[multi_i];
1911 host->host = addr[multi_i];
1912 connSuccess = conns[multi_i];
1913 rx_SetConnDeadTime(host->callback_rxcon, 50);
1914 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1915 ViceLog(125,("multiprobe success with addr:%x\n",
1923 /* Destroy all connections except the one on which we succeeded */
1924 for ( i=0; i < j; i++)
1925 if ( conns[i] != connSuccess )
1926 rx_DestroyConnection(conns[i] );
1928 if ( connSuccess ) return 0; /* success */
1929 else return 1; /* failure */
1932 #endif /* !defined(INTERPRET_DUMP) */