b5595b
# ./pullrev.sh 1872790
b5595b
b5595b
http://svn.apache.org/viewvc?view=revision&revision=1872790
b5595b
b5595b
- Adjusted to remove (pointless-for-RHEL) additions of #if APR_HAS_THREADS.
b5595b
- merged a previous change to connection_destructor in mod_proxy_balancer.c
b5595b
- s/hostname_ex/hostname since 2.4.6 doesn't have hostname_ex
b5595b
b5595b
--- httpd-2.4.6/modules/proxy/mod_proxy_balancer.c.r1872790
b5595b
+++ httpd-2.4.6/modules/proxy/mod_proxy_balancer.c
b5595b
@@ -1229,12 +1229,23 @@
b5595b
                     bsel->wupdated = bsel->s->wupdated = nworker->s->updated = apr_time_now();
b5595b
                     /* by default, all new workers are disabled */
b5595b
                     ap_proxy_set_wstatus('D', 1, nworker);
b5595b
+                } else {
b5595b
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10163)
b5595b
+                                  "%s: failed to add worker %s",
b5595b
+                                  bsel->s->name, val);
b5595b
+                    PROXY_GLOBAL_UNLOCK(bsel);
b5595b
+                    return HTTP_BAD_REQUEST;
b5595b
                 }
b5595b
                 if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) {
b5595b
                     ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01203)
b5595b
                                   "%s: Unlock failed for adding worker",
b5595b
                                   bsel->s->name);
b5595b
                 }
b5595b
+            } else {
b5595b
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10164)
b5595b
+                                  "%s: failed to add worker %s",
b5595b
+                                  bsel->s->name, val);
b5595b
+                return HTTP_BAD_REQUEST;
b5595b
             }
b5595b
 
b5595b
         }
b5595b
--- httpd-2.4.6/modules/proxy/mod_proxy_ftp.c.r1872790
b5595b
+++ httpd-2.4.6/modules/proxy/mod_proxy_ftp.c
b5595b
@@ -972,7 +972,7 @@
b5595b
     conn_rec *origin, *data = NULL;
b5595b
     apr_status_t err = APR_SUCCESS;
b5595b
     apr_status_t uerr = APR_SUCCESS;
b5595b
-    apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
b5595b
+    apr_bucket_brigade *bb;
b5595b
     char *buf, *connectname;
b5595b
     apr_port_t connectport;
b5595b
     char buffer[MAX_STRING_LEN];
b5595b
@@ -1112,13 +1112,15 @@
b5595b
 
b5595b
     if (worker->s->is_address_reusable) {
b5595b
         if (!worker->cp->addr) {
b5595b
+#if APR_HAS_THREADS
b5595b
             if ((err = PROXY_THREAD_LOCK(worker->balancer)) != APR_SUCCESS) {
b5595b
                 ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(01037) "lock");
b5595b
                 return HTTP_INTERNAL_SERVER_ERROR;
b5595b
             }
b5595b
+#endif
b5595b
         }
b5595b
-        connect_addr = worker->cp->addr;
b5595b
-        address_pool = worker->cp->pool;
b5595b
+        connect_addr = AP_VOLATILIZE_T(apr_sockaddr_t *, worker->cp->addr);
b5595b
+        address_pool = worker->cp->dns_pool;
b5595b
     }
b5595b
     else
b5595b
         address_pool = r->pool;
b5595b
@@ -1206,6 +1208,7 @@
b5595b
      * correct directory...
b5595b
      */
b5595b
 
b5595b
+    bb = apr_brigade_create(p, c->bucket_alloc);
b5595b
 
b5595b
     /* possible results: */
b5595b
     /* 120 Service ready in nnn minutes. */
b5595b
--- httpd-2.4.6/modules/proxy/mod_proxy.h.r1872790
b5595b
+++ httpd-2.4.6/modules/proxy/mod_proxy.h
b5595b
@@ -260,12 +260,15 @@
b5595b
 
b5595b
 /* Connection pool */
