proto-20030425
[openafs.git] / src / viced / callback.c
index e5be078..441d087 100644 (file)
@@ -108,18 +108,19 @@ RCSID("$Header$");
 #include <afs/nfs.h>   /* yuck.  This is an abomination. */
 #include <lwp.h>
 #include <rx/rx.h>
-#include <afs/afscbint.h>
+#include <afscbint.h>
 #include <afs/afsutil.h>
 #include <lock.h>
 #include <afs/ihandle.h>
 #include <afs/vnode.h>
 #include <afs/volume.h>
+#include "viced_prototypes.h"
 #include "viced.h"
 
 #include <afs/ptclient.h>  /* need definition of prlist for host.h */
 #include "host.h"
 
-
+extern afsUUID FS_HostUUID;
 extern int hostCount;
 int ShowProblems = 1;
 
@@ -145,12 +146,15 @@ struct cbstruct {
 
 struct FileEntry {
     afs_uint32     vnode;      
-    afs_uint32         unique;
+    afs_uint32      unique;
     afs_uint32     volid;
     afs_uint32     fnext;
     afs_uint32     ncbs;
     afs_uint32     firstcb;
+    afs_uint32      status;
+    afs_uint32      spare;
 } *FE; /* Don't use FE[0] */
+#define FE_LATER 0x1
 
 struct CallBack {
     afs_uint32     cnext;              /* Next call back entry */
@@ -163,7 +167,7 @@ struct CallBack {
     unsigned short  spare;              /* make it a multiple of 32 bits. */
 } *CB; /* Don't use CB[0] */
 
-/* status bits for status field of CallBack structure */
+/* status values for status field of CallBack structure */
 #define CB_NORMAL   1  /* Normal call back */
 #define CB_DELAYED  2  /* Delayed call back due to rpc problems.
                        The call back entry will be added back to the
@@ -280,16 +284,18 @@ static int TAdd(register struct CallBack *cb, register afs_uint32 *thead);
 static int TDel(register struct CallBack *cb);
 static int HAdd(register struct CallBack *cb, register struct host *host);
 static int HDel(register struct CallBack *cb);
-static int CDel(struct CallBack *cb);
-static int CDelPtr(register struct FileEntry *fe, register afs_uint32 *cbp);
+static int CDel(struct CallBack *cb, int deletefe);
+static int CDelPtr(register struct FileEntry *fe, register afs_uint32 *cbp, int deletefe);
 static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host);
 static int FDel(register struct FileEntry *fe);
 static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead, int type, int locked);
 static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas, struct AFSCBFids *afidp, struct host *xhost);
-static int MultiBreakVolumeCallBack_r(struct host *host, int isheld, struct VCBParams *parms);
+static int MultiBreakVolumeCallBack_r(struct host *host, int isheld, struct VCBParams *parms, int deletefe);
 static int MultiBreakVolumeCallBack(struct host *host, int isheld, struct VCBParams *parms);
+static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld, struct VCBParams *parms);
 static int lih_r(register struct host *host, register int held, register struct host *hostp);
 static int GetSomeSpace_r(struct host *hostp, int locked);
+static int ClearHostCallbacks_r(struct host *hp, int locked);
 
 #define GetCB() ((struct CallBack *)iGetCB(&cbstuff.nCBs))
 #define GetFE() ((struct FileEntry *)iGetFE(&cbstuff.nFEs))
@@ -427,7 +433,7 @@ static int HDel(register struct CallBack *cb)
 /* N.B.  This one also deletes the CB, and also possibly parent FE, so
  * make sure that it is not on any other list before calling this
  * routine */
-static int CDel(struct CallBack *cb)
+static int CDel(struct CallBack *cb, int deletefe)
 {
     int cbi = cbtoi(cb);
     struct FileEntry *fe = itofe(cb->fhead);
@@ -440,10 +446,10 @@ static int CDel(struct CallBack *cb)
        assert(0);
        ViceLog(0,("CDel: Internal Error -- shutting down: wanted %d from %d, now at %d\n",cbi,fe->firstcb,*cbp));
        DumpCallBackState();
-       ShutDown();
+       ShutDownAndCore(PANIC);
       }
     }
-    CDelPtr(fe, cbp);
+    CDelPtr(fe, cbp, deletefe);
     return 0;
 }
 
