From 62bad3bf0aaade7f80ba4e536e1b9e734ec2e051 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Fri, 9 Aug 2019 11:18:47 -0400 Subject: [PATCH] relayd fix: trace chunk is reclaimed before close command MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The relay daemon control protocol defines a trace chunk close command which allows the tracer to express the 'end' time bound of a trace chunk. However, in the event of a session rotation, the last reference to such a trace chunk can be released before the close command is received. This prevents the trace chunk from being renamed and moved at the completion of a rotation. A reference to a 'pending closure' trace chunk is kept as part of the relay session object until its 'close' command is received. Signed-off-by: Jérémie Galarneau --- src/bin/lttng-relayd/main.c | 33 ++++++++++++++++++++++++++++----- src/bin/lttng-relayd/session.c | 2 ++ src/bin/lttng-relayd/session.h | 1 + 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/bin/lttng-relayd/main.c b/src/bin/lttng-relayd/main.c index 82e260354..a3e2509d2 100644 --- a/src/bin/lttng-relayd/main.c +++ b/src/bin/lttng-relayd/main.c @@ -2423,11 +2423,22 @@ static int relay_create_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr, } pthread_mutex_lock(&conn->session->lock); - lttng_trace_chunk_put(conn->session->current_trace_chunk); + if (conn->session->pending_closure_trace_chunk) { + /* + * Invalid; this means a second create_trace_chunk command was + * received before a close_trace_chunk. + */ + ERR("Invalid trace chunk close command received; a trace chunk is already waiting for a trace chunk close command"); + reply_code = LTTNG_ERR_INVALID_PROTOCOL; + ret = -1; + goto end_unlock_session; + } + conn->session->pending_closure_trace_chunk = + conn->session->current_trace_chunk; conn->session->current_trace_chunk = published_chunk; published_chunk = NULL; +end_unlock_session: pthread_mutex_unlock(&conn->session->lock); - end: reply.ret_code = htobe32((uint32_t) reply_code); send_ret = conn->sock->ops->sendmsg(conn->sock, @@ -2512,13 +2523,23 @@ static int relay_close_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr, goto end; } + pthread_mutex_lock(&session->lock); + if (session->pending_closure_trace_chunk && + session->pending_closure_trace_chunk != chunk) { + ERR("Trace chunk close command for session \"%s\" does not target the trace chunk pending closure", + session->session_name); + reply_code = LTTNG_ERR_INVALID_PROTOCOL; + ret = -1; + goto end_unlock_session; + } + chunk_status = lttng_trace_chunk_set_close_timestamp( chunk, close_timestamp); if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) { ERR("Failed to set trace chunk close timestamp"); ret = -1; reply_code = LTTNG_ERR_UNK; - goto end; + goto end_unlock_session; } if (close_command.is_set) { @@ -2527,11 +2548,10 @@ static int relay_close_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr, if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) { ret = -1; reply_code = LTTNG_ERR_INVALID; - goto end; + goto end_unlock_session; } } - pthread_mutex_lock(&session->lock); if (session->current_trace_chunk == chunk) { /* * After a trace chunk close command, no new streams @@ -2544,6 +2564,9 @@ static int relay_close_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr, lttng_trace_chunk_put(session->current_trace_chunk); session->current_trace_chunk = NULL; } + lttng_trace_chunk_put(session->pending_closure_trace_chunk); + session->pending_closure_trace_chunk = NULL; +end_unlock_session: pthread_mutex_unlock(&session->lock); end: diff --git a/src/bin/lttng-relayd/session.c b/src/bin/lttng-relayd/session.c index 0997fdd65..28e75f1dc 100644 --- a/src/bin/lttng-relayd/session.c +++ b/src/bin/lttng-relayd/session.c @@ -245,6 +245,8 @@ static void destroy_session(struct relay_session *session) assert(!ret); lttng_trace_chunk_put(session->current_trace_chunk); session->current_trace_chunk = NULL; + lttng_trace_chunk_put(session->pending_closure_trace_chunk); + session->pending_closure_trace_chunk = NULL; ret = sessiond_trace_chunk_registry_session_destroyed( sessiond_trace_chunk_registry, session->sessiond_uuid); assert(!ret); diff --git a/src/bin/lttng-relayd/session.h b/src/bin/lttng-relayd/session.h index 8b8ae1f21..6442c17ee 100644 --- a/src/bin/lttng-relayd/session.h +++ b/src/bin/lttng-relayd/session.h @@ -120,6 +120,7 @@ struct relay_session { */ struct cds_list_head viewer_session_node; struct lttng_trace_chunk *current_trace_chunk; + struct lttng_trace_chunk *pending_closure_trace_chunk; struct rcu_head rcu_node; /* For call_rcu teardown. */ }; -- 2.34.1