b5595b
 struct proxy_conn_pool {
b5595b
-    apr_pool_t     *pool;   /* The pool used in constructor and destructor calls */
b5595b
-    apr_sockaddr_t *addr;   /* Preparsed remote address info */
b5595b
-    apr_reslist_t  *res;    /* Connection resource list */
b5595b
-    proxy_conn_rec *conn;   /* Single connection for prefork mpm */
b5595b
+    apr_pool_t     *pool;     /* The pool used in constructor and destructor calls */
b5595b
+    apr_sockaddr_t *addr;     /* Preparsed remote address info */
b5595b
+    apr_reslist_t  *res;      /* Connection resource list */
b5595b
+    proxy_conn_rec *conn;     /* Single connection for prefork mpm */
b5595b
+    apr_pool_t     *dns_pool; /* The pool used for worker scoped DNS resolutions */
b5595b
 };
b5595b
 
b5595b
+#define AP_VOLATILIZE_T(T, x) (*(T volatile *)&(x))
b5595b
+
b5595b
 /* Keep below in sync with proxy_util.c! */
b5595b
 /* worker status bits */
b5595b
 #define PROXY_WORKER_INITIALIZED    0x0001
b5595b
--- httpd-2.4.6/modules/proxy/proxy_util.c.r1872790
b5595b
+++ httpd-2.4.6/modules/proxy/proxy_util.c
b5595b
@@ -1318,16 +1324,14 @@
b5595b
 
b5595b
 static apr_status_t conn_pool_cleanup(void *theworker)
b5595b
 {
b5595b
-    proxy_worker *worker = (proxy_worker *)theworker;
b5595b
-    if (worker->cp->res) {
b5595b
-        worker->cp->pool = NULL;
b5595b
-    }
b5595b
+    ((proxy_worker *)theworker)->cp = NULL;
b5595b
     return APR_SUCCESS;
b5595b
 }
b5595b
 
b5595b
 static void init_conn_pool(apr_pool_t *p, proxy_worker *worker)
b5595b
 {
b5595b
     apr_pool_t *pool;
b5595b
+    apr_pool_t *dns_pool;
b5595b
     proxy_conn_pool *cp;
b5595b
 
b5595b
     /*
b5595b
@@ -1339,11 +1343,20 @@
b5595b
     apr_pool_create(&pool, p);
b5595b
     apr_pool_tag(pool, "proxy_worker_cp");
b5595b
     /*
b5595b
+     * Create a subpool of the connection pool for worker
b5595b
+     * scoped DNS resolutions. This is needed to avoid race
b5595b
+     * conditions in using the connection pool by multiple
b5595b
+     * threads during ramp up.
b5595b
+     */
b5595b
+    apr_pool_create(&dns_pool, pool);
b5595b
+    apr_pool_tag(dns_pool, "proxy_worker_dns");
b5595b
+    /*
b5595b
      * Alloc from the same pool as worker.
b5595b
      * proxy_conn_pool is permanently attached to the worker.
b5595b
      */
b5595b
     cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool));
b5595b
     cp->pool = pool;
b5595b
+    cp->dns_pool = dns_pool;
b5595b
     worker->cp = cp;
b5595b
 }
b5595b
 
b5595b
@@ -1359,14 +1372,6 @@
b5595b
     proxy_conn_rec *conn = (proxy_conn_rec *)theconn;
b5595b
     proxy_worker *worker = conn->worker;
b5595b
 
b5595b
-    /*
b5595b
-     * If the connection pool is NULL the worker
b5595b
-     * cleanup has been run. Just return.
b5595b
-     */
b5595b
-    if (!worker->cp) {
b5595b
-        return APR_SUCCESS;
b5595b
-    }
b5595b
-
b5595b
     if (conn->r) {
b5595b
         apr_pool_destroy(conn->r->pool);
b5595b
         conn->r = NULL;
b5595b
@@ -1487,10 +1492,11 @@
b5595b
 static apr_status_t connection_destructor(void *resource, void *params,
b5595b
                                           apr_pool_t *pool)
b5595b
 {
b5595b
-    proxy_conn_rec *conn = (proxy_conn_rec *)resource;
b5595b
+    proxy_worker *worker = params;
b5595b
 
b5595b
     /* Destroy the pool only if not called from reslist_destroy */
b5595b
-    if (conn->worker->cp->pool) {
b5595b
+    if (worker->cp) {
b5595b
+        proxy_conn_rec *conn = resource;
b5595b
         apr_pool_destroy(conn->pool);
b5595b
     }
b5595b
 
b5595b
@@ -1880,67 +1886,73 @@
b5595b
                      ap_proxy_worker_name(p, worker));
b5595b
     }
b5595b
     else {
b5595b
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927)
b5595b
-                     "initializing worker %s local",
b5595b
-                     ap_proxy_worker_name(p, worker));
b5595b
         apr_global_mutex_lock(proxy_mutex);
