fix-cbd-20051213
[openafs.git] / src / viced / callback.c
index f4d8c5a..8b25dfc 100644 (file)
@@ -328,7 +328,7 @@ FindFE(register AFSFid * fid)
     for (fei = HashTable[hash]; fei; fei = fe->fnext) {
        fe = itofe(fei);
        if (fe->volid == fid->Volume && fe->unique == fid->Unique
-           && fe->vnode == fid->Vnode)
+           && fe->vnode == fid->Vnode && (fe->status & FE_LATER) != FE_LATER)
            return fe;
     }
     return 0;
@@ -572,6 +572,7 @@ XCallBackBulk_r(struct host * ahost, struct AFSFid * fids, afs_int32 nfids)
     struct AFSCBs tc;
     int code;
     int j;
+    struct rx_connection *cb_conn = NULL;
 
 #ifdef ADAPT_MTU
     rx_SetConnDeadTime(ahost->callback_rxcon, 4);
@@ -594,8 +595,12 @@ XCallBackBulk_r(struct host * ahost, struct AFSFid * fids, afs_int32 nfids)
        tc.AFSCBs_len = i;
        tc.AFSCBs_val = tcbs;
 
+       cb_conn = ahost->callback_rxcon;
+       rx_GetConnection(cb_conn);
        H_UNLOCK;
-       code |= RXAFSCB_CallBack(ahost->callback_rxcon, &tf, &tc);
+       code |= RXAFSCB_CallBack(cb_conn, &tf, &tc);
+       rx_PutConnection(cb_conn);
+       cb_conn = NULL;
        H_LOCK;
     }
 
@@ -692,6 +697,7 @@ AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
        fe->vnode = fid->Vnode;
        fe->unique = fid->Unique;
        fe->ncbs = 0;
+       fe->status = 0;
        hash = VHash(fid->Volume, fid->Unique);
        fe->fnext = HashTable[hash];
        HashTable[hash] = fetoi(fe);
@@ -715,6 +721,11 @@ AddCallBack1_r(struct host *host, AFSFid * fid, afs_uint32 * thead, int type,
            TDel(cb);
            TAdd(cb, Thead);
        }
+       if (newfe == NULL) {    /* we are using the new FE */
+            fe->firstcb = cbtoi(cb);
+            fe->ncbs++;
+            cb->fhead = fetoi(fe);
+        }
     } else {
        cb = newcb;
        newcb = NULL;
@@ -766,7 +777,6 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
 {
     int i, j;
     struct rx_connection *conns[MAX_CB_HOSTS];
-    int opt_TO;                        /* secs, but internal adaptive parms are in ms */
     static struct AFSCBs tc = { 0, 0 };
 
     assert(ncbas <= MAX_CB_HOSTS);
@@ -777,6 +787,7 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
        if (!thishost || (thishost->hostFlags & HOSTDELETED)) {
            continue;
        }
+       rx_GetConnection(thishost->callback_rxcon);
        conns[j++] = thishost->callback_rxcon;
 
 #ifdef ADAPT_MTU
@@ -833,14 +844,14 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
                        }
 
                        H_LOCK;
-                       h_Lock_r(hp);
+                       h_Lock_r(hp); 
                        hp->hostFlags |= VENUSDOWN;
                /**
                  * We always go into AddCallBack1_r with the host locked
                  */
                        AddCallBack1_r(hp, afidp->AFSCBFids_val, itot(idx),
                                       CB_DELAYED, 1);
-                       h_Unlock_r(hp);
+                       h_Unlock_r(hp); 
                        H_UNLOCK;
                    }
                }
@@ -854,10 +865,21 @@ MultiBreakCallBack_r(struct cbstruct cba[], int ncbas,
     for (i = 0; i < ncbas; i++) {
        struct host *hp;
        hp = cba[i].hp;
-       if (hp && xhost != hp)
+       if (hp && xhost != hp) {
            h_Release_r(hp);
+       }
     }
 
+    /* H_UNLOCK around this so h_FreeConnection does not deadlock.
+       h_FreeConnection should *never* be called on a callback connection,
+       but on 10/27/04 a deadlock occurred where it was, when we know why,
+       this should be reverted. -- shadow */
+    H_UNLOCK;
+    for (i = 0; i < j; i++) {
+       rx_PutConnection(conns[i]);
+    }
+    H_LOCK;
+
     return;
 }
 
@@ -878,7 +900,6 @@ BreakCallBack(struct host *xhost, AFSFid * fid, int flag)
     struct CallBack *cb, *nextcb;
     struct cbstruct cba[MAX_CB_HOSTS];
     int ncbas;
-    struct rx_connection *conns[MAX_CB_HOSTS];
     struct AFSCBFids tf;
     int hostindex;
     char hoststr[16];
