]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: muxes: Be prepared to don't own connection during the release
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 8 Apr 2019 08:52:21 +0000 (10:52 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 12 Apr 2019 20:06:53 +0000 (22:06 +0200)
This happens during mux upgrades. In such case, when the destroy() callback is
called, the connection points to a different mux's context than the one passed
to the callback. It means the connection is owned by another mux. The old mux is
then released but the connection is not closed.

src/mux_h1.c
src/mux_h2.c
src/mux_pt.c

index 43b062bbb57703bc098a133e22bab7ed84653bc1..ef9dd01dce43327d12c1d024c7fb8b52af0209e5 100644 (file)
@@ -445,6 +445,10 @@ static void h1_release(struct h1c *h1c)
 {
        struct connection *conn = h1c->conn;
 
+       /* The connection was attached to another mux */
+       if (conn && conn->ctx != h1c)
+               conn = NULL;
+
        if (h1c) {
                if (!LIST_ISEMPTY(&h1c->buf_wait.list)) {
                        HA_SPIN_LOCK(BUF_WQ_LOCK, &buffer_wq_lock);
@@ -466,20 +470,20 @@ static void h1_release(struct h1c *h1c)
                        tasklet_free(h1c->wait_event.task);
 
                h1s_destroy(h1c->h1s);
-               if (h1c->wait_event.events != 0)
-                       conn->xprt->unsubscribe(conn, h1c->wait_event.events,
-                           &h1c->wait_event);
                pool_free(pool_head_h1c, h1c);
        }
 
-       conn->mux = NULL;
-       conn->ctx = NULL;
+       if (conn) {
+               conn->mux = NULL;
+               conn->ctx = NULL;
 
-       conn_stop_tracking(conn);
-       conn_full_close(conn);
-       if (conn->destroy_cb)
-               conn->destroy_cb(conn);
-       conn_free(conn);
+               conn_force_unsubscribe(conn);
+               conn_stop_tracking(conn);
+               conn_full_close(conn);
+               if (conn->destroy_cb)
+                       conn->destroy_cb(conn);
+               conn_free(conn);
+       }
 }
 
 /******************************************************/
@@ -1988,7 +1992,7 @@ static void h1_destroy(void *ctx)
 {
        struct h1c *h1c = ctx;
 
-       if (!h1c->h1s)
+       if (!h1c->h1s || !h1c->conn || h1c->conn->ctx != h1c)
                h1_release(h1c);
 }
 
index 32e1fc1ab14ef3583b78231746d18334230f57d4..48876ee20db70119303f7cf6aa5c59ecdd5e94b0 100644 (file)
@@ -621,6 +621,11 @@ static void h2_release(struct h2c *h2c)
 {
        struct connection *conn = h2c->conn;
 
+       /* The connection was attached to another mux (unexpected but safer to
+        * check) */
+       if (conn && conn->ctx != h2c)
+               conn = NULL;
+
        if (h2c) {
                hpack_dht_free(h2c->ddht);
 
@@ -638,21 +643,21 @@ static void h2_release(struct h2c *h2c)
                }
                if (h2c->wait_event.task)
                        tasklet_free(h2c->wait_event.task);
-               if (h2c->wait_event.events != 0)
-                       conn->xprt->unsubscribe(conn, h2c->wait_event.events,
-                           &h2c->wait_event);
 
                pool_free(pool_head_h2c, h2c);
        }
 
-       conn->mux = NULL;
-       conn->ctx = NULL;
+       if (conn) {
+               conn->mux = NULL;
+               conn->ctx = NULL;
 
-       conn_stop_tracking(conn);
-       conn_full_close(conn);
-       if (conn->destroy_cb)
-               conn->destroy_cb(conn);
-       conn_free(conn);
+               conn_force_unsubscribe(conn);
+               conn_stop_tracking(conn);
+               conn_full_close(conn);
+               if (conn->destroy_cb)
+                       conn->destroy_cb(conn);
+               conn_free(conn);
+       }
 }
 
 
@@ -2989,7 +2994,7 @@ static void h2_destroy(void *ctx)
 {
        struct h2c *h2c = ctx;
 
-       if (eb_is_empty(&h2c->streams_by_id))
+       if (eb_is_empty(&h2c->streams_by_id) || !h2c->conn || h2c->conn->ctx != h2c)
                h2_release(h2c);
 }
 
index 6fb9f2f56e6467f96be612045541eb6bd8efdf85..82ba124b11a3fffd71a490325ba7f7e745f6a527 100644 (file)
@@ -28,17 +28,23 @@ static void mux_pt_destroy(struct mux_pt_ctx *ctx)
 {
        struct connection *conn = ctx->conn;
 
-       conn_stop_tracking(conn);
-       conn_full_close(conn);
-       tasklet_free(ctx->wait_event.task);
-       conn->mux = NULL;
-       conn->ctx = NULL;
-       if (conn->destroy_cb)
-               conn->destroy_cb(conn);
-       /* We don't bother unsubscribing here, as we're about to destroy
-        * both the connection and the mux_pt_ctx
-        */
-       conn_free(conn);
+       /* The connection was attached to another mux */
+       if (conn && conn->ctx != ctx)
+               conn = NULL;
+
+       if (conn) {
+               conn_stop_tracking(conn);
+               conn_full_close(conn);
+               tasklet_free(ctx->wait_event.task);
+               conn->mux = NULL;
+               conn->ctx = NULL;
+               if (conn->destroy_cb)
+                       conn->destroy_cb(conn);
+               /* We don't bother unsubscribing here, as we're about to destroy
+                * both the connection and the mux_pt_ctx
+                */
+               conn_free(conn);
+       }
        pool_free(pool_head_pt_ctx, ctx);
 }
 
@@ -172,7 +178,7 @@ static void mux_pt_destroy_meth(void *ctx)
 {
        struct mux_pt_ctx *pt = ctx;
 
-       if (!(pt->cs))
+       if (!(pt->cs) || !(pt->conn) || pt->conn->ctx != pt)
                mux_pt_destroy(pt);
 }