b5595b
-        /* Now init local worker data */
b5595b
-        if (worker->tmutex == NULL) {
b5595b
-            rv = apr_thread_mutex_create(&(worker->tmutex), APR_THREAD_MUTEX_DEFAULT, p);
b5595b
-            if (rv != APR_SUCCESS) {
b5595b
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00928)
b5595b
-                             "can not create worker thread mutex");
b5595b
-                apr_global_mutex_unlock(proxy_mutex);
b5595b
-                return rv;
b5595b
+        /* Check again after we got the lock if we are still uninitialized */
b5595b
+        if (!(AP_VOLATILIZE_T(unsigned int, worker->local_status) & PROXY_WORKER_INITIALIZED)) {
b5595b
+            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927)
b5595b
+                         "initializing worker %s local",
b5595b
+                         ap_proxy_worker_name(p, worker));
b5595b
+            /* Now init local worker data */
b5595b
+#if APR_HAS_THREADS
b5595b
+            if (worker->tmutex == NULL) {
b5595b
+                rv = apr_thread_mutex_create(&(worker->tmutex), APR_THREAD_MUTEX_DEFAULT, p);
b5595b
+                if (rv != APR_SUCCESS) {
b5595b
+                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00928)
b5595b
+                                 "can not create worker thread mutex");
b5595b
+                    apr_global_mutex_unlock(proxy_mutex);
b5595b
+                    return rv;
b5595b
+                }
b5595b
             }
b5595b
-        }
b5595b
-        if (worker->cp == NULL)
b5595b
-            init_conn_pool(p, worker);
b5595b
-        if (worker->cp == NULL) {
b5595b
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00929)
b5595b
-                         "can not create connection pool");
b5595b
-            apr_global_mutex_unlock(proxy_mutex);
b5595b
-            return APR_EGENERAL;
b5595b
-        }
b5595b
-
b5595b
-        if (worker->s->hmax) {
b5595b
-            rv = apr_reslist_create(&(worker->cp->res),
b5595b
-                                    worker->s->min, worker->s->smax,
b5595b
-                                    worker->s->hmax, worker->s->ttl,
b5595b
-                                    connection_constructor, connection_destructor,
b5595b
-                                    worker, worker->cp->pool);
b5595b
-
b5595b
-            apr_pool_cleanup_register(worker->cp->pool, (void *)worker,
b5595b
-                                      conn_pool_cleanup,
b5595b
-                                      apr_pool_cleanup_null);
b5595b
-
b5595b
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00930)
b5595b
-                "initialized pool in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d",
b5595b
-                 getpid(), worker->s->hostname, worker->s->min,
b5595b
-                 worker->s->hmax, worker->s->smax);
b5595b
-
b5595b
-            /* Set the acquire timeout */
b5595b
-            if (rv == APR_SUCCESS && worker->s->acquire_set) {
b5595b
-                apr_reslist_timeout_set(worker->cp->res, worker->s->acquire);
b5595b
+#endif
b5595b
+            if (worker->cp == NULL)
b5595b
+                init_conn_pool(p, worker);
b5595b
+            if (worker->cp == NULL) {
b5595b
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00929)
b5595b
+                             "can not create connection pool");
b5595b
+                apr_global_mutex_unlock(proxy_mutex);
b5595b
+                return APR_EGENERAL;
b5595b
             }
b5595b
 
b5595b
-        }
b5595b
-        else {
b5595b
-            void *conn;
b5595b
+            if (worker->s->hmax) {
b5595b
+                rv = apr_reslist_create(&(worker->cp->res),
b5595b
+                                        worker->s->min, worker->s->smax,
b5595b
+                                        worker->s->hmax, worker->s->ttl,
b5595b
+                                        connection_constructor, connection_destructor,
b5595b
+                                        worker, worker->cp->pool);
b5595b
+
b5595b
+                apr_pool_pre_cleanup_register(worker->cp->pool, worker,
b5595b
+                                              conn_pool_cleanup);
b5595b
+
b5595b
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00930)
b5595b
+                    "initialized pool in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d",
b5595b
+                     getpid(), worker->s->hostname, worker->s->min,
b5595b
+                     worker->s->hmax, worker->s->smax);
b5595b
+
b5595b
+                /* Set the acquire timeout */
b5595b
+                if (rv == APR_SUCCESS && worker->s->acquire_set) {
b5595b
+                    apr_reslist_timeout_set(worker->cp->res, worker->s->acquire);
b5595b
+                }
b5595b
 
