#include <linux/dmi.h>
#include <wrapper/uuid.h>
-#include <wrapper/vmalloc.h> /* for wrapper_vmalloc_sync_all() */
+#include <wrapper/vmalloc.h> /* for wrapper_vmalloc_sync_mappings() */
#include <wrapper/random.h>
#include <wrapper/tracepoint.h>
#include <wrapper/list.h>
BUG_ON(chan->channel_type == METADATA_CHANNEL);
_lttng_channel_destroy(chan);
}
+ mutex_lock(&session->metadata_cache->lock);
list_for_each_entry(metadata_stream, &session->metadata_cache->metadata_stream, list)
_lttng_metadata_channel_hangup(metadata_stream);
+ mutex_unlock(&session->metadata_cache->lock);
lttng_id_tracker_destroy(&session->pid_tracker, false);
lttng_id_tracker_destroy(&session->vpid_tracker, false);
lttng_id_tracker_destroy(&session->uid_tracker, false);
* was written and a negative value on error.
*/
int lttng_metadata_output_channel(struct lttng_metadata_stream *stream,
- struct channel *chan)
+ struct channel *chan, bool *coherent)
{
struct lib_ring_buffer_ctx ctx;
int ret = 0;
ret = stream->transport->ops.event_reserve(&ctx, 0);
if (ret != 0) {
printk(KERN_WARNING "LTTng: Metadata event reservation failed\n");
+ stream->coherent = false;
goto end;
}
stream->transport->ops.event_write(&ctx,
reserve_len);
stream->transport->ops.event_commit(&ctx);
stream->metadata_in += reserve_len;
+ if (reserve_len < len)
+ stream->coherent = false;
+ else
+ stream->coherent = true;
ret = reserve_len;
end:
+ if (coherent)
+ *coherent = stream->coherent;
mutex_unlock(&stream->metadata_cache->lock);
return ret;
}
+static
+void lttng_metadata_begin(struct lttng_session *session)
+{
+ if (atomic_inc_return(&session->metadata_cache->producing) == 1)
+ mutex_lock(&session->metadata_cache->lock);
+}
+
+static
+void lttng_metadata_end(struct lttng_session *session)
+{
+ WARN_ON_ONCE(!atomic_read(&session->metadata_cache->producing));
+ if (atomic_dec_return(&session->metadata_cache->producing) == 0) {
+ struct lttng_metadata_stream *stream;
+
+ list_for_each_entry(stream, &session->metadata_cache->metadata_stream, list)
+ wake_up_interruptible(&stream->read_wait);
+ mutex_unlock(&session->metadata_cache->lock);
+ }
+}
+
/*
* Write the metadata to the metadata cache.
* Must be called with sessions_mutex held.
* The metadata cache lock protects us from concurrent read access from
* thread outputting metadata content to ring buffer.
+ * The content of the printf is printed as a single atomic metadata
+ * transaction.
*/
int lttng_metadata_printf(struct lttng_session *session,
const char *fmt, ...)
char *str;
size_t len;
va_list ap;
- struct lttng_metadata_stream *stream;
WARN_ON_ONCE(!READ_ONCE(session->active));
return -ENOMEM;
len = strlen(str);
- mutex_lock(&session->metadata_cache->lock);
+ WARN_ON_ONCE(!atomic_read(&session->metadata_cache->producing));
if (session->metadata_cache->metadata_written + len >
session->metadata_cache->cache_alloc) {
char *tmp_cache_realloc;
session->metadata_cache->metadata_written,
str, len);
session->metadata_cache->metadata_written += len;
- mutex_unlock(&session->metadata_cache->lock);
kfree(str);
- list_for_each_entry(stream, &session->metadata_cache->metadata_stream, list)
- wake_up_interruptible(&stream->read_wait);
-
return 0;
err:
- mutex_unlock(&session->metadata_cache->lock);
kfree(str);
return -ENOMEM;
}
/*
* Must be called with sessions_mutex held.
+ * The entire event metadata is printed as a single atomic metadata
+ * transaction.
*/
static
int _lttng_event_metadata_statedump(struct lttng_session *session,
if (chan->channel_type == METADATA_CHANNEL)
return 0;
+ lttng_metadata_begin(session);
+
ret = lttng_metadata_printf(session,
"event {\n"
" name = \"%s\";\n"
event->metadata_dumped = 1;
end:
+ lttng_metadata_end(session);
return ret;
}
/*
* Must be called with sessions_mutex held.
+ * The entire channel metadata is printed as a single atomic metadata
+ * transaction.
*/
static
int _lttng_channel_metadata_statedump(struct lttng_session *session,
if (chan->channel_type == METADATA_CHANNEL)
return 0;
+ lttng_metadata_begin(session);
+
WARN_ON_ONCE(!chan->header_type);
ret = lttng_metadata_printf(session,
"stream {\n"
chan->metadata_dumped = 1;
end:
+ lttng_metadata_end(session);
return ret;
}
if (!READ_ONCE(session->active))
return 0;
+
+ lttng_metadata_begin(session);
+
if (session->metadata_dumped)
goto skip_session;
}
session->metadata_dumped = 1;
end:
+ lttng_metadata_end(session);
return ret;
}
* Registers a transport which can be used as output to extract the data out of
* LTTng. The module calling this registration function must ensure that no
* trap-inducing code will be executed by the transport functions. E.g.
- * vmalloc_sync_all() must be called between a vmalloc and the moment the memory
+ * vmalloc_sync_mappings() must be called between a vmalloc and the moment the memory
* is made visible to the transport function. This registration acts as a
- * vmalloc_sync_all. Therefore, only if the module allocates virtual memory
+ * vmalloc_sync_mappings. Therefore, only if the module allocates virtual memory
* after its registration must it synchronize the TLBs.
*/
void lttng_transport_register(struct lttng_transport *transport)
/*
* Make sure no page fault can be triggered by the module about to be
* registered. We deal with this here so we don't have to call
- * vmalloc_sync_all() in each module's init.
+ * vmalloc_sync_mappings() in each module's init.
*/
- wrapper_vmalloc_sync_all();
+ wrapper_vmalloc_sync_mappings();
mutex_lock(&sessions_mutex);
list_add_tail(&transport->node, <tng_transport_list);