@@ -455,7 +461,7 @@ static int CDel(struct CallBack *cb)
 int Ccdelpt=0, CcdelB=0;
 
 static int CDelPtr(register struct FileEntry *fe, 
-       register afs_uint32 *cbp)
+       register afs_uint32 *cbp, int deletefe)
 {
     register struct CallBack *cb;
 
@@ -467,7 +473,7 @@ static int CDelPtr(register struct FileEntry *fe,
        CcdelB++;
     *cbp = cb->cnext;
     FreeCB(cb);
-    if (--fe->ncbs == 0)
+    if (deletefe && (--fe->ncbs == 0))
        FDel(fe);
     return 0;
 }
@@ -483,7 +489,7 @@ static afs_uint32 *FindCBPtr(struct FileEntry *fe, struct host *host)
        if (safety > cbstuff.nblks) {
          ViceLog(0,("FindCBPtr: Internal Error -- shutting down.\n"));
          DumpCallBackState();
-         ShutDown();
+         ShutDownAndCore(PANIC);
        }
        cb = itocb(*cbp);
        if (cb->hhead == hostindex)
@@ -510,14 +516,21 @@ int InitCallBack(int nblks)
 {
     H_LOCK
     tfirst = CBtime(FT_ApproxTime());
-    /* N.B. FE's, CB's share same free list.  If the sizes of either change,
-      FE and CB will have to be separated.  The "-1", below, is because
+    /* N.B. The "-1", below, is because
       FE[0] and CB[0] are not used--and not allocated */
     FE = ((struct FileEntry *)(malloc(sizeof(struct FileEntry)*nblks)))-1;
+    if (!FE) {
+       ViceLog(0, ("Failed malloc in InitCallBack\n"));
+       assert(0);
+    }
     cbstuff.nFEs = nblks;
     while (cbstuff.nFEs)
        FreeFE(&FE[cbstuff.nFEs]); /* This is correct */
     CB = ((struct CallBack *)(malloc(sizeof(struct CallBack)*nblks)))-1;
+    if (!CB) {
+       ViceLog(0, ("Failed malloc in InitCallBack\n"));
+       assert(0);
+    }
     cbstuff.nCBs = nblks;
     while (cbstuff.nCBs)
        FreeCB(&CB[cbstuff.nCBs]); /* This is correct */
@@ -662,7 +675,7 @@ static int AddCallBack1_r(struct host *host, AFSFid *fid, afs_uint32 *thead,
        if (safety > cbstuff.nblks) {
          ViceLog(0,("AddCallBack1: Internal Error -- shutting down.\n"));
          DumpCallBackState();
-         ShutDown();
+         ShutDownAndCore(PANIC);
        }
        if (cb->hhead == h_htoi(host))
            break;
@@ -784,7 +797,7 @@ static void MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
                ViceLog(7, 
                  ("BCB: Failed on file %u.%d.%d, host %s:%d is down\n",
                   afidp->AFSCBFids_val->Volume, afidp->AFSCBFids_val->Vnode,
-                  afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), hp->port));
+                  afidp->AFSCBFids_val->Unique, afs_inet_ntoa_r(hp->host,hoststr), ntohs(hp->port)));
                }
 
                H_LOCK
@@ -836,7 +849,7 @@ int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
     char hoststr[16];
 
     ViceLog(7,("BCB: BreakCallBack(all but %s:%d, (%u,%d,%d))\n",
-              afs_inet_ntoa_r(xhost->host,hoststr), xhost->port, fid->Volume, fid->Vnode, 
+              afs_inet_ntoa_r(xhost->host,hoststr), ntohs(xhost->port), fid->Volume, fid->Vnode, 
               fid->Unique));
 
     H_LOCK
@@ -867,7 +880,7 @@ int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
          }
          else if (thishost->hostFlags & VENUSDOWN) {
            ViceLog(7,("BCB: %s:%d is down; delaying break call back\n",
-                      afs_inet_ntoa_r(thishost->host,hoststr), thishost->port));
+                      afs_inet_ntoa_r(thishost->host,hoststr), ntohs(thishost->port)));
            cb->status = CB_DELAYED;
          }
          else {
@@ -877,8 +890,8 @@ int BreakCallBack(struct host *xhost, AFSFid *fid, int flag)
            ncbas++;
            TDel(cb);
            HDel(cb);
-           CDel(cb); /* Usually first; so this delete */
-                     /* is reasonably inexpensive */
+           CDel(cb, 1); /* Usually first; so this delete 
+                           is reasonably inexpensive */
          }
        }
       }
