summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
85016ad)
The "flush" operation can be performed on the metadata file descriptor
concurrently with get_next_subbuffer operations by different processes
(e.g. lttng session daemon issuing flush at "stop" concurrently with
consumer daemon issuing get_next_subbuf for metadata I/O). We need
to protect the metadata cache from those concurrent use by introducing a
mutex.
This fixes a race where metadata from a kernel trace is corrupted due to
this scenario. The corruption shows up like the same metadata content (a
metadata packet) being written twice consecutively in the metadata
stream, thus triggering a babeltrace "parse error" when trying to read
the trace.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
metadata_stream->priv = buf;
stream_priv = metadata_stream;
metadata_stream->transport = channel->transport;
metadata_stream->priv = buf;
stream_priv = metadata_stream;
metadata_stream->transport = channel->transport;
+ mutex_init(&metadata_stream->lock);
/*
* Since life-time of metadata cache differs from that of
/*
* Since life-time of metadata cache differs from that of
/*
* Ensure we support mutiple get_next / put sequences followed
/*
* Ensure we support mutiple get_next / put sequences followed
+ * by put_next. The metadata stream lock internally protects
+ * reading the metadata cache. It can indeed be read
+ * concurrently by "get_next_subbuf" and "flush" operations on
+ * the buffer invoked by different processes.
+ mutex_lock(&stream->lock);
WARN_ON(stream->metadata_in < stream->metadata_out);
if (stream->metadata_in != stream->metadata_out)
WARN_ON(stream->metadata_in < stream->metadata_out);
if (stream->metadata_in != stream->metadata_out)
len = stream->metadata_cache->metadata_written -
stream->metadata_in;
if (!len)
len = stream->metadata_cache->metadata_written -
stream->metadata_in;
if (!len)
reserve_len = min_t(size_t,
stream->transport->ops.packet_avail_size(chan),
len);
reserve_len = min_t(size_t,
stream->transport->ops.packet_avail_size(chan),
len);
+ mutex_unlock(&stream->lock);
wait_queue_head_t read_wait; /* Reader buffer-level wait queue */
struct list_head list; /* Stream list */
struct lttng_transport *transport;
wait_queue_head_t read_wait; /* Reader buffer-level wait queue */
struct list_head list; /* Stream list */
struct lttng_transport *transport;
};
struct lttng_session {
};
struct lttng_session {