return 0;
}
+static
+long lttng_abi_add_context(struct file *file,
+ struct lttng_kernel_context __user *ucontext_param,
+ struct lttng_ctx **ctx, struct ltt_session *session)
+{
+ struct lttng_kernel_context context_param;
+
+ if (session->been_active)
+ return -EPERM;
+
+ if (copy_from_user(&context_param, ucontext_param, sizeof(context_param)))
+ return -EFAULT;
+
+ switch (context_param.ctx) {
+ case LTTNG_CONTEXT_PID:
+ return lttng_add_pid_to_ctx(ctx);
+ case LTTNG_CONTEXT_PERF_COUNTER:
+ return -ENOSYS;
+ default:
+ return -EINVAL;
+ }
+}
+
/**
* lttng_ioctl - lttng syscall through ioctl
*
* This ioctl implements lttng commands:
* LTTNG_KERNEL_CHANNEL
* Returns a LTTng channel file descriptor
+ * LTTNG_KERNEL_SESSION_START
+ * Starts tracing session
+ * LTTNG_KERNEL_SESSION_STOP
+ * Stops tracing session
+ * LTTNG_KERNEL_METADATA
+ * Returns a LTTng metadata file descriptor
*
* The returned channel will be deleted when its file descriptor is closed.
*/
* (typically, one event stream records events from one CPU)
* LTTNG_KERNEL_EVENT
* Returns an event file descriptor or failure.
+ * LTTNG_KERNEL_CONTEXT
+ * Prepend a context field to each event in the channel
*
* Channel and event file descriptors also hold a reference on the session.
*/
static
long lttng_channel_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
+ struct ltt_channel *channel = file->private_data;
+
switch (cmd) {
case LTTNG_KERNEL_STREAM:
return lttng_abi_open_stream(file);
case LTTNG_KERNEL_EVENT:
return lttng_abi_create_event(file, (struct lttng_kernel_event __user *) arg);
+ case LTTNG_KERNEL_CONTEXT:
+ return lttng_abi_add_context(file,
+ (struct lttng_kernel_context __user *) arg,
+ &channel->ctx, channel->session);
default:
return -ENOIOCTLCMD;
}
#endif
};
+/**
+ * lttng_event_ioctl - lttng syscall through ioctl
+ *
+ * @file: the file
+ * @cmd: the command
+ * @arg: command arg
+ *
+ * This ioctl implements lttng commands:
+ * LTTNG_KERNEL_STREAM
+ * Returns an event stream file descriptor or failure.
+ * (typically, one event stream records events from one CPU)
+ * LTTNG_KERNEL_EVENT
+ * Returns an event file descriptor or failure.
+ * LTTNG_KERNEL_CONTEXT
+ * Prepend a context field to each record of this event
+ */
+static
+long lttng_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct ltt_event *event = file->private_data;
+
+ switch (cmd) {
+ case LTTNG_KERNEL_CONTEXT:
+ return lttng_abi_add_context(file,
+ (struct lttng_kernel_context __user *) arg,
+ &event->ctx, event->chan->session);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
static
int lttng_event_release(struct inode *inode, struct file *file)
{
/* TODO: filter control ioctl */
static const struct file_operations lttng_event_fops = {
.release = lttng_event_release,
+ .unlocked_ioctl = lttng_event_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lttng_event_ioctl,
+#endif
};
int __init ltt_debugfs_abi_init(void)
}
ACCESS_ONCE(session->active) = 1;
+ ACCESS_ONCE(session->been_active) = 1;
synchronize_trace(); /* Wait for in-flight events to complete */
ret = _ltt_session_metadata_statedump(session);
if (ret) {
struct ltt_transport *transport;
mutex_lock(&sessions_mutex);
- if (session->active) {
- printk(KERN_WARNING "LTTng refusing to add channel to active session\n");
+ if (session->been_active)
goto active; /* Refuse to add channel to active session */
- }
transport = ltt_transport_find(transport_name);
if (!transport) {
printk(KERN_WARNING "LTTng transport %s not found\n",
{
chan->ops->channel_destroy(chan->chan);
list_del(&chan->list);
+ lttng_destroy_context(chan->ctx);
kfree(chan);
}
WARN_ON_ONCE(1);
}
list_del(&event->list);
+ lttng_destroy_context(event->ctx);
kmem_cache_free(event_cache, event);
}
}
static
-int _ltt_fields_metadata_statedump(struct ltt_session *session,
- struct ltt_event *event)
+int _ltt_field_statedump(struct ltt_session *session,
+ const struct lttng_event_field *field)
{
- const struct lttng_event_desc *desc = event->desc;
int ret = 0;
- int i;
-
- for (i = 0; i < desc->nr_fields; i++) {
- const struct lttng_event_field *field = &desc->fields[i];
- switch (field->type.atype) {
- case atype_integer:
- ret = lttng_metadata_printf(session,
- " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s;\n",
- field->type.u.basic.integer.size,
- field->type.u.basic.integer.alignment,
- field->type.u.basic.integer.signedness,
- (field->type.u.basic.integer.encoding == lttng_encode_none)
- ? "none"
- : (field->type.u.basic.integer.encoding == lttng_encode_UTF8)
- ? "UTF8"
- : "ASCII",
- field->type.u.basic.integer.base,
+ switch (field->type.atype) {
+ case atype_integer:
+ ret = lttng_metadata_printf(session,
+ " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s;\n",
+ field->type.u.basic.integer.size,
+ field->type.u.basic.integer.alignment,
+ field->type.u.basic.integer.signedness,
+ (field->type.u.basic.integer.encoding == lttng_encode_none)
+ ? "none"
+ : (field->type.u.basic.integer.encoding == lttng_encode_UTF8)
+ ? "UTF8"
+ : "ASCII",
+ field->type.u.basic.integer.base,
#ifdef __BIG_ENDIAN
- field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
+ field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
#else
- field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
+ field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
#endif
- field->name);
- break;
- case atype_enum:
- ret = lttng_metadata_printf(session,
- " %s %s;\n",
- field->type.u.basic.enumeration.name,
- field->name);
- break;
- case atype_array:
- {
- const struct lttng_basic_type *elem_type;
-
- elem_type = &field->type.u.array.elem_type;
- ret = lttng_metadata_printf(session,
- " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[%u];\n",
- elem_type->u.basic.integer.size,
- elem_type->u.basic.integer.alignment,
- elem_type->u.basic.integer.signedness,
- (elem_type->u.basic.integer.encoding == lttng_encode_none)
- ? "none"
- : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8)
- ? "UTF8"
- : "ASCII",
- elem_type->u.basic.integer.base,
+ field->name);
+ break;
+ case atype_enum:
+ ret = lttng_metadata_printf(session,
+ " %s %s;\n",
+ field->type.u.basic.enumeration.name,
+ field->name);
+ break;
+ case atype_array:
+ {
+ const struct lttng_basic_type *elem_type;
+
+ elem_type = &field->type.u.array.elem_type;
+ ret = lttng_metadata_printf(session,
+ " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[%u];\n",
+ elem_type->u.basic.integer.size,
+ elem_type->u.basic.integer.alignment,
+ elem_type->u.basic.integer.signedness,
+ (elem_type->u.basic.integer.encoding == lttng_encode_none)
+ ? "none"
+ : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8)
+ ? "UTF8"
+ : "ASCII",
+ elem_type->u.basic.integer.base,
#ifdef __BIG_ENDIAN
- elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
+ elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
#else
- elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
+ elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
#endif
- field->name, field->type.u.array.length);
- break;
- }
- case atype_sequence:
- {
- const struct lttng_basic_type *elem_type;
- const struct lttng_basic_type *length_type;
-
- elem_type = &field->type.u.sequence.elem_type;
- length_type = &field->type.u.sequence.length_type;
- ret = lttng_metadata_printf(session,
- " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n",
- " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[ __%s_length ];\n",
- length_type->u.basic.integer.size,
- length_type->u.basic.integer.alignment,
- length_type->u.basic.integer.signedness,
- (length_type->u.basic.integer.encoding == lttng_encode_none)
- ? "none"
- : (length_type->u.basic.integer.encoding == lttng_encode_UTF8)
- ? "UTF8"
- : "ASCII",
- length_type->u.basic.integer.base,
+ field->name, field->type.u.array.length);
+ break;
+ }
+ case atype_sequence:
+ {
+ const struct lttng_basic_type *elem_type;
+ const struct lttng_basic_type *length_type;
+
+ elem_type = &field->type.u.sequence.elem_type;
+ length_type = &field->type.u.sequence.length_type;
+ ret = lttng_metadata_printf(session,
+ " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n",
+ " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[ __%s_length ];\n",
+ length_type->u.basic.integer.size,
+ length_type->u.basic.integer.alignment,
+ length_type->u.basic.integer.signedness,
+ (length_type->u.basic.integer.encoding == lttng_encode_none)
+ ? "none"
+ : (length_type->u.basic.integer.encoding == lttng_encode_UTF8)
+ ? "UTF8"
+ : "ASCII",
+ length_type->u.basic.integer.base,
#ifdef __BIG_ENDIAN
- length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
+ length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
#else
- length_type->u.basic.integer.reverse_byte_order
+ length_type->u.basic.integer.reverse_byte_order
? " byte_order = be;" : "",
#endif
- field->name,
- elem_type->u.basic.integer.size,
- elem_type->u.basic.integer.alignment,
- elem_type->u.basic.integer.signedness,
- (elem_type->u.basic.integer.encoding == lttng_encode_none)
- ? "none"
- : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8)
- ? "UTF8"
- : "ASCII",
- elem_type->u.basic.integer.base,
+ field->name,
+ elem_type->u.basic.integer.size,
+ elem_type->u.basic.integer.alignment,
+ elem_type->u.basic.integer.signedness,
+ (elem_type->u.basic.integer.encoding == lttng_encode_none)
+ ? "none"
+ : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8)
+ ? "UTF8"
+ : "ASCII",
+ elem_type->u.basic.integer.base,
#ifdef __BIG_ENDIAN
- elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
+ elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "",
#else
- elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
+ elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "",
#endif
- field->name,
- field->name
- );
- break;
- }
+ field->name,
+ field->name
+ );
+ break;
+ }
- case atype_string:
- /* Default encoding is UTF8 */
- ret = lttng_metadata_printf(session,
- " string%s %s;\n",
- field->type.u.basic.string.encoding == lttng_encode_ASCII ?
- " { encoding = ASCII; }" : "",
- field->name);
- break;
- default:
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
+ case atype_string:
+ /* Default encoding is UTF8 */
+ ret = lttng_metadata_printf(session,
+ " string%s %s;\n",
+ field->type.u.basic.string.encoding == lttng_encode_ASCII ?
+ " { encoding = ASCII; }" : "",
+ field->name);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static
+int _ltt_context_metadata_statedump(struct ltt_session *session,
+ struct lttng_ctx *ctx)
+{
+ int ret = 0;
+ int i;
+
+ if (!ctx)
+ return 0;
+ for (i = 0; i < ctx->nr_fields; i++) {
+ const struct lttng_ctx_field *field = &ctx->fields[i];
+
+ ret = _ltt_field_statedump(session, &field->event_field);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+static
+int _ltt_fields_metadata_statedump(struct ltt_session *session,
+ struct ltt_event *event)
+{
+ const struct lttng_event_desc *desc = event->desc;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < desc->nr_fields; i++) {
+ const struct lttng_event_field *field = &desc->fields[i];
+
+ ret = _ltt_field_statedump(session, field);
+ if (ret)
+ return ret;
}
return ret;
}
" name = %s;\n"
" id = %u;\n"
" stream_id = %u;\n"
- " fields := struct {\n",
+ " context := struct {\n",
event->desc->name,
event->id,
event->chan->id);
if (ret)
goto end;
+ ret = _ltt_context_metadata_statedump(session, event->ctx);
+ if (ret)
+ goto end;
+
+ ret = lttng_metadata_printf(session,
+ " };\n"
+ " fields := struct {\n"
+ );
+ if (ret)
+ goto end;
+
ret = _ltt_fields_metadata_statedump(session, event);
if (ret)
goto end;
" id = %u;\n"
" event.header := %s;\n"
" packet.context := struct packet_context;\n"
- "};\n\n",
+ " event.context := {\n",
chan->id,
chan->header_type == 1 ? "struct event_header_compact" :
"struct event_header_large");
if (ret)
goto end;
+ ret = _ltt_context_metadata_statedump(session, chan->ctx);
+ if (ret)
+ goto end;
+
+ ret = lttng_metadata_printf(session,
+ " };\n"
+ "};\n\n"
+ );
+
chan->metadata_dumped = 1;
end:
return ret;