@@ -926,14 +939,14 @@ int DeleteCallBack(struct host *host, AFSFid *fid)
     pcb = FindCBPtr(fe, host);
     if (!*pcb) {
        ViceLog(8,("DCB: No call back for host %s:%d, (%u, %d, %d)\n",
-           afs_inet_ntoa_r(host->host,hoststr), host->port, fid->Volume, fid->Vnode, fid->Unique));
+           afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port), fid->Volume, fid->Vnode, fid->Unique));
        h_Unlock_r(host);
        H_UNLOCK
        return 0;
     }
     HDel(itocb(*pcb));
     TDel(itocb(*pcb));
-    CDelPtr(fe, pcb);
+    CDelPtr(fe, pcb, 1);
     h_Unlock_r(host);
     H_UNLOCK
     return 0;
@@ -975,16 +988,7 @@ int DeleteFileCallBacks(AFSFid *fid)
 
 /* Delete (do not break) all call backs for host.  The host should be
  * locked. */
-int DeleteAllCallBacks(struct host *host)
-{
-    int retVal;
-    H_LOCK
-    retVal = DeleteAllCallBacks_r(host);
-    H_UNLOCK
-    return retVal;
-}
-
-int DeleteAllCallBacks_r(struct host *host)
+int DeleteAllCallBacks_r(struct host *host, int deletefe)
 {
     register struct CallBack *cb;
     register int cbi, first;
@@ -999,7 +1003,7 @@ int DeleteAllCallBacks_r(struct host *host)
        cb = itocb(cbi);
        cbi = cb->hnext;
        TDel(cb);
-       CDel(cb);
+       CDel(cb, deletefe);
     } while (cbi != first);
     host->cblist = 0;
     return 0;
@@ -1019,8 +1023,6 @@ int BreakDelayedCallBacks(struct host *host)
     return retVal;
 }
 
-extern afsUUID FS_HostUUID;
-
 int BreakDelayedCallBacks_r(struct host *host)
 {
     struct AFSFid fids[AFSCBMAX];
@@ -1049,7 +1051,7 @@ int BreakDelayedCallBacks_r(struct host *host)
            if (ShowProblems) {
                ViceLog(0,
           ("CB: Call back connect back failed (in break delayed) for %s:%d\n",
-                       afs_inet_ntoa_r(host->host,hoststr), host->port));
+                       afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
              }
            host->hostFlags |= VENUSDOWN;
        }
@@ -1079,7 +1081,7 @@ int BreakDelayedCallBacks_r(struct host *host)
                nfids++;
                HDel(cb);
                TDel(cb);
-               CDel(cb);
+               CDel(cb, 1);
            }
        } while (cbi && cbi != first && nfids < AFSCBMAX);
 
@@ -1094,13 +1096,13 @@ int BreakDelayedCallBacks_r(struct host *host)
            if (ShowProblems) {
                ViceLog(0,
             ("CB: XCallBackBulk failed, host=%s:%d; callback list follows:\n",
-                   afs_inet_ntoa_r(host->host,hoststr), host->port));
+                   afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
            }
            for (i = 0; i<nfids; i++) {
                if (ShowProblems) {
                    ViceLog(0,
                    ("CB: Host %s:%d, file %u.%u.%u (part of bulk callback)\n",
-                              afs_inet_ntoa_r(host->host,hoststr), host->port, 
+                              afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port), 
                               fids[i].Volume, fids[i].Vnode, fids[i].Unique));
                }
                /* used to do this:
@@ -1118,6 +1120,9 @@ int BreakDelayedCallBacks_r(struct host *host)
     }
 
     cbstuff.nbreakers--;
+    /* If we succeeded it's always ok to unset HFE_LATER */
+    if (!host->hostFlags & VENUSDOWN)
+       host->hostFlags &= ~HFE_LATER;
     return (host->hostFlags & VENUSDOWN);
 }
 