@@ -1073,24 +1094,26 @@ BreakDelayedCallBacks_r(struct host *host)
     u_byte thead[AFSCBMAX];    /* This should match thead in struct Callback */
     int cbi, first, nfids;
     struct CallBack *cb;
-    struct interfaceAddr interf;
     int code;
     char hoststr[16];
+    struct rx_connection *cb_conn;
 
     cbstuff.nbreakers++;
     if (!(host->hostFlags & RESETDONE) && !(host->hostFlags & HOSTDELETED)) {
        host->hostFlags &= ~ALTADDR;    /* alterrnate addresses are invalid */
+       cb_conn = host->callback_rxcon;
+       rx_GetConnection(cb_conn);
        if (host->interface) {
            H_UNLOCK;
            code =
-               RXAFSCB_InitCallBackState3(host->callback_rxcon,
-                                          &FS_HostUUID);
-           H_LOCK;
+               RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
        } else {
            H_UNLOCK;
-           code = RXAFSCB_InitCallBackState(host->callback_rxcon);
-           H_LOCK;
+           code = RXAFSCB_InitCallBackState(cb_conn);
        }
+       rx_PutConnection(cb_conn);
+       cb_conn = NULL;
+       H_LOCK;
        host->hostFlags |= ALTADDR;     /* alternate addresses are valid */
        if (code) {
            if (ShowProblems) {
@@ -1385,9 +1408,11 @@ BreakVolumeCallBacksLater(afs_uint32 volume)
 
     ViceLog(25, ("Fsync thread wakeup\n"));
 #ifdef AFS_PTHREAD_ENV
+    FSYNC_LOCK;
     assert(pthread_cond_broadcast(&fsync_cond) == 0);
+    FSYNC_UNLOCK;
 #else
-    LWP_NoYieldSignal(&fsync_wait);
+    LWP_NoYieldSignal(fsync_wait);
 #endif
     return 0;
 }
@@ -1404,10 +1429,12 @@ BreakLaterCallBacks(void)
     struct host *host;
     struct VCBParams henumParms;
     unsigned short tthead = 0; /* zero is illegal value */
+    char hoststr[16];
 
     /* Unchain first */
     ViceLog(25, ("Looking for FileEntries to unchain\n"));
     H_LOCK;
+    FSYNC_LOCK;
     /* Pick the first volume we see to clean up */
     fid.Volume = fid.Vnode = fid.Unique = 0;
 
@@ -1415,18 +1442,22 @@ BreakLaterCallBacks(void)
        for (feip = &HashTable[hash]; fe = itofe(*feip);) {
            if (fe && (fe->status & FE_LATER)
                && (fid.Volume == 0 || fid.Volume == fe->volid)) {
+               /* Ugly, but used to avoid left side casting */
+               struct object *tmpfe;
                ViceLog(125,
                        ("Unchaining for %u:%u:%u\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;
+               tmpfe = (struct object *)fe;
+               tmpfe->next = (struct object *)myfe;
                myfe = fe;
            } else
                feip = &fe->fnext;
        }
     }
+    FSYNC_UNLOCK;
 
     if (!myfe) {
        H_UNLOCK;
@@ -1434,21 +1465,27 @@ BreakLaterCallBacks(void)
     }
 
     /* 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;
+           host = h_itoh(cb->hhead);
+           if (cb->status == CB_DELAYED) {
+               h_Hold_r(host);
+               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 */
+           } else {
+               ViceLog(125,
+                       ("Found host %s:%d non-DELAYED cb for %u:%u:%u\n", 
+                        afs_inet_ntoa_r(host->host, hoststr),
+                        ntohs(host->port), fe->vnode, fe->unique, fe->volid));
            }
-           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;
@@ -1472,8 +1509,7 @@ BreakLaterCallBacks(void)
            henumParms.ncbas = 0;
        }
     }
-    FSYNC_LOCK;
-    H_UNLOCK;;
+    H_UNLOCK;
 
     /* Arrange to be called again */
     return 1;
@@ -1489,6 +1525,7 @@ CleanupTimedOutCallBacks(void)
     H_LOCK;
     CleanupTimedOutCallBacks_r();
     H_UNLOCK;
+    return 0;
 }
 
 int
@@ -1531,6 +1568,7 @@ CleanupTimedOutCallBacks_r(void)
 }
 
 static struct host *lih_host;
