A kernel context, when added to multiple channels, must be copied
before being added to individual channels. The current code
adds the same ltt_kernel_context structure to multiple kernel
channels which introduces a conceptual ambiguity in the ownership
of the context object.
Concretely, creating multiple kernel channels and adding a context
to all of them (by not specifying a channel name) causes the context
to be added to each channels' list of contexts, overwritting the
context's list node, and causing the channel context lists to become
corrupted. This results in crashes being observed during the
destruction of the session.
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
/*
* Add kernel context to all channel.
/*
* Add kernel context to all channel.
+ *
+ * Assumes the ownership of kctx.
*/
static int add_kctx_all_channels(struct ltt_kernel_session *ksession,
struct ltt_kernel_context *kctx)
*/
static int add_kctx_all_channels(struct ltt_kernel_session *ksession,
struct ltt_kernel_context *kctx)
/* Go over all channels */
cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) {
/* Go over all channels */
cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) {
- ret = kernel_add_channel_context(kchan, kctx);
+ struct ltt_kernel_context *kctx_copy;
+
+ kctx_copy = trace_kernel_copy_context(kctx);
+ if (!kctx_copy) {
+ PERROR("zmalloc ltt_kernel_context");
+ goto error;
+ }
+
+ /* Ownership of kctx_copy is transferred to the callee. */
+ ret = kernel_add_channel_context(kchan, kctx_copy);
+ kctx_copy = NULL;
if (ret != 0) {
goto error;
}
if (ret != 0) {
goto error;
}
+ trace_kernel_destroy_context(kctx);
return ret;
}
/*
* Add kernel context to a specific channel.
return ret;
}
/*
* Add kernel context to a specific channel.
+ *
+ * Assumes the ownership of kctx.
*/
static int add_kctx_to_channel(struct ltt_kernel_context *kctx,
struct ltt_kernel_channel *kchan)
*/
static int add_kctx_to_channel(struct ltt_kernel_context *kctx,
struct ltt_kernel_channel *kchan)
DBG("Add kernel context to channel '%s'", kchan->channel->name);
DBG("Add kernel context to channel '%s'", kchan->channel->name);
+ /* Ownership of kctx is transferred to the callee. */
ret = kernel_add_channel_context(kchan, kctx);
ret = kernel_add_channel_context(kchan, kctx);
if (ret != 0) {
goto error;
}
if (ret != 0) {
goto error;
}
if (*channel_name == '\0') {
ret = add_kctx_all_channels(ksession, kctx);
if (*channel_name == '\0') {
ret = add_kctx_all_channels(ksession, kctx);
+ /* Ownership of kctx is transferred to the callee. */
+ kctx = NULL;
if (ret != LTTNG_OK) {
goto error;
}
if (ret != LTTNG_OK) {
goto error;
}
}
ret = add_kctx_to_channel(kctx, kchan);
}
ret = add_kctx_to_channel(kctx, kchan);
+ /* Ownership of kctx is transferred to the callee. */
+ kctx = NULL;
if (ret != LTTNG_OK) {
goto error;
}
}
if (ret != LTTNG_OK) {
goto error;
}
}
/*
* Add context on a kernel channel.
/*
* Add context on a kernel channel.
+ *
+ * Assumes the ownership of ctx.
*/
int kernel_add_channel_context(struct ltt_kernel_channel *chan,
struct ltt_kernel_context *ctx)
*/
int kernel_add_channel_context(struct ltt_kernel_channel *chan,
struct ltt_kernel_context *ctx)
end:
cds_list_add_tail(&ctx->list, &chan->ctx_list);
end:
cds_list_add_tail(&ctx->list, &chan->ctx_list);
+ if (ctx) {
+ trace_kernel_destroy_context(ctx);
+ }
if (ctx) {
memcpy(&kctx->ctx, ctx, sizeof(kctx->ctx));
}
if (ctx) {
memcpy(&kctx->ctx, ctx, sizeof(kctx->ctx));
}
+error:
+ return kctx;
+}
- CDS_INIT_LIST_HEAD(&kctx->list);
+/*
+ * Allocate and init a kernel context object from an existing kernel context
+ * object.
+ *
+ * Return the allocated object or NULL on error.
+ */
+struct ltt_kernel_context *trace_kernel_copy_context(
+ struct ltt_kernel_context *kctx)
+{
+ struct ltt_kernel_context *kctx_copy;
+
+ assert(kctx);
+ kctx_copy = zmalloc(sizeof(*kctx_copy));
+ if (!kctx_copy) {
+ PERROR("zmalloc ltt_kernel_context");
+ goto error;
+ }
+
+ memcpy(kctx_copy, kctx, sizeof(*kctx_copy));
+ memset(&kctx_copy->list, 0, sizeof(kctx_copy->list));
unsigned int count);
struct ltt_kernel_context *trace_kernel_create_context(
struct lttng_kernel_context *ctx);
unsigned int count);
struct ltt_kernel_context *trace_kernel_create_context(
struct lttng_kernel_context *ctx);
+struct ltt_kernel_context *trace_kernel_copy_context(
+ struct ltt_kernel_context *ctx);
/*
* Destroy functions free() the data structure and remove from linked list if
/*
* Destroy functions free() the data structure and remove from linked list if