@@ -1126,7 +1131,7 @@ int BreakDelayedCallBacks_r(struct host *host)
 ** isheld is 1 if the host is held in BreakVolumeCallBacks
 */
 static int MultiBreakVolumeCallBack_r(struct host *host, 
-       int isheld, struct VCBParams *parms)
+       int isheld, struct VCBParams *parms, int deletefe)
 {
     char hoststr[16];
 
@@ -1142,14 +1147,16 @@ static int MultiBreakVolumeCallBack_r(struct host *host,
            return 0;      /* Release hold */
        }
        ViceLog(8,("BVCB: volume call back for host %s:%d failed\n",
-                afs_inet_ntoa_r(host->host,hoststr),host->port));
+                afs_inet_ntoa_r(host->host,hoststr),ntohs(host->port)));
        if (ShowProblems) {
            ViceLog(0, ("CB: volume callback for host %s:%d failed\n",
-                   afs_inet_ntoa_r(host->host,hoststr), host->port));
+                   afs_inet_ntoa_r(host->host,hoststr), ntohs(host->port)));
        }
-       DeleteAllCallBacks_r(host); /* Delete all callback state rather than
-                                    attempting to selectively remember to
-                                    delete the volume callbacks later */
+       DeleteAllCallBacks_r(host, deletefe); /* Delete all callback state 
+                                                rather than attempting to 
+                                                selectively remember to
+                                                delete the volume callbacks
+                                                later */
        host->hostFlags &= ~RESETDONE; /* Do InitCallBackState when host returns */
        h_Unlock_r(host);
        return 0; /* release hold */
@@ -1184,7 +1191,21 @@ static int MultiBreakVolumeCallBack(struct host *host, int isheld,
 {
     int retval;
     H_LOCK
-    retval = MultiBreakVolumeCallBack_r(host, isheld, parms);
+    retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 1);
+    H_UNLOCK
+    return retval;
+}
+
+/*
+** isheld is 0 if the host is held in h_Enumerate
+** isheld is 1 if the host is held in BreakVolumeCallBacks
+*/
+static int MultiBreakVolumeLaterCallBack(struct host *host, int isheld, 
+       struct VCBParams *parms)
+{
+    int retval;
+    H_LOCK
+    retval = MultiBreakVolumeCallBack_r(host, isheld, parms, 0);
     H_UNLOCK
     return retval;
 }
@@ -1266,6 +1287,144 @@ int BreakVolumeCallBacks(afs_uint32 volume)
     return 0;
 }
 