b5595b
-            rv = connection_constructor(&conn, worker, worker->cp->pool);
b5595b
-            worker->cp->conn = conn;
b5595b
+            }
b5595b
+            else {
b5595b
+                void *conn;
b5595b
+
b5595b
+                rv = connection_constructor(&conn, worker, worker->cp->pool);
b5595b
+                worker->cp->conn = conn;
b5595b
 
b5595b
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00931)
b5595b
-                 "initialized single connection worker in child %" APR_PID_T_FMT " for (%s)",
b5595b
-                 getpid(), worker->s->hostname);
b5595b
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s, APLOGNO(00931)
b5595b
+                     "initialized single connection worker in child %" APR_PID_T_FMT " for (%s)",
b5595b
+                     getpid(), worker->s->hostname);
b5595b
+            }
b5595b
+            if (rv == APR_SUCCESS) {
b5595b
+                worker->local_status |= (PROXY_WORKER_INITIALIZED);
b5595b
+            }
b5595b
         }
b5595b
         apr_global_mutex_unlock(proxy_mutex);
b5595b
 
b5595b
     }
b5595b
     if (rv == APR_SUCCESS) {
b5595b
         worker->s->status |= (PROXY_WORKER_INITIALIZED);
b5595b
-        worker->local_status |= (PROXY_WORKER_INITIALIZED);
b5595b
     }
b5595b
     return rv;
b5595b
 }
b5595b
@@ -2183,13 +2195,13 @@
b5595b
     else {
b5595b
         /* create the new connection if the previous was destroyed */
b5595b
         if (!worker->cp->conn) {
b5595b
-            connection_constructor((void **)conn, worker, worker->cp->pool);
b5595b
+            rv = connection_constructor((void **)conn, worker, worker->cp->pool);
b5595b
         }
b5595b
         else {
b5595b
             *conn = worker->cp->conn;
b5595b
             worker->cp->conn = NULL;
b5595b
+            rv = APR_SUCCESS;
b5595b
         }
b5595b
-        rv = APR_SUCCESS;
b5595b
     }
b5595b
 
b5595b
     if (rv != APR_SUCCESS) {
b5595b
@@ -2374,15 +2386,25 @@
b5595b
                 }
b5595b
 
b5595b
                 /*
b5595b
-                 * Worker can have the single constant backend adress.
b5595b
-                 * The single DNS lookup is used once per worker.
b5595b
-                 * If dynamic change is needed then set the addr to NULL
b5595b
-                 * inside dynamic config to force the lookup.
b5595b
+                 * Recheck addr after we got the lock. This may have changed
b5595b
+                 * while waiting for the lock.
b5595b
                  */
b5595b
-                err = apr_sockaddr_info_get(&(worker->cp->addr),
b5595b
-                                            conn->hostname, APR_UNSPEC,
b5595b
-                                            conn->port, 0,
b5595b
-                                            worker->cp->pool);
b5595b
+                if (!AP_VOLATILIZE_T(apr_sockaddr_t *, worker->cp->addr)) {
b5595b
+
b5595b
+                    apr_sockaddr_t *addr;
b5595b
+
b5595b
+                    /*
b5595b
+                     * Worker can have the single constant backend address.
b5595b
+                     * The single DNS lookup is used once per worker.
b5595b
+                     * If dynamic change is needed then set the addr to NULL
b5595b
+                     * inside dynamic config to force the lookup.
b5595b
+                     */
b5595b
+                    err = apr_sockaddr_info_get(&addr,
b5595b
+                                                conn->hostname, APR_UNSPEC,
b5595b
+                                                conn->port, 0,
b5595b
+                                                worker->cp->dns_pool);
b5595b
+                    worker->cp->addr = addr;
b5595b
+                }
b5595b
                 conn->addr = worker->cp->addr;
b5595b
                 if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) {
b5595b
                     ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock");