MINOR: muxes: Pass the context of the mux to destroy() instead of the connection

It is mandatory to handle mux upgrades, because during a mux upgrade, the
connection will be reassigned to another multiplexer. So when the old one is
destroyed, it does not own the connection anymore. Or in other words, conn->ctx
does not point to the old mux's context when its destroy() callback is
called. So we now rely on the multiplexer context do destroy it instead of the
connection.

In addition, h1_release() and h2_release() have also been updated in the same
way.
This commit is contained in:
Christopher Faulet 2019-04-08 11:23:22 +02:00
parent 51f73eb11a
commit 73c1207c71
8 changed files with 35 additions and 34 deletions

View File

@ -126,7 +126,7 @@ static inline int session_check_idle_conn(struct session *sess, struct connectio
conn->owner = NULL;
if (!srv_add_to_idle_list(objt_server(conn->target), conn)) {
/* The server doesn't want it, let's kill the connection right away */
conn->mux->destroy(conn);
conn->mux->destroy(conn->ctx);
return -1;
} else
conn->flags &= ~CO_FL_SESS_IDLE;

View File

@ -346,7 +346,7 @@ struct mux_ops {
int (*unsubscribe)(struct conn_stream *cs, int event_type, void *param); /* Unsubscribe to events */
int (*avail_streams)(struct connection *conn); /* Returns the number of streams still available for a connection */
int (*used_streams)(struct connection *conn); /* Returns the number of streams in use on a connection. */
void (*destroy)(struct connection *conn); /* Let the mux know one of its users left, so it may have to disappear */
void (*destroy)(void *ctx); /* Let the mux know one of its users left, so it may have to disappear */
void (*reset)(struct connection *conn); /* Reset the mux, because we're re-trying to connect */
const struct cs_info *(*get_cs_info)(struct conn_stream *cs); /* Return info on the specified conn_stream or NULL if not defined */
unsigned int flags; /* some flags characterizing the mux's capabilities (MX_FL_*) */

View File

@ -1371,7 +1371,7 @@ int connect_server(struct stream *s)
old_conn->owner = sess;
if (!session_add_conn(sess, old_conn, old_conn->target)) {
old_conn->owner = NULL;
old_conn->mux->destroy(old_conn);
old_conn->mux->destroy(old_conn->ctx);
} else
session_check_idle_conn(sess, old_conn);
}
@ -1427,7 +1427,7 @@ int connect_server(struct stream *s)
srv_conn->owner = NULL;
if (srv_conn->mux && !srv_add_to_idle_list(objt_server(srv_conn->target), srv_conn))
/* The server doesn't want it, let's kill the connection right away */
srv_conn->mux->destroy(srv_conn);
srv_conn->mux->destroy(srv_conn->ctx);
srv_conn = NULL;
}

View File