+#ifdef AFS_PTHREAD_ENV
+extern pthread_cond_t fsync_cond;
+#else
+extern char fsync_wait[];
+#endif
+
+int BreakVolumeCallBacksLater(afs_uint32 volume)
+{
+    int hash;
+    afs_int32 *feip;
+    struct FileEntry *fe;
+    struct CallBack *cb;
+    struct host *host;
+    int found = 0;
+
+    ViceLog(25, ("Setting later on volume %d\n", volume));
+    H_LOCK
+    for (hash=0; hash<VHASH; hash++) {
+       for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
+           if (fe->volid == volume) {
+               register struct CallBack *cbnext;
+                for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
+                   host = h_itoh(cb->hhead);
+                   host->hostFlags |= HFE_LATER;
+                   cb->status = CB_DELAYED;
+                    cbnext = itocb(cb->cnext);
+                }
+               FSYNC_LOCK
+               fe->status |= FE_LATER;
+               FSYNC_UNLOCK
+               found++;
+           }
+           feip = &fe->fnext;
+       }
+    }
+    H_UNLOCK
+
+    if (!found) {
+       /* didn't find any callbacks, so return right away. */
+       return 0;
+    }
+
+    ViceLog(25, ("Fsync thread wakeup\n"));
+#ifdef AFS_PTHREAD_ENV
+    assert(pthread_cond_broadcast(&fsync_cond) == 0);
+#else
+    LWP_NoYieldSignal(&fsync_wait);
+#endif
+    return 0;
+}
+
+int BreakLaterCallBacks(void)
+{
+    struct AFSFid fid;
+    int hash;
+    afs_int32 *feip;
+    struct CallBack *cb;
+    struct FileEntry *fe = NULL;
+    struct FileEntry *myfe = NULL;
+    struct host *host;
+    struct VCBParams henumParms;
+    unsigned short tthead = 0;  /* zero is illegal value */
+    
+    /* Unchain first */
+    ViceLog(25, ("Looking for FileEntries to unchain\n"));
+    H_LOCK
+
+    /* Pick the first volume we see to clean up */
+    fid.Volume = fid.Vnode = fid.Unique = 0;
+
+    for (hash=0; hash<VHASH; hash++) {
+       for (feip = &HashTable[hash]; fe = itofe(*feip); ) {
+           if (fe && (fe->status & FE_LATER) && 
+               (fid.Volume == 0 || fid.Volume == fe->volid)) {
+               ViceLog(125, ("Unchaining for %d:%d:%d\n", fe->vnode, 
+                             fe->unique, fe->volid));
+               fid.Volume = fe->volid;
+               *feip = fe->fnext;
+               /* Works since volid is deeper than the largest pointer */
+               ((struct object *)fe)->next = (struct object *)myfe;
+               myfe = fe;
+           } else 
+               feip = &fe->fnext;
+       }
+    }
+    
+    if (!myfe) {
+       H_UNLOCK
+       return 0;
+    }
+
+    /* loop over FEs from myfe and free/break */
+    FSYNC_UNLOCK
+    tthead = 0;
+    for (fe = myfe; fe; ) {
+       register struct CallBack *cbnext;
+       for (cb = itocb(fe->firstcb); cb; cb = cbnext) {
+           host = h_itoh(cb->hhead);
+           h_Hold_r(host);
+           cbnext = itocb(cb->cnext);
+           if (!tthead || (TNorm(tthead) < TNorm(cb->thead))) {
+               tthead = cb->thead;
+           }
+           TDel(cb);
+           HDel(cb);
+           CDel(cb, 0); /* Don't let CDel clean up the fe */
+           /* leave hold for MultiBreakVolumeCallBack to clear */
+       }
+       myfe = fe;
+       fe = (struct FileEntry *)((struct object *)fe)->next;
+       FreeFE(myfe);
+    }
+
+    if (tthead) {
+       ViceLog(125, ("Breaking volume %d\n", fid.Volume));
+       henumParms.ncbas = 0;
+       henumParms.fid = &fid;
+       henumParms.thead = tthead;
+       H_UNLOCK
+       h_Enumerate(MultiBreakVolumeLaterCallBack, (char *) &henumParms);
+       H_LOCK
+           
+       if (henumParms.ncbas) {    /* do left-overs */
+           struct AFSCBFids tf;
+           tf.AFSCBFids_len = 1;
+           tf.AFSCBFids_val = &fid;
+           
+           MultiBreakCallBack_r(henumParms.cba, henumParms.ncbas, &tf, 0 );
+           henumParms.ncbas = 0;
+       }
+    }  
+    FSYNC_LOCK
+    H_UNLOCK
+
+    /* Arrange to be called again */
+    return 1;
+}
+
 /*
  * Delete all timed-out call back entries (to be called periodically by file
  * server)
@@ -1297,12 +1456,12 @@ int CleanupTimedOutCallBacks_r(void)
                        itofe(cb->fhead)->volid, itofe(cb->fhead)->vnode,
                        itofe(cb->fhead)->unique));
                HDel(cb);
-               CDel(cb);
+               CDel(cb, 1);
                ntimedout++;
                if (ntimedout > cbstuff.nblks) {
                  ViceLog(0,("CCB: Internal Error -- shutting down...\n"));
                  DumpCallBackState();
-                 ShutDown();
+                 ShutDownAndCore(PANIC);
                }
            } while (cbi != *thead);
            *thead = 0;
@@ -1384,17 +1543,7 @@ static int GetSomeSpace_r(struct host *hostp, int locked)
 }
 
 /* locked - set if caller has already locked the host */
-int ClearHostCallbacks(struct host *hp, int locked)
-{
-    int retVal;
-    H_LOCK
-    retVal = ClearHostCallbacks_r(hp, locked);
-    H_UNLOCK
-    return retVal;
-}
-
-/* locked - set if caller has already locked the host */
-int ClearHostCallbacks_r(struct host *hp, int locked)
+static int ClearHostCallbacks_r(struct host *hp, int locked)
 {
     struct interfaceAddr interf;
     int code;
@@ -1427,7 +1576,7 @@ int ClearHostCallbacks_r(struct host *hp, int locked)
          */
        cbstuff.GSS5++;
     }
