viced-avoid-tying-up-all-threads-20070730
[openafs.git] / src / viced / host.c
index 87f7c13..13aeb0f 100644 (file)
@@ -1299,6 +1299,24 @@ removeInterfaceAddr_r(struct host *host, afs_uint32 addr, afs_uint16 port)
     return 0;
 }
 
+int 
+h_threadquota(int waiting) 
+{
+    if (lwps > 64) {
+       if (waiting > 5)
+           return 1;
+    } else if (lwps > 32) {
+       if (waiting > 4)
+           return 1;
+    } else if (lwps > 16) {
+       if (waiting > 3)
+           return 1;
+    } else {
+       if (waiting > 2)
+           return 1;
+    }
+    return 0;
+}
 
 /* Host is returned held */
 struct host *
@@ -1335,8 +1353,12 @@ h_GetHost_r(struct rx_connection *tcon)
         * structure for this address. Verify that the identity
         * of the caller matches the identity in the host structure.
         */
+       if ((host->hostFlags & HWHO_INPROGRESS) && 
+           h_threadquota(host->lock.num_waiting))
+           return 0;
        h_Lock_r(host);
        if (!(host->hostFlags & ALTADDR)) {
+           host->hostFlags &= ~HWHO_INPROGRESS;
            /* Another thread is doing initialization */
            h_Unlock_r(host);
            if (!held)
@@ -1377,6 +1399,7 @@ h_GetHost_r(struct rx_connection *tcon)
                         afs_inet_ntoa_r(host->host, hoststr),
                         ntohs(host->port)));
                host->hostFlags |= HOSTDELETED;
+               host->hostFlags &= ~HWHO_INPROGRESS;
                h_Unlock_r(host);
                if (!held)
                    h_Release_r(host);
@@ -1402,6 +1425,7 @@ h_GetHost_r(struct rx_connection *tcon)
                        ("Host %s:%d has changed its identity, deleting.\n",
                         afs_inet_ntoa_r(host->host, hoststr), host->port));
                host->hostFlags |= HOSTDELETED;
+               host->hostFlags &= ~HWHO_INPROGRESS;
                h_Unlock_r(host);
                if (!held)
                    h_Release_r(host);
@@ -1421,6 +1445,7 @@ h_GetHost_r(struct rx_connection *tcon)
        else
            host->hostFlags &= ~(HERRORTRANS);
        host->hostFlags |= ALTADDR;
+       host->hostFlags &= ~HWHO_INPROGRESS;
        h_Unlock_r(host);
     } else if (host) {
        if (!(host->hostFlags & ALTADDR)) {
@@ -1430,6 +1455,7 @@ h_GetHost_r(struct rx_connection *tcon)
                     afs_inet_ntoa_r(host->host, hoststr),
                     ntohs(host->port)));
            h_Lock_r(host);
+           host->hostFlags &= ~HWHO_INPROGRESS;
            h_Unlock_r(host);
            if (!held)
                h_Release_r(host);
@@ -1462,6 +1488,7 @@ h_GetHost_r(struct rx_connection *tcon)
 
            /* The host in the cache is not the host for this connection */
            host->hostFlags |= HOSTDELETED;
+           host->hostFlags &= ~HWHO_INPROGRESS;
            h_Unlock_r(host);
            if (!held)
                h_Release_r(host);
@@ -1539,6 +1566,7 @@ h_GetHost_r(struct rx_connection *tcon)
                    if (!(oheld = h_Held_r(oldHost)))
                        h_Hold_r(oldHost);
                    h_Lock_r(oldHost);
+                   oldHost->hostFlags |= HWHO_INPROGRESS;
 
                     if (oldHost->interface) {
                        int code2;
@@ -1629,6 +1657,7 @@ h_GetHost_r(struct rx_connection *tcon)
                        }
                    }
                    host->hostFlags |= HOSTDELETED;
+                   host->hostFlags &= ~HWHO_INPROGRESS;
                    h_Unlock_r(host);
                    /* release host because it was allocated by h_Alloc_r */
                    h_Release_r(host);
@@ -1675,6 +1704,7 @@ h_GetHost_r(struct rx_connection *tcon)
        else
            host->hostFlags &= ~(HERRORTRANS);
        host->hostFlags |= ALTADDR;     /* host structure initialization complete */
+       host->hostFlags &= ~HWHO_INPROGRESS;
        h_Unlock_r(host);
     }
     if (caps.Capabilities_val)
@@ -1925,6 +1955,9 @@ h_FindClient_r(struct rx_connection *tcon)
     if (!client) { /* loop */
        host = h_GetHost_r(tcon);       /* Returns it h_Held */
 
+       if (!host) 
+           return 0;
+
     retryfirstclient:
        /* First try to find the client structure */
        for (client = host->FirstClient; client; client = client->next) {
@@ -3120,6 +3153,7 @@ CheckHost(register struct host *host, int held)
     }
     if (host->LastCall < checktime) {
        h_Lock_r(host);
+       host->hostFlags |= HWHO_INPROGRESS;
        if (!(host->hostFlags & HOSTDELETED)) {
            cb_conn = host->callback_rxcon;
            rx_GetConnection(cb_conn);
@@ -3189,6 +3223,7 @@ CheckHost(register struct host *host, int held)
            cb_conn=NULL;
            H_LOCK;
        }
+       host->hostFlags &= ~HWHO_INPROGRESS;
        h_Unlock_r(host);
     }
     H_UNLOCK;