@ -438,13 +438,12 @@ static int h1_init(struct connection *conn, struct proxy *proxy, struct session
return -1;
}
/* release function for a connection. This one should be called to free all
* resources allocated to the mux.
/* release function. This one should be called to free all resources allocated
* to the mux.
*/
static void h1_release(struct connection *conn)
static void h1_release(struct h1c *h1c)
{
struct h1c *h1c = conn->ctx;
struct connection *conn = h1c->conn;
if (h1c) {
if (!LIST_ISEMPTY(&h1c->buf_wait.list)) {
@ -1867,7 +1866,7 @@ static int h1_process(struct h1c * h1c)
return 0;
release:
h1_release(conn);
h1_release(h1c);
return -1;
}
@ -1936,13 +1935,14 @@ static struct task *h1_timeout_task(struct task *t, void *context, unsigned shor
if (h1c->h1s && h1c->h1s->cs)
h1c->flags |= H1C_F_CS_ERROR;
else
h1_release(h1c->conn);
h1_release(h1c);
return NULL;
}
/*******************************************/
/* functions below are used by the streams */
/*******************************************/
/*
* Attach a new stream to a connection
* (Used for outgoing connections)
@ -1984,12 +1984,12 @@ static const struct conn_stream *h1_get_first_cs(const struct connection *conn)
return NULL;
}
static void h1_destroy(struct connection *conn)
static void h1_destroy(void *ctx)
{
struct h1c *h1c = conn->ctx;
struct h1c *h1c = ctx;
if (!h1c->h1s)
h1_release(conn);
h1_release(h1c);
}
/*
@ -2065,7 +2065,7 @@ static void h1_detach(struct conn_stream *cs)
/* We don't want to close right now unless the connection is in error */
if ((h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTDOWN)) ||
(h1c->conn->flags & CO_FL_ERROR) || !h1c->conn->owner)
h1_release(h1c->conn);
h1_release(h1c);
else {
tasklet_wakeup(h1c->wait_event.task);
if (h1c->task) {

View File

@ -614,12 +614,12 @@ static inline struct h2s *h2c_st_by_id(struct h2c *h2c, int id)
return container_of(node, struct h2s, by_id);
}
/* release function for a connection. This one should be called to free all
* resources allocated to the mux.
/* release function. This one should be called to free all resources allocated
* to the mux.
*/
static void h2_release(struct connection *conn)
static void h2_release(struct h2c *h2c)
{
struct h2c *h2c = conn->ctx;
struct connection *conn = h2c->conn;
if (h2c) {
hpack_dht_free(h2c->ddht);
@ -2845,7 +2845,7 @@ static int h2_process(struct h2c *h2c)
if (eb_is_empty(&h2c->streams_by_id)) {
/* no more stream, kill the connection now */
h2_release(conn);
h2_release(h2c);
return -1;
}
}
@ -2930,7 +2930,7 @@ static struct task *h2_timeout_task(struct task *t, void *context, unsigned shor
* the last stream closes.
*/
if (eb_is_empty(&h2c->streams_by_id))
h2_release(h2c->conn);
h2_release(h2c);
return NULL;
}
@ -2985,12 +2985,12 @@ static const struct conn_stream *h2_get_first_cs(const struct connection *conn)
/*
* Destroy the mux and the associated connection, if it is no longer used
*/
static void h2_destroy(struct connection *conn)
static void h2_destroy(void *ctx)
{
struct h2c *h2c = conn->ctx;
struct h2c *h2c = ctx;
if (eb_is_empty(&h2c->streams_by_id))
h2_release(h2c->conn);
h2_release(h2c);
}
/*
@ -3082,7 +3082,7 @@ static void h2_detach(struct conn_stream *cs)
*/
if (h2c_is_dead(h2c)) {
/* no more stream will come, kill it now */
h2_release(h2c->conn);
h2_release(h2c);
}
else if (h2c->task) {
if (eb_is_empty(&h2c->streams_by_id) || b_data(&h2c->mbuf)) {
@ -3248,7 +3248,7 @@ static struct task *h2_deferred_shut(struct task *t, void *ctx, unsigned short s
h2s_destroy(h2s);
if (h2c_is_dead(h2c))
h2_release(h2c->conn);
h2_release(h2c);
}
return NULL;

View File

@ -166,13 +166,14 @@ static const struct conn_stream *mux_pt_get_first_cs(const struct connection *co
return cs;
}
/* Destroy the mux and the associated connection, if no longer used */
static void mux_pt_destroy_meth(struct connection *conn)
/* Destroy the mux and the associated connection if still attached to this mux
* and no longer used */
static void mux_pt_destroy_meth(void *ctx)
{
struct mux_pt_ctx *ctx = conn->ctx;
struct mux_pt_ctx *pt = ctx;
if (!(ctx->cs))
mux_pt_destroy(ctx);
if (!(pt->cs))
mux_pt_destroy(pt);
}
/*

View File

@ -5317,7 +5317,7 @@ struct task *srv_cleanup_toremove_connections(struct task *task, void *context,
while ((conn = LIST_POP_LOCKED(&toremove_connections[tid],
struct connection *, list)) != NULL) {
conn->mux->destroy(conn);
conn->mux->destroy(conn->ctx);
}
return task;

View File

@ -74,7 +74,7 @@ void session_free(struct session *sess)
vars_prune_per_sess(&sess->vars);
conn = objt_conn(sess->origin);
if (conn != NULL && conn->mux)
conn->mux->destroy(conn);
conn->mux->destroy(conn->ctx);
list_for_each_entry_safe(srv_list, srv_list_back, &sess->srv_list, srv_list) {
list_for_each_entry_safe(conn, conn_back, &srv_list->conn_list, session_list) {
if (conn->mux) {
@ -84,7 +84,7 @@ void session_free(struct session *sess)
conn->owner = NULL;
conn->flags &= ~CO_FL_SESS_IDLE;
if (!srv_add_to_idle_list(objt_server(conn->target), conn))
conn->mux->destroy(conn);
conn->mux->destroy(conn->ctx);
} else {
/* We have a connection, but not yet an associated mux.
* So destroy it now.