+static int lih_host_held;
 
 static int
 lih_r(register struct host *host, register int held,
@@ -1539,7 +1577,12 @@ lih_r(register struct host *host, register int held,
     if (host->cblist
        && ((hostp && host != hostp) || (!held && !h_OtherHolds_r(host)))
        && (!lih_host || host->ActiveCall < lih_host->ActiveCall)) {
+       if (lih_host != NULL && lih_host_held) {
+           h_Release_r(lih_host);
+       }
        lih_host = host;
+       lih_host_held = !held;
+       held = 1;
     }
     return held;
 }
@@ -1567,9 +1610,16 @@ GetSomeSpace_r(struct host *hostp, int locked)
        h_Enumerate_r(lih_r, hp2, (char *)hp1);
        hp = lih_host;
        if (hp) {
+           /* set in lih_r! private copy before giving up H_LOCK */
+           int lih_host_held2=lih_host_held;   
            cbstuff.GSS4++;
-           if (!ClearHostCallbacks_r(hp, 0 /* not locked or held */ ))
+           if (!ClearHostCallbacks_r(hp, 0 /* not locked or held */ )) {
+               if (lih_host_held2)
+                   h_Release_r(hp);
                return 0;
+           }
+           if (lih_host_held2)
+               h_Release_r(hp);
            hp2 = hp->next;
        } else {
            hp2 = hostList;
@@ -1608,10 +1658,10 @@ GetSomeSpace_r(struct host *hostp, int locked)
 static int
 ClearHostCallbacks_r(struct host *hp, int locked)
 {
-    struct interfaceAddr interf;
     int code;
     int held = 0;
     char hoststr[16];
+    struct rx_connection *cb_conn = NULL;
 
     ViceLog(5,
            ("GSS: Delete longest inactive host %s\n",
@@ -1647,16 +1697,19 @@ ClearHostCallbacks_r(struct host *hp, int locked)
     } else {
        /* host is up, try a call */
        hp->hostFlags &= ~ALTADDR;      /* alternate addresses are invalid */
+       cb_conn = hp->callback_rxcon;
+       rx_GetConnection(hp->callback_rxcon);
        if (hp->interface) {
            H_UNLOCK;
            code =
-               RXAFSCB_InitCallBackState3(hp->callback_rxcon, &FS_HostUUID);
-           H_LOCK;
+               RXAFSCB_InitCallBackState3(cb_conn, &FS_HostUUID);
        } else {
            H_UNLOCK;
-           code = RXAFSCB_InitCallBackState(hp->callback_rxcon);
-           H_LOCK;
+           code = RXAFSCB_InitCallBackState(cb_conn);
        }
+       rx_PutConnection(cb_conn);
+       cb_conn = NULL;
+       H_LOCK;
        hp->hostFlags |= ALTADDR;       /* alternate addresses are valid */
        if (code) {
            /* failed, mark host down and need reset */
@@ -1904,6 +1957,9 @@ PrintCB(register struct CallBack *cb, afs_uint32 now)
     struct FileEntry *fe = itofe(cb->fhead);
     time_t expires = TIndexToTime(cb->thead);
 
+    if (fe == NULL)
+       return;
+
     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, fe->status,
           expires - now, ctime(&expires));
@@ -1933,7 +1989,7 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
     int i, j;
     struct rx_connection **conns;
     struct rx_connection *connSuccess = 0;
-    afs_int32 *addr;
+    struct AddrPort *interfaces;
     static struct rx_securityClass *sc = 0;
     static struct AFSCBs tc = { 0, 0 };
     char hoststr[16];
@@ -1953,9 +2009,9 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
        sc = rxnull_NewClientSecurityObject();
 
     i = host->interface->numberOfInterfaces;
-    addr = calloc(i, sizeof(afs_int32));
+    interfaces = calloc(i, sizeof(struct AddrPort));
     conns = calloc(i, sizeof(struct rx_connection *));
-    if (!addr || !conns) {
+    if (!interfaces || !conns) {
        ViceLog(0,
                ("Failed malloc in MultiBreakCallBackAlternateAddress_r\n"));
        assert(0);
@@ -1964,12 +2020,14 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
     /* initialize alternate rx connections */
     for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
        /* this is the current primary address */
-       if (host->host == host->interface->addr[i])
+       if (host->host == host->interface->interface[i].addr &&
+           host->port == host->interface->interface[i].port)
            continue;
 
-       addr[j] = host->interface->addr[i];
+       interfaces[j] = host->interface->interface[i];
        conns[j] =
-           rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
+           rx_NewConnection(interfaces[j].addr, 
+                            interfaces[j].port, 1, sc, 0);
        rx_SetConnDeadTime(conns[j], 2);
        rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
        j++;
@@ -1988,13 +2046,14 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
            if (host->callback_rxcon)
                rx_DestroyConnection(host->callback_rxcon);
            host->callback_rxcon = conns[multi_i];
-           host->host = addr[multi_i];
+           host->host = interfaces[multi_i].addr;
+           host->port = interfaces[multi_i].port;
            connSuccess = conns[multi_i];
            rx_SetConnDeadTime(host->callback_rxcon, 50);
            rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
            ViceLog(125,
                    ("multibreakcall success with addr %s\n",
-                    afs_inet_ntoa_r(addr[multi_i], hoststr)));
+                    afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
            H_UNLOCK;
            multi_Abort;
        }
@@ -2006,7 +2065,7 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
        if (conns[i] != connSuccess)
            rx_DestroyConnection(conns[i]);
 
-    free(addr);
+    free(interfaces);
     free(conns);
 
     if (connSuccess)
@@ -2017,8 +2076,8 @@ MultiBreakCallBackAlternateAddress_r(struct host *host,
 
 
 /*
-** try multiRX probes to host. 
-** return 0 on success, non-zero on failure
+** try multi_RX probes to host. 
+** return 0 on success, non-0 on failure
 */
 int
 MultiProbeAlternateAddress_r(struct host *host)
@@ -2026,7 +2085,7 @@ MultiProbeAlternateAddress_r(struct host *host)
     int i, j;
     struct rx_connection **conns;
     struct rx_connection *connSuccess = 0;
-    afs_int32 *addr;
+    struct AddrPort *interfaces;
     static struct rx_securityClass *sc = 0;
     char hoststr[16];
 
@@ -2045,9 +2104,9 @@ MultiProbeAlternateAddress_r(struct host *host)
        sc = rxnull_NewClientSecurityObject();
 
     i = host->interface->numberOfInterfaces;
-    addr = calloc(i, sizeof(afs_int32));
+    interfaces = calloc(i, sizeof(struct AddrPort));
     conns = calloc(i, sizeof(struct rx_connection *));
-    if (!addr || !conns) {
+    if (!interfaces || !conns) {
        ViceLog(0, ("Failed malloc in MultiProbeAlternateAddress_r\n"));
        assert(0);
     }
@@ -2055,12 +2114,14 @@ MultiProbeAlternateAddress_r(struct host *host)
     /* initialize alternate rx connections */
     for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
        /* this is the current primary address */
-       if (host->host == host->interface->addr[i])
+       if (host->host == host->interface->interface[i].addr &&
+           host->port == host->interface->interface[i].port)
            continue;
 
-       addr[j] = host->interface->addr[i];
+       interfaces[j] = host->interface->interface[i];
        conns[j] =
-           rx_NewConnection(host->interface->addr[i], host->port, 1, sc, 0);
+           rx_NewConnection(interfaces[i].addr, 
+                            interfaces[i].port, 1, sc, 0);
        rx_SetConnDeadTime(conns[j], 2);
        rx_SetConnHardDeadTime(conns[j], AFS_HARDDEADTIME);
        j++;
@@ -2079,16 +2140,44 @@ MultiProbeAlternateAddress_r(struct host *host)
            if (host->callback_rxcon)
                rx_DestroyConnection(host->callback_rxcon);
            host->callback_rxcon = conns[multi_i];
-           host->host = addr[multi_i];
+           host->host = interfaces[multi_i].addr;
+           host->port = interfaces[multi_i].port;
            connSuccess = conns[multi_i];
            rx_SetConnDeadTime(host->callback_rxcon, 50);
            rx_SetConnHardDeadTime(host->callback_rxcon, AFS_HARDDEADTIME);
            ViceLog(125,
                    ("multiprobe success with addr %s\n",
-                    afs_inet_ntoa_r(addr[multi_i], hoststr)));
+                    afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
            H_UNLOCK;
            multi_Abort;
-       }
+       } else {
+           ViceLog(125,
+                   ("multiprobe failure with addr %s\n",
+                    afs_inet_ntoa_r(interfaces[multi_i].addr, hoststr)));
+            
+            /* This is less than desirable but its the best we can do.
+             * The AFS Cache Manager will return either 0 for a Uuid  
+             * match and a 1 for a non-match.   If the error is 1 we 
+             * therefore know that our mapping of IP address to Uuid 
+             * is wrong.   We should attempt to find the correct
+             * Uuid and fix the host tables.
+             */
+            if (multi_error == 1) {
+                struct host * newhost;
+
+                /* remove the current alternate address from this host */
+                H_LOCK;
+                for (i = 0, j = 0; i < host->interface->numberOfInterfaces; i++) {
+                    if (interfaces[multi_i].addr != host->interface->interface[i].addr &&
+                       interfaces[multi_i].port != host->interface->interface[i].port) {
+                        host->interface->interface[j] = host->interface->interface[i];
+                        j++;
+                    }
+                }
+                host->interface->numberOfInterfaces--;
+                H_UNLOCK;
+            }
+        }
     }
     multi_End_Ignore;
     H_LOCK;
@@ -2097,7 +2186,7 @@ MultiProbeAlternateAddress_r(struct host *host)
        if (conns[i] != connSuccess)
            rx_DestroyConnection(conns[i]);
 
-    free(addr);
+    free(interfaces);
     free(conns);
 
     if (connSuccess)