2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * NEW callback package callback.c (replaces vicecb.c)
12 * Updated call back routines, NOW with:
14 * Faster DeleteVenus (Now called DeleteAllCallBacks)
15 * Call back breaking for volumes
16 * Adaptive timeouts on call backs
17 * Architected for Multi RPC
18 * No locks (currently implicit vnode locks--these will go, to)
19 * Delayed call back when rpc connection down.
20 * Bulk break of delayed call backs when rpc connection
22 * Strict limit on number of call backs.
24 * InitCallBack(nblocks)
25 * Initialize: nblocks is max number # of file entries + # of callback entries
26 * nblocks must be < 65536
27 * Space used is nblocks*16 bytes
28 * Note that space will be reclaimed by breaking callbacks of old hosts
30 * time = AddCallBack(host, fid)
32 * Returns the expiration time at the workstation.
34 * BreakCallBack(host, fid)
35 * Break all call backs for fid, except for the specified host.
38 * BreakVolumeCallBacks(volume)
39 * Break all call backs on volume, using single call to each host
40 * Delete all the call backs.
42 * DeleteCallBack(host,fid)
43 * Delete (do not break) single call back for fid.
45 * DeleteFileCallBacks(fid)
46 * Delete (do not break) all call backs for fid.
48 * DeleteAllCallBacks(host)
49 * Delete (do not break) all call backs for host.
51 * CleanupTimedOutCallBacks()
52 * Delete all timed out call back entries
53 * Must be called periodically by file server.
55 * BreakDelayedCallBacks(host)
56 * Break all delayed call backs for host.
57 * Returns 1: one or more failed, 0: success.
59 * PrintCallBackStats()
60 * Print statistics about call backs to stdout.
62 * DumpCallBacks() ---wishful thinking---
63 * Dump call back state to /tmp/callback.state.
64 * This is separately interpretable by the program pcb.
66 * Notes: In general, if a call back to a host doesn't get through,
67 * then HostDown, supplied elsewhere, is called. BreakDelayedCallBacks,
68 * however, does not call HostDown, but instead returns an indication of
69 * success if all delayed call backs were finally broken.
71 * BreakDelayedCallBacks MUST be called at the first sign of activity
72 * from the host after HostDown has been called (or a previous
73 * BreakDelayedCallBacks failed). The BreakDelayedCallBacks must be
74 * allowed to complete before any requests from that host are handled.
75 * If BreakDelayedCallBacks fails, then the host should remain
76 * down (and the request should be failed).
78 * CleanupCallBacks MUST be called periodically by the file server for
79 * this package to work correctly. Every 5 minutes is suggested.
82 #include <afsconfig.h>
83 #include <afs/param.h>
88 #include <stdlib.h> /* for malloc() */
89 #include <time.h> /* ANSI standard location for time stuff */
100 #ifdef HAVE_STRINGS_H
104 #include <afs/assert.h>
106 #include <afs/stds.h>
108 #include <afs/nfs.h> /* yuck. This is an abomination. */
111 #include <afscbint.h>
112 #include <afs/afsutil.h>
114 #include <afs/ihandle.h>
115 #include <afs/vnode.h>
116 #include <afs/volume.h>
119 #include <afs/ptclient.h> /* need definition of prlist for host.h */
123 extern int hostCount;
124 int ShowProblems = 1;
126 /* Maximum number of call backs to break at once, single fid */
127 /* There is some debate as to just how large this value should be */
128 /* Ideally, it would be very very large, but I am afraid that the */
129 /* cache managers will all send in their responses simultaneously, */
130 /* thereby swamping the file server. As a result, something like */
131 /* 10 or 15 might be a better bet. */
132 #define MAX_CB_HOSTS 10
134 /* max time to break a callback, otherwise client is dead or net is hosed */
137 #define u_byte unsigned char
139 struct cbcounters cbstuff;
153 } *FE; /* Don't use FE[0] */
156 afs_uint32 cnext; /* Next call back entry */
157 afs_uint32 fhead; /* Head of this call back chain */
158 u_byte thead; /* Head of timeout chain */
159 u_byte status; /* Call back status; see definitions, below */
160 afs_uint32 hhead; /* Head of host table chain */
161 afs_uint32 tprev, tnext; /* Timeout chain */
162 afs_uint32 hprev, hnext; /* Chain from host table */
163 unsigned short spare; /* make it a multiple of 32 bits. */
164 } *CB; /* Don't use CB[0] */
166 /* status values for status field of CallBack structure */
167 #define CB_NORMAL 1 /* Normal call back */
168 #define CB_DELAYED 2 /* Delayed call back due to rpc problems.
169 The call back entry will be added back to the
170 host list at the END of the list, so that
171 searching backwards in the list will find all
172 the (consecutive)host. delayed call back entries */
173 #define CB_VOLUME 3 /* Callback for a volume */
174 #define CB_BULK 4 /* Normal callbacks, handed out from FetchBulkStatus */
176 /* call back indices to pointers, and vice-versa */
177 #define itocb(i) ((i)?CB+(i):0)
178 #define cbtoi(cbp) (!(cbp)?0:(cbp)-CB)
180 /* file entry indices to pointers, and vice-versa */
181 #define itofe(i) ((i)?FE+(i):0)
182 #define fetoi(fep) (!(fep)?0:(fep)-FE)
184 /* Timeouts: there are 128 possible timeout values in effect at any
185 * given time. Each timeout represents timeouts in an interval of 128
186 * seconds. So the maximum timeout for a call back is 128*128=16384
187 * seconds, or 4 1/2 hours. The timeout cleanup stuff is called only
188 * if space runs out or by the file server every 5 minutes. This 5
189 * minute slack should be allowed for--so a maximum time of 4 hours
192 * Timeouts must be chosen to correspond to an exact multiple
193 * of 128, because all times are truncated to a 128 multiple, and
194 * timed out if the current truncated time is <= to the truncated time
195 * corresponding to the timeout queue.
198 /* Unix time to Call Back time, and vice-versa. Call back time is
199 in units of 128 seconds, corresponding to time queues. */
200 #define CBtime(uxtime) ((uxtime)>>7)
201 #define UXtime(cbtime) ((cbtime)<<7)
203 /* Given a Unix time, compute the closest Unix time that corresponds to
204 a time queue, rounding up */
205 #define TimeCeiling(uxtime) (((uxtime)+127)&~127)
207 /* Time to live for call backs depends upon number of users of the file.
208 * TimeOuts is indexed by this number/8 (using TimeOut macro). Times
209 * in this table are for the workstation; server timeouts, add
212 static int TimeOuts[] = {
213 /* Note: don't make the first entry larger than 4 hours (see above) */
214 4*60*60, /* 0-7 users */
215 1*60*60, /* 8-15 users */
216 30*60, /* 16-23 users */
217 15*60, /* 24-31 users */
218 15*60, /* 32-39 users */
219 10*60, /* 40-47 users */
220 10*60, /* 48-55 users */
221 10*60, /* 56-63 users */
222 }; /* Anything more: MinTimeOut */
224 /* minimum time given for a call back */
225 static int MinTimeOut = (7*60);
227 #define TimeOutCutoff ((sizeof(TimeOuts)/sizeof(TimeOuts[0]))*8)
228 #define TimeOut(nusers) ((nusers)>=TimeOutCutoff? MinTimeOut: TimeOuts[(nusers)>>3])
230 /* time out at server is 3 minutes more than ws */
231 #define ServerBias (3*60)
233 /* Heads of CB queues; a timeout index is 1+index into this array */
234 static afs_uint32 timeout[128];
236 /* Convert cbtime to timeout queue index */
237 #define TIndex(cbtime) (((cbtime)&127)+1)
239 /* Convert cbtime to pointer to timeout queue head */
240 #define THead(cbtime) (&timeout[TIndex(cbtime)-1])
242 static afs_int32 tfirst; /* cbtime of oldest unexpired call back time queue */
244 /* Normalize index into timeout array so that two such indices will be
245 ordered correctly, so that they can be compared to see which times
246 sooner, or so that the difference in time out times between them
248 #define TNorm(index) ((index)<TIndex(tfirst)?(index)+128:(index))
250 /* This converts a timeout index into the actual time it will expire */
251 #define TIndexToTime(index) (UXtime(TNorm(index) - TIndex(tfirst) + tfirst))
254 /* Convert pointer to timeout queue head to index, and vice versa */
255 #define ttoi(t) ((t-timeout)+1)
256 #define itot(i) ((timeout)+(i-1))
258 /* 16 byte object get/free routines */
264 struct cbstruct cba[MAX_CB_HOSTS]; /* re-entrant storage */
266 afs_uint32 thead; /* head of timeout queue for youngest callback */
270 struct CallBack *CBfree = 0;
271 struct FileEntry *FEfree = 0;
273 /* Prototypes for static routines */
274 static struct FileEntry *FindFE (register AFSFid *fid);
275 static struct CallBack *iGetCB(register int *nused);
276 static int iFreeCB(register struct CallBack *cb, register int *nused);
277 static struct FileEntry *iGetFE(register int *nused);
278 static int iFreeFE(register struct FileEntry *fe, register int *nused);
279 static int TAdd(register struct CallBack *cb, register afs_uint32 *thead);
280 static int TDel(register struct CallBack *cb);
281 static int HAdd(register struct CallBack *cb, register struct host *host);
282 static int HDel(register struct CallBack *cb);
283 static int CDel(struct CallBack *cb);
284 static int CDelPtr(register struct FileEntry *fe, register afs_uint32 *cbp);
285 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host);
286 static int FDel(register struct FileEntry *fe);
287 static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead, int type, int locked);
288 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas, struct AFSCBFids *afidp, struct host *xhost);
289 static int MultiBreakVolumeCallBack_r(struct host *host, int isheld, struct VCBParams *parms);
290 static int MultiBreakVolumeCallBack(struct host *host, int isheld, struct VCBParams *parms);
291 static int lih_r(register struct host *host, register int held, register struct host *hostp);
292 static int GetSomeSpace_r(struct host *hostp, int locked);
294 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
295 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
296 #define FreeCB(cb) iFreeCB((struct CallBack *)cb, &cbstuff.nCBs)
297 #define FreeFE(fe) iFreeFE((struct FileEntry *)fe, &cbstuff.nFEs)
299 /* Other protos - move out sometime */
300 extern void ShutDown();
302 #define VHASH 512 /* Power of 2 */
303 static afs_uint32 HashTable[VHASH]; /* File entry hash table */
304 #define VHash(volume, unique) (((volume)+(unique))&(VHASH-1))
306 static struct FileEntry *FindFE (register AFSFid *fid)
310 register struct FileEntry *fe;
312 hash = VHash(fid->Volume, fid->Unique);
313 for (fei=HashTable[hash]; fei; fei = fe->fnext) {
315 if (fe->volid == fid->Volume && fe->unique == fid->Unique &&
316 fe->vnode == fid->Vnode)
322 #ifndef INTERPRET_DUMP
324 static struct CallBack *iGetCB(register int *nused)
326 register struct CallBack *ret;
328 if ((ret = CBfree)) {
329 CBfree = (struct CallBack *)(((struct object *)ret)->next);
335 static int iFreeCB(register struct CallBack *cb, register int *nused)
337 ((struct object *)cb)->next = (struct object *)CBfree;
343 static struct FileEntry *iGetFE(register int *nused)
345 register struct FileEntry *ret;
347 if ((ret = FEfree)) {
348 FEfree = (struct FileEntry *)(((struct object *)ret)->next);
354 static int iFreeFE(register struct FileEntry *fe, register int *nused)
356 ((struct object *)fe)->next = (struct object *)FEfree;
362 /* Add cb to end of specified timeout list */
363 static int TAdd(register struct CallBack *cb, register afs_uint32 *thead)
366 (*thead) = cb->tnext = cb->tprev = cbtoi(cb);
368 register struct CallBack *thp = itocb(*thead);
370 cb->tprev = thp->tprev;
374 thp->tprev = (itocb(thp->tprev)->tnext = cbtoi(cb));
376 thp->tprev = cbtoi(cb);
379 cb->thead = ttoi(thead);
383 /* Delete call back entry from timeout list */
384 static int TDel(register struct CallBack *cb)
386 register afs_uint32 *thead = itot(cb->thead);
388 if (*thead == cbtoi(cb))
389 *thead = (*thead == cb->tnext? 0: cb->tnext);
390 if (itocb(cb->tprev))
391 itocb(cb->tprev)->tnext = cb->tnext;
392 if (itocb(cb->tnext))
393 itocb(cb->tnext)->tprev = cb->tprev;
397 /* Add cb to end of specified host list */
398 static int HAdd(register struct CallBack *cb, register struct host *host)
400 cb->hhead = h_htoi(host);
402 host->cblist = cb->hnext = cb->hprev = cbtoi(cb);
405 register struct CallBack *hhp = itocb(host->cblist);
407 cb->hprev = hhp->hprev;
408 cb->hnext = host->cblist;
409 hhp->hprev = (itocb(hhp->hprev)->hnext = cbtoi(cb));
414 /* Delete call back entry from host list */
415 static int HDel(register struct CallBack *cb)
417 register afs_uint32 *hhead = &h_itoh(cb->hhead)->cblist;
419 if (*hhead == cbtoi(cb))
420 *hhead = (*hhead == cb->hnext? 0: cb->hnext);
421 itocb(cb->hprev)->hnext = cb->hnext;
422 itocb(cb->hnext)->hprev = cb->hprev;
426 /* Delete call back entry from fid's chain of cb's */
427 /* N.B. This one also deletes the CB, and also possibly parent FE, so
428 * make sure that it is not on any other list before calling this
430 static int CDel(struct CallBack *cb)
433 struct FileEntry *fe = itofe(cb->fhead);
434 register afs_uint32 *cbp;
437 for (safety = 0, cbp = &fe->firstcb; *cbp && *cbp != cbi;
438 cbp = &itocb(*cbp)->cnext, safety++) {
439 if (safety > cbstuff.nblks + 10) {
441 ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
450 /* Same as CDel, but pointer to parent pointer to CB entry is passed,
451 * as well as file entry */
452 /* N.B. This one also deletes the CB, and also possibly parent FE, so
453 * make sure that it is not on any other list before calling this
455 int Ccdelpt=0, CcdelB=0;
457 static int CDelPtr(register struct FileEntry *fe,
458 register afs_uint32 *cbp)
460 register struct CallBack *cb;
475 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host)
477 register afs_uint32 hostindex = h_htoi(host);
478 register struct CallBack *cb;
479 register afs_uint32 *cbp;
482 for (safety = 0, cbp = &fe->firstcb; *cbp; cbp = &cb->cnext, safety++) {
483 if (safety > cbstuff.nblks) {
484 ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
489 if (cb->hhead == hostindex)
495 /* Delete file entry from hash table */
496 static int FDel(register struct FileEntry *fe)
498 register int fei = fetoi(fe);
499 register afs_uint32 *p = &HashTable[VHash(fe->volid, fe->unique)];
501 while (*p && *p != fei)
502 p = &itofe(*p)->fnext;
509 int InitCallBack(int nblks)
512 tfirst = CBtime(FT_ApproxTime());
513 /* N.B. FE's, CB's share same free list. If the sizes of either change,
514 FE and CB will have to be separated. The "-1", below, is because
515 FE[0] and CB[0] are not used--and not allocated */
516 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*nblks)))-1;
517 cbstuff.nFEs = nblks;
519 FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
520 CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
521 cbstuff.nCBs = nblks;
523 FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
524 cbstuff.nblks = nblks;
525 cbstuff.nbreakers = 0;
530 afs_int32 XCallBackBulk_r(struct host *ahost, struct AFSFid *fids,
533 struct AFSCallBack tcbs[AFSCBMAX];
541 rx_SetConnDeadTime(ahost->callback_rxcon, 4);
542 rx_SetConnHardDeadTime(ahost->callback_rxcon, AFS_HARDDEADTIME);
549 for(i=0;i<nfids && i < AFSCBMAX;i++) {
550 tcbs[i].CallBackVersion = CALLBACK_VERSION;
551 tcbs[i].ExpirationTime = 0;
552 tcbs[i].CallBackType = CB_DROPPED;
554 tf.AFSCBFids_len = i;
555 tf.AFSCBFids_val = &(fids[j]);
559 tc.AFSCBs_val = tcbs;
562 code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
569 /* the locked flag tells us if the host entry has already been locked
570 * by our parent. I don't think anybody actually calls us with the
571 * host locked, but here's how to make that work: GetSomeSpace has to
572 * change so that it doesn't attempt to lock any hosts < "host". That
573 * means that it might be unable to free any objects, so it has to
574 * return an exit status. If it fails, then AddCallBack1 might fail,
575 * as well. If so, the host->ResetDone should probably be set to 0,
576 * and we probably don't want to return a callback promise to the
577 * cache manager, either. */
578 int AddCallBack1(struct host *host, AFSFid *fid, afs_uint32 *thead,
579 int type, int locked)
586 retVal = AddCallBack1_r(host, fid, thead, type, 1);
595 static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead,
596 int type, int locked)
598 struct FileEntry *fe;
599 struct CallBack *cb = 0, *lastcb = 0;
600 struct FileEntry *newfe = 0;
602 afs_uint32 *Thead = thead;
603 struct CallBack *newcb = 0;
608 /* allocate these guys first, since we can't call the allocator with
609 the host structure locked -- or we might deadlock. However, we have
610 to avoid races with FindFE... */
611 while (!(newcb = GetCB())) {
612 GetSomeSpace_r(host, locked);
614 while(!(newfe = GetFE())) { /* Get it now, so we don't have to call */
615 /* GetSomeSpace with the host locked, later. This might turn out to */
616 /* have been unneccessary, but that's actually kind of unlikely, since */
617 /* most files are not shared. */
618 GetSomeSpace_r(host, locked);
622 h_Lock_r(host); /* this can yield, so do it before we get any */
627 if (type == CB_NORMAL) {
628 time_out = TimeCeiling(FT_ApproxTime()+TimeOut(fe?fe->ncbs:0)+ServerBias);
629 Thead = THead(CBtime(time_out));
631 else if (type == CB_VOLUME) {
632 time_out = TimeCeiling((60*120+FT_ApproxTime())+ServerBias);
633 Thead = THead(CBtime(time_out));
635 else if (type == CB_BULK) {
636 /* bulk status can get so many callbacks all at once, and most of them
637 * are probably not for things that will be used for long.
639 time_out = TimeCeiling(FT_ApproxTime() + ServerBias
640 + TimeOut(22 + (fe?fe->ncbs:0)));
641 Thead = THead(CBtime(time_out));
647 register afs_uint32 hash;
652 fe->volid = fid->Volume;
653 fe->vnode = fid->Vnode;
654 fe->unique = fid->Unique;
656 hash = VHash(fid->Volume, fid->Unique);
657 fe->fnext = HashTable[hash];
658 HashTable[hash] = fetoi(fe);
660 for (safety = 0, lastcb = cb = itocb(fe->firstcb); cb;
661 lastcb = cb, cb = itocb(cb->cnext), safety++) {
662 if (safety > cbstuff.nblks) {
663 ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
667 if (cb->hhead == h_htoi(host))
670 if (cb) {/* Already have call back: move to new timeout list */
671 /* don't change delayed callbacks back to normal ones */
672 if (cb->status != CB_DELAYED)
674 /* Only move if new timeout is longer */
675 if (TNorm(ttoi(Thead)) > TNorm(cb->thead)) {
682 *(lastcb?&lastcb->cnext:&fe->firstcb) = cbtoi(cb);
685 cb->fhead = fetoi(fe);
691 /* now free any still-unused callback or host entries */
692 if (newcb) FreeCB(newcb);
693 if (newfe) FreeFE(newfe);
695 if (!locked) /* freecb and freefe might(?) yield */
698 if (type == CB_NORMAL || type == CB_VOLUME || type == CB_BULK )
699 return time_out-ServerBias; /* Expires sooner at workstation */
704 /* Take an array full of hosts, all held. Break callbacks to them, and
705 * release the holds once you're done, except don't release xhost. xhost
706 * may be NULL. Currently only works for a single Fid in afidp array.
707 * If you want to make this work with multiple fids, you need to fix
708 * the error handling. One approach would be to force a reset if a
709 * multi-fid call fails, or you could add delayed callbacks for each
710 * fid. You probably also need to sort and remove duplicate hosts.
711 * When this is called from the BreakVolumeCallBacks path, it does NOT
712 * force a reset if the RPC fails, it just marks the host down and tries
713 * to create a delayed callback. */
714 /* N.B. be sure that code works when ncbas == 0 */
715 /* N.B. requires all the cba[*].hp pointers to be valid... */
716 /* This routine does not hold a lock on the host for the duration of
717 * the BreakCallBack RPC, which is a significant deviation from tradition.
718 * It _does_ get a lock on the host before setting VenusDown = 1,
719 * which is sufficient only if VenusDown = 0 only happens when the
720 * lock is held over the RPC and the subsequent VenusDown == 0
721 * wherever that is done. */
722 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
723 struct AFSCBFids *afidp, struct host *xhost)
726 struct rx_connection *conns[MAX_CB_HOSTS];
727 int opt_TO; /* secs, but internal adaptive parms are in ms */
728 static struct AFSCBs tc = {0,0};
730 assert(ncbas <= MAX_CB_HOSTS);
732 /* set up conns for multi-call */
733 for (i=0,j=0; i<ncbas; i++) {
734 struct host *thishost = cba[i].hp;
735 if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
738 conns[j++] = thishost->callback_rxcon;
741 rx_SetConnDeadTime (thishost->callback_rxcon, 4);
742 rx_SetConnHardDeadTime (thishost->callback_rxcon, AFS_HARDDEADTIME);
746 if (j) { /* who knows what multi would do with 0 conns? */
750 multi_RXAFSCB_CallBack(afidp, &tc);
757 /* If there's an error, we have to hunt for the right host.
758 * The conns array _should_ correspond one-to-one to the cba
759 * array, except in some rare cases it might be missing one
760 * or more elements. So the optimistic case is almost
761 * always right. At worst, it's the starting point for the
763 for (hp=0,i=multi_i;i<j;i++) {
764 hp = cba[i].hp; /* optimistic, but usually right */
768 if (conns[multi_i] == hp->callback_rxcon) {
775 ViceLog(0, ("BCB: INTERNAL ERROR: hp=%x, cba=%x\n",hp,cba));
779 ** try breaking callbacks on alternate interface addresses
781 if ( MultiBreakCallBackAlternateAddress(hp, afidp) )
785 ("BCB: Failed on file %u.%d.%d, host %s:%d is down\n",
786 afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
787 afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), hp->port));
792 hp->hostFlags |= VENUSDOWN;
794 * We always go into AddCallBack1_r with the host locked
796 AddCallBack1_r(hp,afidp->AFSCBFids_val,itot(idx), CB_DELAYED, 1);
807 for (i=0; i<ncbas; i++) {
810 if (hp && xhost != hp)
818 * Break all call backs for fid, except for the specified host (unless flag
819 * is true, in which case all get a callback message. Assumption: the specified
820 * host is h_Held, by the caller; the others aren't.
821 * Specified host may be bogus, that's ok. This used to check to see if the
822 * host was down in two places, once right after the host was h_held, and
823 * again after it was locked. That race condition is incredibly rare and
824 * relatively harmless even when it does occur, so we don't check for it now.
826 /* if flag is true, send a break callback msg to "host", too */
827 int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
829 struct FileEntry *fe;
830 struct CallBack *cb, *nextcb;
831 struct cbstruct cba[MAX_CB_HOSTS];
833 struct rx_connection *conns[MAX_CB_HOSTS];
838 ViceLog(7,("BCB: BreakCallBack(all but %s:%d, (%u,%d,%d))\n",
839 afs_inet_ntoa_r(xhost->host,hoststr), xhost->port, fid->Volume, fid->Vnode,
844 cbstuff.BreakCallBacks++;
849 hostindex = h_htoi(xhost);
850 cb = itocb(fe->firstcb);
851 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
852 /* the most common case is what follows the || */
855 tf.AFSCBFids_len = 1;
856 tf.AFSCBFids_val = fid;
859 for (ncbas=0; cb && ncbas<MAX_CB_HOSTS; cb=nextcb) {
860 nextcb = itocb(cb->cnext);
861 if ((cb->hhead != hostindex || flag)
862 && (cb->status == CB_BULK || cb->status == CB_NORMAL
863 || cb->status == CB_VOLUME) ) {
864 struct host *thishost = h_itoh(cb->hhead);
866 ViceLog(0,("BCB: BOGUS! cb->hhead is NULL!\n"));
868 else if (thishost->hostFlags & VENUSDOWN) {
869 ViceLog(7,("BCB: %s:%d is down; delaying break call back\n",
870 afs_inet_ntoa_r(thishost->host,hoststr), thishost->port));
871 cb->status = CB_DELAYED;
875 cba[ncbas].hp = thishost;
876 cba[ncbas].thead = cb->thead;
880 CDel(cb); /* Usually first; so this delete */
881 /* is reasonably inexpensive */
887 MultiBreakCallBack_r(cba, ncbas, &tf, xhost);
889 /* we need to to all these initializations again because MultiBreakCallBack may block */
894 cb = itocb(fe->firstcb);
895 if (!cb || ((fe->ncbs == 1) && (cb->hhead == hostindex) && !flag)) {
896 /* the most common case is what follows the || */
907 /* Delete (do not break) single call back for fid */
908 int DeleteCallBack(struct host *host, AFSFid *fid)
910 register struct FileEntry *fe;
911 register afs_uint32 *pcb;
914 cbstuff.DeleteCallBacks++;
922 ViceLog(8,("DCB: No call backs for fid (%u, %d, %d)\n",
923 fid->Volume, fid->Vnode, fid->Unique));
926 pcb = FindCBPtr(fe, host);
928 ViceLog(8,("DCB: No call back for host %s:%d, (%u, %d, %d)\n",
929 afs_inet_ntoa_r(host->host,hoststr), host->port, fid->Volume, fid->Vnode, fid->Unique));
943 * Delete (do not break) all call backs for fid. This call doesn't
944 * set all of the various host locks, but it shouldn't really matter
945 * since we're not adding callbacks, but deleting them. I'm not sure
946 * why it doesn't set the lock, however; perhaps it should.
948 int DeleteFileCallBacks(AFSFid *fid)
950 register struct FileEntry *fe;
951 register struct CallBack *cb;
952 register afs_uint32 cbi;
956 cbstuff.DeleteFiles++;
960 ViceLog(8,("DF: No fid (%u,%u,%u) to delete\n",
961 fid->Volume, fid->Vnode, fid->Unique));
964 for (n=0,cbi = fe->firstcb; cbi; n++) {
976 /* Delete (do not break) all call backs for host. The host should be
978 int DeleteAllCallBacks(struct host *host)
982 retVal = DeleteAllCallBacks_r(host);
987 int DeleteAllCallBacks_r(struct host *host)
989 register struct CallBack *cb;
990 register int cbi, first;
992 cbstuff.DeleteAllCallBacks++;
993 cbi = first = host->cblist;
995 ViceLog(8,("DV: no call backs\n"));
1003 } while (cbi != first);
1009 * Break all delayed call backs for host. Returns 1 if all call backs
1010 * successfully broken; 0 otherwise. Assumes host is h_Held and h_Locked.
1011 * Must be called with VenusDown set for this host
1013 int BreakDelayedCallBacks(struct host *host)
1017 retVal = BreakDelayedCallBacks_r(host);
1022 extern afsUUID FS_HostUUID;
1024 int BreakDelayedCallBacks_r(struct host *host)
1026 struct AFSFid fids[AFSCBMAX];
1027 u_byte thead[AFSCBMAX]; /* This should match thead in struct Callback */
1028 int cbi, first, nfids;
1029 struct CallBack *cb;
1030 struct interfaceAddr interf;
1034 cbstuff.nbreakers++;
1035 if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
1036 host->hostFlags &= ~ALTADDR; /* alterrnate addresses are invalid */
1037 if ( host->interface ) {
1039 code = RXAFSCB_InitCallBackState3(host->callback_rxcon,
1044 code = RXAFSCB_InitCallBackState(host->callback_rxcon);
1047 host->hostFlags |= ALTADDR; /* alternate addresses are valid */
1051 ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
1052 afs_inet_ntoa_r(host->host,hoststr), host->port));
1054 host->hostFlags |= VENUSDOWN;
1057 ViceLog(25,("InitCallBackState success on %s\n",afs_inet_ntoa_r(host->host,hoststr)));
1058 /* reset was done successfully */
1059 host->hostFlags |= RESETDONE;
1060 host->hostFlags &= ~VENUSDOWN;
1063 else while (!(host->hostFlags & HOSTDELETED)) {
1065 host->hostFlags &= ~VENUSDOWN; /* presume up */
1066 cbi = first = host->cblist;
1070 first = host->cblist;
1073 if (cb->status == CB_DELAYED) {
1074 register struct FileEntry *fe = itofe(cb->fhead);
1075 thead[nfids] = cb->thead;
1076 fids[nfids].Volume = fe->volid;
1077 fids[nfids].Vnode = fe->vnode;
1078 fids[nfids].Unique = fe->unique;
1084 } while (cbi && cbi != first && nfids < AFSCBMAX);
1090 if (XCallBackBulk_r(host, fids, nfids)) {
1091 /* Failed, again: put them back, probably with old
1096 ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
1097 afs_inet_ntoa_r(host->host,hoststr), host->port));
1099 for (i = 0; i<nfids; i++) {
1102 ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
1103 afs_inet_ntoa_r(host->host,hoststr), host->port,
1104 fids[i].Volume, fids[i].Vnode, fids[i].Unique));
1107 AddCallBack1_r(host, &fids[i], itot(thead[i]), CB_DELAYED, 1);
1108 * but it turns out to cause too many tricky locking problems.
1109 * now, if break delayed fails, screw it. */
1111 host->hostFlags |= VENUSDOWN; /* Failed */
1112 ClearHostCallbacks_r(host, 1/* locked */);
1116 if (nfids < AFSCBMAX)
1120 cbstuff.nbreakers--;
1121 return (host->hostFlags & VENUSDOWN);
1125 ** isheld is 0 if the host is held in h_Enumerate
1126 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1128 static int MultiBreakVolumeCallBack_r(struct host *host,
1129 int isheld, struct VCBParams *parms)
1134 return isheld; /* host is held only by h_Enumerate, do nothing */
1135 if ( host->hostFlags & HOSTDELETED )
1136 return 0; /* host is deleted, release hold */
1138 if (host->hostFlags & VENUSDOWN) {
1140 if (host->hostFlags & HOSTDELETED) {
1142 return 0; /* Release hold */
1144 ViceLog(8,("BVCB: volume call back for host %s:%d failed\n",
1145 afs_inet_ntoa_r(host->host,hoststr),host->port));
1147 ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
1148 afs_inet_ntoa_r(host->host,hoststr), host->port));
1150 DeleteAllCallBacks_r(host); /* Delete all callback state rather than
1151 attempting to selectively remember to
1152 delete the volume callbacks later */
1153 host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
1155 return 0; /* release hold */
1157 assert(parms->ncbas <= MAX_CB_HOSTS);
1159 /* Do not call MultiBreakCallBack on the current host structure
1160 ** because it would prematurely release the hold on the host
1162 if ( parms->ncbas == MAX_CB_HOSTS ) {
1163 struct AFSCBFids tf;
1165 tf.AFSCBFids_len = 1;
1166 tf.AFSCBFids_val = parms->fid;
1168 /* this releases all the hosts */
1169 MultiBreakCallBack_r(parms->cba, parms->ncbas, &tf, 0 /* xhost */);
1173 parms->cba[parms->ncbas].hp = host;
1174 parms->cba[(parms->ncbas)++].thead = parms->thead;
1175 return 1; /* DON'T release hold, because we still need it. */
1179 ** isheld is 0 if the host is held in h_Enumerate
1180 ** isheld is 1 if the host is held in BreakVolumeCallBacks
1182 static int MultiBreakVolumeCallBack(struct host *host, int isheld,
1183 struct VCBParams *parms)
1187 retval = MultiBreakVolumeCallBack_r(host, isheld, parms);
1193 * Break all call backs on a single volume. Don't call this with any
1194 * hosts h_held. Note that this routine clears the callbacks before
1195 * actually breaking them, and that the vnode isn't locked during this
1196 * operation, so that people might see temporary callback loss while
1197 * this function is executing. It is just a temporary state, however,
1198 * since the callback will be broken later by this same function.
1200 * Now uses multi-RX for CallBack RPC. Note that the
1201 * multiBreakCallBacks routine does not force a reset if the RPC
1202 * fails, unlike the previous version of this routine, but does create
1203 * a delayed callback. Resets will be forced if the host is
1204 * determined to be down before the RPC is executed.
1206 int BreakVolumeCallBacks(afs_uint32 volume)
1211 struct CallBack *cb;
1212 struct FileEntry *fe;
1214 struct VCBParams henumParms;
1215 afs_uint32 tthead = 0; /* zero is illegal value */
1218 fid.Volume = volume, fid.Vnode = fid.Unique = 0;
1219 for (hash=0; hash<VHASH; hash++) {
1220 for (feip = &HashTable[hash]; (fe = itofe(*feip)); ) {
1221 if (fe->volid == volume) {
1222 register struct CallBack *cbnext;
1223 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1224 host = h_itoh(cb->hhead);
1226 cbnext = itocb(cb->cnext);
1227 if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
1233 /* leave hold for MultiBreakVolumeCallBack to clear */
1244 /* didn't find any callbacks, so return right away. */
1248 henumParms.ncbas = 0;
1249 henumParms.fid = &fid;
1250 henumParms.thead = tthead;
1252 h_Enumerate(MultiBreakVolumeCallBack, (char *) &henumParms);
1255 if (henumParms.ncbas) { /* do left-overs */
1256 struct AFSCBFids tf;
1257 tf.AFSCBFids_len = 1;
1258 tf.AFSCBFids_val = &fid;
1260 MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
1262 henumParms.ncbas = 0;
1270 * Delete all timed-out call back entries (to be called periodically by file
1273 int CleanupTimedOutCallBacks(void)
1276 CleanupTimedOutCallBacks_r();
1280 int CleanupTimedOutCallBacks_r(void)
1282 afs_uint32 now = CBtime(FT_ApproxTime());
1283 register afs_uint32 *thead;
1284 register struct CallBack *cb;
1285 register int ntimedout = 0;
1288 while (tfirst <= now) {
1290 cbi = *(thead = THead(tfirst));
1295 ViceLog(8,("CCB: deleting timed out call back %s:%d, (%u,%u,%u)\n",
1296 afs_inet_ntoa_r(h_itoh(cb->hhead)->host, hoststr), h_itoh(cb->hhead)->port,
1297 itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
1298 itofe(cb->fhead)->unique));
1302 if (ntimedout > cbstuff.nblks) {
1303 ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
1304 DumpCallBackState();
1307 } while (cbi != *thead);
1312 cbstuff.CBsTimedOut += ntimedout;
1313 ViceLog(7,("CCB: deleted %d timed out callbacks\n", ntimedout));
1314 return (ntimedout > 0);
1317 static struct host *lih_host;
1319 static int lih_r(register struct host *host, register int held,
1320 register struct host *hostp)
1323 && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
1324 && (!lih_host || host->ActiveCall < lih_host->ActiveCall) ) {
1330 /* This could be upgraded to get more space each time */
1331 /* first pass: find the oldest host which isn't held by anyone */
1332 /* second pass: find the oldest host who isn't "me" */
1333 /* always called with hostp unlocked */
1334 extern struct host *hostList;
1335 static int GetSomeSpace_r(struct host *hostp, int locked)
1337 register struct host *hp, *hp1 = (struct host *)0, *hp2 = hostList;
1340 cbstuff.GotSomeSpaces++;
1341 ViceLog(5,("GSS: First looking for timed out call backs via CleanupCallBacks\n"));
1342 if (CleanupTimedOutCallBacks_r()) {
1348 h_Enumerate_r(lih_r, hp2, (char *)hp1);
1352 if ( ! ClearHostCallbacks_r(hp, 0 /* not locked or held */) )
1359 ViceLog(5,("GSS: Try harder for longest inactive host cnt= %d\n", i));
1361 * Next time try getting callbacks from any host even if
1362 * it's deleted (that's actually great since we can freely
1363 * remove its callbacks) or it's held since the only other
1364 * option is starvation for the file server (i.e. until the
1365 * callback timeout arrives).
1371 * No choice to clear this host's callback state
1373 /* third pass: we still haven't gotten any space, so we free what we had
1374 * previously passed over. */
1379 ClearHostCallbacks_r(hostp, 1/*already locked*/);
1386 /* locked - set if caller has already locked the host */
1387 int ClearHostCallbacks(struct host *hp, int locked)
1391 retVal = ClearHostCallbacks_r(hp, locked);
1396 /* locked - set if caller has already locked the host */
1397 int ClearHostCallbacks_r(struct host *hp, int locked)
1399 struct interfaceAddr interf;
1404 ViceLog(5,("GSS: Delete longest inactive host %s\n", afs_inet_ntoa_r(hp->host,hoststr)));
1405 if ( !(held = h_Held_r(hp)) )
1408 /** Try a non-blocking lock. If the lock is already held return
1409 * after releasing hold on hp
1412 if ( h_NBLock_r(hp) ) {
1418 if (hp->Console & 2) {
1420 * If the special console field is set it means that a thread
1421 * is waiting in AddCallBack1 after it set pointers to the
1422 * file entry and/or callback entry. Because of the bogus
1423 * usage of h_hold it won't prevent from another thread, this
1424 * one, to remove all the callbacks so just to be safe we keep
1425 * a reference. NOTE, on the last phase we'll free the calling
1426 * host's callbacks but that's ok...
1430 DeleteAllCallBacks_r(hp);
1431 if (hp->hostFlags & VENUSDOWN) {
1432 hp->hostFlags &= ~RESETDONE; /* remember that we must do a reset */
1434 /* host is up, try a call */
1435 hp->hostFlags &= ~ALTADDR; /* alternate addresses are invalid */
1436 if (hp->interface) {
1438 code = RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
1442 code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
1445 hp->hostFlags |= ALTADDR; /* alternate addresses are valid */
1448 /* failed, mark host down and need reset */
1449 hp->hostFlags |= VENUSDOWN;
1450 hp->hostFlags &= ~RESETDONE;
1452 /* reset succeeded, we're done */
1453 hp->hostFlags |= RESETDONE;
1464 #endif /* INTERPRET_DUMP */
1467 int PrintCallBackStats(void)
1469 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",
1470 cbstuff.AddCallBacks, cbstuff.BreakCallBacks, cbstuff.DeleteCallBacks,
1471 cbstuff.DeleteFiles, cbstuff.CBsTimedOut, cbstuff.GotSomeSpaces,
1472 cbstuff.DeleteAllCallBacks);
1473 fprintf(stderr, "%d CBs, %d FEs, (%d of total of %d 16-byte blocks)\n",
1474 cbstuff.nCBs, cbstuff.nFEs, cbstuff.nCBs+cbstuff.nFEs, cbstuff.nblks);
1479 #define MAGIC 0x12345678 /* To check byte ordering of dump when it is read in */
1481 #ifndef INTERPRET_DUMP
1483 int DumpCallBackState(void)
1486 afs_uint32 magic = MAGIC, now = FT_ApproxTime(), freelisthead;
1488 fd = open(AFSDIR_SERVER_CBKDUMP_FILEPATH, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1490 ViceLog(0, ("Couldn't create callback dump file %s\n", AFSDIR_SERVER_CBKDUMP_FILEPATH));
1493 write(fd, &magic, sizeof(magic));
1494 write(fd, &now, sizeof(now));
1495 write(fd, &cbstuff, sizeof(cbstuff));
1496 write(fd, TimeOuts, sizeof(TimeOuts));
1497 write(fd, timeout, sizeof(timeout));
1498 write(fd, &tfirst, sizeof(tfirst));
1499 freelisthead = cbtoi((struct CallBack *) CBfree);
1500 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1501 freelisthead = fetoi((struct FileEntry *) FEfree);
1502 write(fd, &freelisthead, sizeof(freelisthead)); /* This is a pointer */
1503 write(fd, HashTable, sizeof(HashTable));
1504 write(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1505 write(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1513 #ifdef INTERPRET_DUMP
1515 /* This is only compiled in for the callback analyzer program */
1516 /* Returns the time of the dump */
1517 time_t ReadDump(char *file)
1520 afs_uint32 magic, freelisthead;
1523 fd = open(file, O_RDONLY);
1525 fprintf(stderr, "Couldn't read dump file %s\n", file);
1528 read(fd, &magic, sizeof(magic));
1529 if (magic != MAGIC) {
1530 fprintf(stderr, "Magic number of %s is invalid. You might be trying to\n",
1533 "run this program on a machine type with a different byte ordering.\n");
1536 read(fd, &now, sizeof(now));
1537 read(fd, &cbstuff, sizeof(cbstuff));
1538 read(fd, TimeOuts, sizeof(TimeOuts));
1539 read(fd, timeout, sizeof(timeout));
1540 read(fd, &tfirst, sizeof(tfirst));
1541 read(fd, &freelisthead, sizeof(freelisthead));
1542 CB = ((struct CallBack *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1543 FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*cbstuff.nblks)))-1;
1544 CBfree = (struct CallBack *) itocb(freelisthead);
1545 read(fd, &freelisthead, sizeof(freelisthead));
1546 FEfree = (struct FileEntry *) itofe(freelisthead);
1547 read(fd, HashTable, sizeof(HashTable));
1548 read(fd, &CB[1], sizeof(CB[1])*cbstuff.nblks); /* CB stuff */
1549 read(fd, &FE[1], sizeof(FE[1])*cbstuff.nblks); /* FE stuff */
1551 perror("Error reading dumpfile");
1557 #include "AFS_component_version_number.c"
1559 int main(int argc, char **argv)
1561 int err = 0, cbi = 0, stats = 0, noptions = 0, all = 0, vol = 0, raw = 0;
1563 register struct FileEntry *fe;
1564 register struct CallBack *cb;
1567 memset(&fid, 0, sizeof(fid));
1569 while (argc && **argv == '-') {
1572 if (!strcmp(*argv, "-host")) {
1578 cbi = atoi(*++argv);
1580 else if (!strcmp(*argv, "-fid")) {
1586 fid.Volume = atoi(*++argv);
1587 fid.Vnode = atoi(*++argv);
1588 fid.Unique = atoi(*++argv);
1590 else if (!strcmp(*argv, "-time")) {
1591 fprintf(stderr, "-time not supported\n");
1594 else if (!strcmp(*argv, "-stats")) {
1597 else if (!strcmp(*argv, "-all")) {
1600 else if (!strcmp(*argv, "-raw")) {
1603 else if (!strcmp(*argv, "-volume")) {
1609 vol = atoi(*++argv);
1614 if (err || argc != 1) {
1616 "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
1617 fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
1620 now = ReadDump(*argv);
1621 if (stats || noptions == 0) {
1622 time_t uxtfirst = UXtime(tfirst);
1623 printf("The time of the dump was %u %s", now, ctime(&now));
1624 printf("The last time cleanup ran was %u %s", uxtfirst, ctime(&uxtfirst));
1625 PrintCallBackStats();
1629 register afs_uint32 *feip;
1630 register struct CallBack *cb;
1631 register struct FileEntry *fe;
1633 for (hash=0; hash<VHASH; hash++) {
1634 for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
1635 if (!vol || (fe->volid == vol)) {
1636 register struct CallBack *cbnext;
1637 for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
1639 cbnext = itocb(cb->cnext);
1649 afs_uint32 cfirst = cbi;
1654 } while (cbi != cfirst);
1659 printf("No callback entries for %u.%u\n", fid.Volume, fid.Vnode);
1662 cb = itocb(fe->firstcb);
1665 cb = itocb(cb->cnext);
1669 struct FileEntry *fe;
1671 for (i=1; i < cbstuff.nblks; i++) {
1672 p = (afs_int32 *) &FE[i];
1673 printf("%d:%12x%12x%12x%12x\n", i, p[0], p[1], p[2], p[3]);
1678 int PrintCB(register struct CallBack *cb, afs_uint32 now)
1680 struct FileEntry *fe = itofe(cb->fhead);
1681 time_t expires = TIndexToTime(cb->thead);
1683 printf("vol=%u vn=%u cbs=%d hi=%d st=%d, exp in %d secs at %s",
1684 fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
1685 expires - now, ctime(&expires));
1690 #if !defined(INTERPRET_DUMP)
1692 ** try breaking calbacks on afidp from host. Use multi_rx.
1693 ** return 0 on success, non-zero on failure
1695 int MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afidp)
1699 retVal = MultiBreakCallBackAlternateAddress_r(host, afidp);
1704 int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *afidp)
1707 struct rx_connection** conns;
1708 struct rx_connection* connSuccess = 0;
1710 static struct rx_securityClass *sc = 0;
1711 static struct AFSCBs tc = {0,0};
1714 /* nothing more can be done */
1715 if ( !host->interface ) return 1; /* failure */
1717 assert(host->interface->numberOfInterfaces > 0 );
1719 /* the only address is the primary interface */
1720 if ( host->interface->numberOfInterfaces == 1 )
1721 return 1; /* failure */
1723 /* initialise a security object only once */
1725 sc = rxnull_NewClientSecurityObject();
1727 i = host->interface->numberOfInterfaces;
1728 addr = malloc(i * sizeof(afs_int32));
1729 conns = malloc(i * sizeof(struct rx_connection *));
1731 /* initialize alternate rx connections */
1732 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1734 /* this is the current primary address */
1735 if ( host->host == host->interface->addr[i] )
1738 addr[j] = host->interface->addr[i];
1739 conns[j] = rx_NewConnection (host->interface->addr[i],
1740 host->port, 1, sc, 0);
1741 rx_SetConnDeadTime(conns[j], 2);
1742 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1746 assert(j); /* at least one alternate address */
1747 ViceLog(125,("Starting multibreakcall back on all addr for host %s\n",
1748 afs_inet_ntoa_r(host->host,hoststr)));
1752 multi_RXAFSCB_CallBack(afidp, &tc);
1757 if ( host->callback_rxcon )
1758 rx_DestroyConnection(host->callback_rxcon);
1759 host->callback_rxcon = conns[multi_i];
1760 host->host = addr[multi_i];
1761 connSuccess = conns[multi_i];
1762 rx_SetConnDeadTime(host->callback_rxcon, 50);
1763 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1764 ViceLog(125,("multibreakcall success with addr %s\n",
1765 afs_inet_ntoa_r(addr[multi_i],hoststr)));
1772 /* Destroy all connections except the one on which we succeeded */
1773 for ( i=0; i < j; i++)
1774 if ( conns[i] != connSuccess )
1775 rx_DestroyConnection(conns[i] );
1780 if ( connSuccess ) return 0; /* success */
1781 else return 1; /* failure */
1786 ** try multiRX probes to host.
1787 ** return 0 on success, non-zero on failure
1789 int MultiProbeAlternateAddress_r(struct host *host)
1792 struct rx_connection** conns;
1793 struct rx_connection* connSuccess = 0;
1795 static struct rx_securityClass *sc = 0;
1798 /* nothing more can be done */
1799 if ( !host->interface ) return 1; /* failure */
1801 assert(host->interface->numberOfInterfaces > 0 );
1803 /* the only address is the primary interface */
1804 if ( host->interface->numberOfInterfaces == 1 )
1805 return 1; /* failure */
1807 /* initialise a security object only once */
1809 sc = rxnull_NewClientSecurityObject();
1811 i = host->interface->numberOfInterfaces;
1812 addr = malloc(i * sizeof(afs_int32));
1813 conns = malloc(i * sizeof(struct rx_connection *));
1815 /* initialize alternate rx connections */
1816 for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
1818 /* this is the current primary address */
1819 if ( host->host == host->interface->addr[i] )
1822 addr[j] = host->interface->addr[i];
1823 conns[j] = rx_NewConnection (host->interface->addr[i],
1824 host->port, 1, sc, 0);
1825 rx_SetConnDeadTime(conns[j], 2);
1826 rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
1830 assert(j); /* at least one alternate address */
1831 ViceLog(125,("Starting multiprobe on all addr for host %s\n",
1832 afs_inet_ntoa_r(host->host,hoststr)));
1836 multi_RXAFSCB_ProbeUuid(&host->interface->uuid);
1841 if ( host->callback_rxcon )
1842 rx_DestroyConnection(host->callback_rxcon);
1843 host->callback_rxcon = conns[multi_i];
1844 host->host = addr[multi_i];
1845 connSuccess = conns[multi_i];
1846 rx_SetConnDeadTime(host->callback_rxcon, 50);
1847 rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
1848 ViceLog(125,("multiprobe success with addr %s\n",
1849 afs_inet_ntoa_r(addr[multi_i],hoststr)));
1856 /* Destroy all connections except the one on which we succeeded */
1857 for ( i=0; i < j; i++)
1858 if ( conns[i] != connSuccess )
1859 rx_DestroyConnection(conns[i] );
1864 if ( connSuccess ) return 0; /* success */
1865 else return 1; /* failure */
1868 #endif /* !defined(INTERPRET_DUMP) */