-    DeleteAllCallBacks_r(hp);
+    DeleteAllCallBacks_r(hp, 1);
     if (hp->hostFlags & VENUSDOWN) {
        hp->hostFlags &= ~RESETDONE;    /* remember that we must do a reset */
     } else {
@@ -1613,7 +1762,7 @@ int main(int argc, char **argv)
     }
     if (err || argc != 1) {
        fprintf(stderr,
-               "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] callbackdumpfile\n");
+               "Usage: cbd [-host cbid] [-fid volume vnode] [-stats] [-all] callbackdumpfile\n");
        fprintf(stderr, "[cbid is shown for each host in the hosts.dump file]\n");
        exit(1);
     }
@@ -1680,9 +1829,9 @@ int PrintCB(register struct CallBack *cb, afs_uint32 now)
     struct FileEntry *fe = itofe(cb->fhead);
     time_t expires = TIndexToTime(cb->thead);
 
-    printf("vol=%u vn=%u cbs=%d hi=%d st=%d, exp in %d secs at %s", 
+    printf("vol=%u vn=%u cbs=%d hi=%d st=%d fest=%d, exp in %d secs at %s", 
           fe->volid, fe->vnode, fe->ncbs, cb->hhead, cb->status,
-          expires - now, ctime(&expires));
+          fe->status, expires - now, ctime(&expires));
 }
 
 #endif
@@ -1704,9 +1853,9 @@ int MultiBreakCallBackAlternateAddress(struct host *host, struct AFSCBFids *afid
 int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *afidp)
 {
        int i,j;
-       struct rx_connection*   conns[AFS_MAX_INTERFACE_ADDR];
+       struct rx_connection**  conns;
        struct rx_connection*   connSuccess = 0;
-       afs_int32                       addr[AFS_MAX_INTERFACE_ADDR];
+       afs_int32               *addr;
        static struct rx_securityClass *sc = 0;
        static struct AFSCBs tc = {0,0};
        char hoststr[16];
@@ -1724,6 +1873,14 @@ int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *af
        if ( !sc )
            sc = rxnull_NewClientSecurityObject();
 
+       i = host->interface->numberOfInterfaces;
+       addr = malloc(i * sizeof(afs_int32));
+       conns = malloc(i * sizeof(struct rx_connection *));
+       if (!addr || !conns) {
+           ViceLog(0, ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
+           assert(0);
+       }
+
        /* initialize alternate rx connections */
        for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
        {
@@ -1770,6 +1927,9 @@ int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *af
                if ( conns[i] != connSuccess )
                        rx_DestroyConnection(conns[i] );
 
+       free(addr);
+       free(conns);
+
        if ( connSuccess ) return 0;    /* success */
                else return 1;          /* failure */
 }
@@ -1782,9 +1942,9 @@ int MultiBreakCallBackAlternateAddress_r(struct host *host, struct AFSCBFids *af
 int MultiProbeAlternateAddress_r(struct host *host)
 {
        int i,j;
-       struct rx_connection*   conns[AFS_MAX_INTERFACE_ADDR];
+       struct rx_connection**  conns;
        struct rx_connection*   connSuccess = 0;
-       afs_int32                       addr[AFS_MAX_INTERFACE_ADDR];
+       afs_int32               *addr;
        static struct rx_securityClass *sc = 0;
        char hoststr[16];
 
@@ -1801,6 +1961,14 @@ int MultiProbeAlternateAddress_r(struct host *host)
        if ( !sc )
            sc = rxnull_NewClientSecurityObject();
 
+       i = host->interface->numberOfInterfaces;
+       addr = malloc(i * sizeof(afs_int32));   
+       conns = malloc(i * sizeof(struct rx_connection *));
+       if (!addr || !conns) {
+           ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
+           assert(0);
+       }
+
        /* initialize alternate rx connections */
        for ( i=0,j=0; i < host->interface->numberOfInterfaces; i++)
        {
@@ -1847,6 +2015,9 @@ int MultiProbeAlternateAddress_r(struct host *host)
                if ( conns[i] != connSuccess )
                        rx_DestroyConnection(conns[i] );
 
+       free(addr);
+       free(conns);
+
        if ( connSuccess ) return 0;    /* success */
                else return 1;          /* failure */
 }