From: Julien Desfossez Date: Thu, 12 Nov 2015 20:49:24 +0000 (-0500) Subject: Contexts for RT debugging X-Git-Tag: v2.8.0-rc1~58 X-Git-Url: http://git.lttng.org/?p=lttng-modules.git;a=commitdiff_plain;h=79150a4903b5f31695fcd1d9655555ba6dc4bfa4 Contexts for RT debugging Add the interruptible, preemptible, need_resched and migratable contexts. Signed-off-by: Julien Desfossez Signed-off-by: Mathieu Desnoyers --- diff --git a/Makefile b/Makefile index f7aa23f6..29204bc0 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,8 @@ lttng-tracer-objs := lttng-events.o lttng-abi.o \ lttng-context-vpid.o lttng-context-tid.o \ lttng-context-vtid.o lttng-context-ppid.o \ lttng-context-vppid.o lttng-context-cpu-id.o \ - lttng-calibrate.o \ + lttng-context-interruptible.o \ + lttng-context-need-reschedule.o lttng-calibrate.o \ lttng-context-hostname.o wrapper/random.o \ probes/lttng.o wrapper/trace-clock.o \ wrapper/page_alloc.o \ @@ -66,6 +67,15 @@ lttng-tracer-objs += $(shell \ echo "lttng-context-perf-counters.o" ; fi;) endif # CONFIG_PERF_EVENTS +ifneq ($(CONFIG_PREEMPT_RT_FULL),) +lttng-tracer-objs += lttng-context-migratable.o +lttng-tracer-objs += lttng-context-preemptible.o +endif # CONFIG_PREEMPT_RT_FULL + +ifneq ($(CONFIG_PREEMPT),) +lttng-tracer-objs += lttng-context-preemptible.o +endif + lttng-tracer-objs += $(shell \ if [ $(VERSION) -ge 4 \ -o \( $(VERSION) -eq 3 -a $(PATCHLEVEL) -ge 15 -a $(SUBLEVEL) -ge 0 \) ] ; then \ diff --git a/lttng-abi.c b/lttng-abi.c index f6f30430..b3de0926 100644 --- a/lttng-abi.c +++ b/lttng-abi.c @@ -236,6 +236,14 @@ long lttng_abi_add_context(struct file *file, return lttng_add_hostname_to_ctx(ctx); case LTTNG_KERNEL_CONTEXT_CPU_ID: return lttng_add_cpu_id_to_ctx(ctx); + case LTTNG_KERNEL_CONTEXT_INTERRUPTIBLE: + return lttng_add_interruptible_to_ctx(ctx); + case LTTNG_KERNEL_CONTEXT_NEED_RESCHEDULE: + return lttng_add_need_reschedule_to_ctx(ctx); + case LTTNG_KERNEL_CONTEXT_PREEMPTIBLE: + return lttng_add_preemptible_to_ctx(ctx); + case LTTNG_KERNEL_CONTEXT_MIGRATABLE: + return lttng_add_migratable_to_ctx(ctx); default: return -EINVAL; } diff --git a/lttng-abi.h b/lttng-abi.h index a40b58f5..e53ff272 100644 --- a/lttng-abi.h +++ b/lttng-abi.h @@ -142,6 +142,10 @@ enum lttng_kernel_context_type { LTTNG_KERNEL_CONTEXT_VPPID = 9, LTTNG_KERNEL_CONTEXT_HOSTNAME = 10, LTTNG_KERNEL_CONTEXT_CPU_ID = 11, + LTTNG_KERNEL_CONTEXT_INTERRUPTIBLE = 12, + LTTNG_KERNEL_CONTEXT_PREEMPTIBLE = 13, + LTTNG_KERNEL_CONTEXT_NEED_RESCHEDULE = 14, + LTTNG_KERNEL_CONTEXT_MIGRATABLE = 15, }; struct lttng_kernel_perf_counter_ctx { diff --git a/lttng-context-cpu-id.c b/lttng-context-cpu-id.c index 0738d9c7..ed2a2a92 100644 --- a/lttng-context-cpu-id.c +++ b/lttng-context-cpu-id.c @@ -52,6 +52,7 @@ void cpu_id_record(struct lttng_ctx_field *field, static void cpu_id_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { value->s64 = smp_processor_id(); diff --git a/lttng-context-hostname.c b/lttng-context-hostname.c index 28881d05..7d9f0816 100644 --- a/lttng-context-hostname.c +++ b/lttng-context-hostname.c @@ -67,6 +67,7 @@ void hostname_record(struct lttng_ctx_field *field, static void hostname_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { struct nsproxy *nsproxy; diff --git a/lttng-context-interruptible.c b/lttng-context-interruptible.c new file mode 100644 index 00000000..b608a6e2 --- /dev/null +++ b/lttng-context-interruptible.c @@ -0,0 +1,102 @@ +/* + * lttng-context-interruptible.c + * + * LTTng interruptible context. + * + * Copyright (C) 2009-2015 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include "lttng-events.h" +#include "wrapper/ringbuffer/frontend_types.h" +#include "wrapper/vmalloc.h" +#include "lttng-tracer.h" + +/* + * Interruptible at value -1 means "unknown". + */ + +static +size_t interruptible_get_size(size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(int8_t)); + size += sizeof(int8_t); + return size; +} + +static +void interruptible_record(struct lttng_ctx_field *field, + struct lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + struct lttng_probe_ctx *lttng_probe_ctx = ctx->priv; + int8_t interruptible = lttng_probe_ctx->interruptible; + + lib_ring_buffer_align_ctx(ctx, lttng_alignof(interruptible)); + chan->ops->event_write(ctx, &interruptible, sizeof(interruptible)); +} + +static +void interruptible_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, + union lttng_ctx_value *value) +{ + int8_t interruptible = lttng_probe_ctx->interruptible; + + value->s64 = interruptible; +} + +int lttng_add_interruptible_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "interruptible")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "interruptible"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(int8_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(int8_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(int8_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = interruptible_get_size; + field->record = interruptible_record; + field->get_value = interruptible_get_value; + lttng_context_update(*ctx); + wrapper_vmalloc_sync_all(); + return 0; +} +EXPORT_SYMBOL_GPL(lttng_add_interruptible_to_ctx); + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("Linux Trace Toolkit interruptible Context"); +MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "." + __stringify(LTTNG_MODULES_MINOR_VERSION) "." + __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION) + LTTNG_MODULES_EXTRAVERSION); diff --git a/lttng-context-migratable.c b/lttng-context-migratable.c new file mode 100644 index 00000000..1aaedf6a --- /dev/null +++ b/lttng-context-migratable.c @@ -0,0 +1,95 @@ +/* + * lttng-context-migratable.c + * + * LTTng migratable context. + * + * Copyright (C) 2009-2015 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include "lttng-events.h" +#include "wrapper/ringbuffer/frontend_types.h" +#include "wrapper/vmalloc.h" +#include "lttng-tracer.h" + +static +size_t migratable_get_size(size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(uint8_t)); + size += sizeof(uint8_t); + return size; +} + +static +void migratable_record(struct lttng_ctx_field *field, + struct lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + uint8_t migratable = !__migrate_disabled(current); + + lib_ring_buffer_align_ctx(ctx, lttng_alignof(migratable)); + chan->ops->event_write(ctx, &migratable, sizeof(migratable)); +} + +static +void migratable_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, + union lttng_ctx_value *value) +{ + value->s64 = !__migrate_disabled(current); +} + +int lttng_add_migratable_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "migratable")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "migratable"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(uint8_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(uint8_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(uint8_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = migratable_get_size; + field->record = migratable_record; + field->get_value = migratable_get_value; + lttng_context_update(*ctx); + wrapper_vmalloc_sync_all(); + return 0; +} +EXPORT_SYMBOL_GPL(lttng_add_migratable_to_ctx); + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("Linux Trace Toolkit migratable Context"); +MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "." + __stringify(LTTNG_MODULES_MINOR_VERSION) "." + __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION) + LTTNG_MODULES_EXTRAVERSION); diff --git a/lttng-context-need-reschedule.c b/lttng-context-need-reschedule.c new file mode 100644 index 00000000..82f2d614 --- /dev/null +++ b/lttng-context-need-reschedule.c @@ -0,0 +1,95 @@ +/* + * lttng-context-need-reschedule.c + * + * LTTng need_reschedule context. + * + * Copyright (C) 2009-2015 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include "lttng-events.h" +#include "wrapper/ringbuffer/frontend_types.h" +#include "wrapper/vmalloc.h" +#include "lttng-tracer.h" + +static +size_t need_reschedule_get_size(size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(uint8_t)); + size += sizeof(uint8_t); + return size; +} + +static +void need_reschedule_record(struct lttng_ctx_field *field, + struct lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + uint8_t need_reschedule = test_tsk_need_resched(current); + + lib_ring_buffer_align_ctx(ctx, lttng_alignof(need_reschedule)); + chan->ops->event_write(ctx, &need_reschedule, sizeof(need_reschedule)); +} + +static +void need_reschedule_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, + union lttng_ctx_value *value) +{ + value->s64 = test_tsk_need_resched(current);; +} + +int lttng_add_need_reschedule_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "need_reschedule")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "need_reschedule"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(uint8_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(uint8_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(uint8_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = need_reschedule_get_size; + field->record = need_reschedule_record; + field->get_value = need_reschedule_get_value; + lttng_context_update(*ctx); + wrapper_vmalloc_sync_all(); + return 0; +} +EXPORT_SYMBOL_GPL(lttng_add_need_reschedule_to_ctx); + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("Linux Trace Toolkit need_reschedule Context"); +MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "." + __stringify(LTTNG_MODULES_MINOR_VERSION) "." + __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION) + LTTNG_MODULES_EXTRAVERSION); diff --git a/lttng-context-nice.c b/lttng-context-nice.c index 412dd93a..b2d7705f 100644 --- a/lttng-context-nice.c +++ b/lttng-context-nice.c @@ -52,6 +52,7 @@ void nice_record(struct lttng_ctx_field *field, static void nice_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { value->s64 = task_nice(current); diff --git a/lttng-context-pid.c b/lttng-context-pid.c index 3211819d..5ad92c14 100644 --- a/lttng-context-pid.c +++ b/lttng-context-pid.c @@ -52,6 +52,7 @@ void pid_record(struct lttng_ctx_field *field, static void pid_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { value->s64 = task_tgid_nr(current); diff --git a/lttng-context-ppid.c b/lttng-context-ppid.c index 33ea1a79..28c97b58 100644 --- a/lttng-context-ppid.c +++ b/lttng-context-ppid.c @@ -62,6 +62,7 @@ void ppid_record(struct lttng_ctx_field *field, static void ppid_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { pid_t ppid; diff --git a/lttng-context-preemptible.c b/lttng-context-preemptible.c new file mode 100644 index 00000000..d4d474cf --- /dev/null +++ b/lttng-context-preemptible.c @@ -0,0 +1,113 @@ +/* + * lttng-context-preemptible.c + * + * LTTng preemptible context. + * + * Copyright (C) 2009-2015 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include "lttng-events.h" +#include "wrapper/ringbuffer/frontend_types.h" +#include "wrapper/vmalloc.h" +#include "lttng-tracer.h" + +/* + * We nest twice in preempt disabling within LTTng: one nesting is done + * by the instrumentation (tracepoint, kprobes, kretprobes, syscall + * tracepoint), and the second is within the lib ring buffer + * lib_ring_buffer_get_cpu(). + */ +#define LTTNG_PREEMPT_DISABLE_NESTING 2 + +static +size_t preemptible_get_size(size_t offset) +{ + size_t size = 0; + + size += lib_ring_buffer_align(offset, lttng_alignof(uint8_t)); + size += sizeof(uint8_t); + return size; +} + +static +void preemptible_record(struct lttng_ctx_field *field, + struct lib_ring_buffer_ctx *ctx, + struct lttng_channel *chan) +{ + int pc = preempt_count(); + uint8_t preemptible = 0; + + WARN_ON_ONCE(pc < LTTNG_PREEMPT_DISABLE_NESTING); + if (pc == LTTNG_PREEMPT_DISABLE_NESTING) + preemptible = 1; + lib_ring_buffer_align_ctx(ctx, lttng_alignof(preemptible)); + chan->ops->event_write(ctx, &preemptible, sizeof(preemptible)); +} + +static +void preemptible_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, + union lttng_ctx_value *value) +{ + int pc = preempt_count(); + + WARN_ON_ONCE(pc < LTTNG_PREEMPT_DISABLE_NESTING); + if (pc == LTTNG_PREEMPT_DISABLE_NESTING) + value->s64 = 1; + else + value->s64 = 0; +} + +int lttng_add_preemptible_to_ctx(struct lttng_ctx **ctx) +{ + struct lttng_ctx_field *field; + + field = lttng_append_context(ctx); + if (!field) + return -ENOMEM; + if (lttng_find_context(*ctx, "preemptible")) { + lttng_remove_context_field(ctx, field); + return -EEXIST; + } + field->event_field.name = "preemptible"; + field->event_field.type.atype = atype_integer; + field->event_field.type.u.basic.integer.size = sizeof(uint8_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.alignment = lttng_alignof(uint8_t) * CHAR_BIT; + field->event_field.type.u.basic.integer.signedness = lttng_is_signed_type(uint8_t); + field->event_field.type.u.basic.integer.reverse_byte_order = 0; + field->event_field.type.u.basic.integer.base = 10; + field->event_field.type.u.basic.integer.encoding = lttng_encode_none; + field->get_size = preemptible_get_size; + field->record = preemptible_record; + field->get_value = preemptible_get_value; + lttng_context_update(*ctx); + wrapper_vmalloc_sync_all(); + return 0; +} +EXPORT_SYMBOL_GPL(lttng_add_preemptible_to_ctx); + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Mathieu Desnoyers"); +MODULE_DESCRIPTION("Linux Trace Toolkit preemptible Context"); +MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "." + __stringify(LTTNG_MODULES_MINOR_VERSION) "." + __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION) + LTTNG_MODULES_EXTRAVERSION); diff --git a/lttng-context-prio.c b/lttng-context-prio.c index d9fb6f31..9da51a22 100644 --- a/lttng-context-prio.c +++ b/lttng-context-prio.c @@ -66,6 +66,7 @@ void prio_record(struct lttng_ctx_field *field, static void prio_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { value->s64 = wrapper_task_prio_sym(current); diff --git a/lttng-context-procname.c b/lttng-context-procname.c index 5c1cd3a6..8a747acd 100644 --- a/lttng-context-procname.c +++ b/lttng-context-procname.c @@ -53,6 +53,7 @@ void procname_record(struct lttng_ctx_field *field, static void procname_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { value->str = current->comm; diff --git a/lttng-context-tid.c b/lttng-context-tid.c index 7b8e04be..12862659 100644 --- a/lttng-context-tid.c +++ b/lttng-context-tid.c @@ -52,6 +52,7 @@ void tid_record(struct lttng_ctx_field *field, static void tid_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { pid_t tid; diff --git a/lttng-context-vpid.c b/lttng-context-vpid.c index 9a8df9a9..6fa1c00d 100644 --- a/lttng-context-vpid.c +++ b/lttng-context-vpid.c @@ -58,6 +58,7 @@ void vpid_record(struct lttng_ctx_field *field, static void vpid_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { pid_t vpid; diff --git a/lttng-context-vppid.c b/lttng-context-vppid.c index 9f36375d..8a7d172f 100644 --- a/lttng-context-vppid.c +++ b/lttng-context-vppid.c @@ -73,6 +73,7 @@ void vppid_record(struct lttng_ctx_field *field, static void vppid_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { struct task_struct *parent; diff --git a/lttng-context-vtid.c b/lttng-context-vtid.c index a264424f..a37bb767 100644 --- a/lttng-context-vtid.c +++ b/lttng-context-vtid.c @@ -58,6 +58,7 @@ void vtid_record(struct lttng_ctx_field *field, static void vtid_get_value(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value) { pid_t vtid; diff --git a/lttng-context.c b/lttng-context.c index eca58ce1..9bf4d800 100644 --- a/lttng-context.c +++ b/lttng-context.c @@ -268,6 +268,26 @@ int lttng_context_init(void) if (ret) { printk(KERN_WARNING "Cannot add context lttng_add_cpu_id_to_ctx"); } + ret = lttng_add_interruptible_to_ctx(<tng_static_ctx); + if (ret) { + printk(KERN_WARNING "Cannot add context lttng_add_interruptible_to_ctx"); + } + ret = lttng_add_need_reschedule_to_ctx(<tng_static_ctx); + if (ret) { + printk(KERN_WARNING "Cannot add context lttng_add_need_reschedule_to_ctx"); + } +#if defined(CONFIG_PREEMPT_RT_FULL) || defined(CONFIG_PREEMPT) + ret = lttng_add_preemptible_to_ctx(<tng_static_ctx); + if (ret != -ENOSYS) { + printk(KERN_WARNING "Cannot add context lttng_add_preemptible_to_ctx"); + } +#endif +#ifdef CONFIG_PREEMPT_RT_FULL + ret = lttng_add_migratable_to_ctx(<tng_static_ctx); + if (ret != -ENOSYS) { + printk(KERN_WARNING "Cannot add context lttng_add_migratable_to_ctx"); + } +#endif /* TODO: perf counters for filtering */ return 0; } diff --git a/lttng-events.h b/lttng-events.h index 234d4bcb..1b4f39c4 100644 --- a/lttng-events.h +++ b/lttng-events.h @@ -162,6 +162,11 @@ struct lttng_perf_counter_field { struct perf_event **e; /* per-cpu array */ }; +struct lttng_probe_ctx { + struct lttng_event *event; + uint8_t interruptible; +}; + struct lttng_ctx_field { struct lttng_event_field event_field; size_t (*get_size)(size_t offset); @@ -169,6 +174,7 @@ struct lttng_ctx_field { struct lib_ring_buffer_ctx *ctx, struct lttng_channel *chan); void (*get_value)(struct lttng_ctx_field *field, + struct lttng_probe_ctx *lttng_probe_ctx, union lttng_ctx_value *value); union { struct lttng_perf_counter_field *perf_counter; @@ -231,7 +237,8 @@ enum lttng_filter_ret { struct lttng_bytecode_runtime { /* Associated bytecode */ struct lttng_filter_bytecode_node *bc; - uint64_t (*filter)(void *filter_data, const char *filter_stack_data); + uint64_t (*filter)(void *filter_data, struct lttng_probe_ctx *lttng_probe_ctx, + const char *filter_stack_data); int link_failed; struct list_head node; /* list of bytecode runtime in event */ }; @@ -630,6 +637,26 @@ int lttng_add_vtid_to_ctx(struct lttng_ctx **ctx); int lttng_add_ppid_to_ctx(struct lttng_ctx **ctx); int lttng_add_vppid_to_ctx(struct lttng_ctx **ctx); int lttng_add_hostname_to_ctx(struct lttng_ctx **ctx); +int lttng_add_interruptible_to_ctx(struct lttng_ctx **ctx); +int lttng_add_need_reschedule_to_ctx(struct lttng_ctx **ctx); +#if defined(CONFIG_PREEMPT_RT_FULL) || defined(CONFIG_PREEMPT) +int lttng_add_preemptible_to_ctx(struct lttng_ctx **ctx); +#else +static inline +int lttng_add_preemptible_to_ctx(struct lttng_ctx **ctx) +{ + return -ENOSYS; +} +#endif +#ifdef CONFIG_PREEMPT_RT_FULL +int lttng_add_migratable_to_ctx(struct lttng_ctx **ctx); +#else +static inline +int lttng_add_migratable_to_ctx(struct lttng_ctx **ctx) +{ + return -ENOSYS; +} +#endif #if defined(CONFIG_PERF_EVENTS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) int lttng_add_perf_counter_to_ctx(uint32_t type, uint64_t config, diff --git a/lttng-filter-interpreter.c b/lttng-filter-interpreter.c index ffce2150..c288cc02 100644 --- a/lttng-filter-interpreter.c +++ b/lttng-filter-interpreter.c @@ -183,6 +183,7 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) } uint64_t lttng_filter_false(void *filter_data, + struct lttng_probe_ctx *lttng_probe_ctx, const char *filter_stack_data) { return 0; @@ -240,6 +241,7 @@ LABEL_##name * effect. */ uint64_t lttng_filter_interpret_bytecode(void *filter_data, + struct lttng_probe_ctx *lttng_probe_ctx, const char *filter_stack_data) { struct bytecode_runtime *bytecode = filter_data; @@ -766,7 +768,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("get context ref offset %u type string\n", ref->offset); ctx_field = <tng_static_ctx->fields[ref->offset]; - ctx_field->get_value(ctx_field, &v); + ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); estack_push(stack, top, ax, bx); estack_ax(stack, top)->u.s.str = v.str; if (unlikely(!estack_ax(stack, top)->u.s.str)) { @@ -792,7 +794,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("get context ref offset %u type s64\n", ref->offset); ctx_field = <tng_static_ctx->fields[ref->offset]; - ctx_field->get_value(ctx_field, &v); + ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); estack_push(stack, top, ax, bx); estack_ax_v = v.s64; dbg_printk("ref get context s64 %lld\n", diff --git a/lttng-filter.h b/lttng-filter.h index 7eea1487..a1bf79b9 100644 --- a/lttng-filter.h +++ b/lttng-filter.h @@ -171,8 +171,10 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode); int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode); uint64_t lttng_filter_false(void *filter_data, + struct lttng_probe_ctx *lttng_probe_ctx, const char *filter_stack_data); uint64_t lttng_filter_interpret_bytecode(void *filter_data, + struct lttng_probe_ctx *lttng_probe_ctx, const char *filter_stack_data); #endif /* _LTTNG_FILTER_H */ diff --git a/lttng-ring-buffer-client.h b/lttng-ring-buffer-client.h index e882f493..d57dda19 100644 --- a/lttng-ring-buffer-client.h +++ b/lttng-ring-buffer-client.h @@ -130,7 +130,8 @@ size_t record_header_size(const struct lib_ring_buffer_config *config, struct lib_ring_buffer_ctx *ctx) { struct lttng_channel *lttng_chan = channel_get_private(chan); - struct lttng_event *event = ctx->priv; + struct lttng_probe_ctx *lttng_probe_ctx = ctx->priv; + struct lttng_event *event = lttng_probe_ctx->event; size_t orig_offset = offset; size_t padding; @@ -198,7 +199,8 @@ void lttng_write_event_header(const struct lib_ring_buffer_config *config, uint32_t event_id) { struct lttng_channel *lttng_chan = channel_get_private(ctx->chan); - struct lttng_event *event = ctx->priv; + struct lttng_probe_ctx *lttng_probe_ctx = ctx->priv; + struct lttng_event *event = lttng_probe_ctx->event; if (unlikely(ctx->rflags)) goto slow_path; @@ -249,7 +251,8 @@ void lttng_write_event_header_slow(const struct lib_ring_buffer_config *config, uint32_t event_id) { struct lttng_channel *lttng_chan = channel_get_private(ctx->chan); - struct lttng_event *event = ctx->priv; + struct lttng_probe_ctx *lttng_probe_ctx = ctx->priv; + struct lttng_event *event = lttng_probe_ctx->event; switch (lttng_chan->header_type) { case 1: /* compact */ diff --git a/probes/lttng-events.h b/probes/lttng-events.h index 0e3b713b..6d8c7113 100644 --- a/probes/lttng-events.h +++ b/probes/lttng-events.h @@ -903,6 +903,10 @@ static void __event_probe__##_name(void *__data, _proto) \ { \ struct probe_local_vars { _locvar }; \ struct lttng_event *__event = __data; \ + struct lttng_probe_ctx __lttng_probe_ctx = { \ + .event = __event, \ + .interruptible = irqs_disabled(), \ + }; \ struct lttng_channel *__chan = __event->chan; \ struct lttng_session *__session = __chan->session; \ struct lib_ring_buffer_ctx __ctx; \ @@ -937,7 +941,7 @@ static void __event_probe__##_name(void *__data, _proto) \ __event_prepare_filter_stack__##_name(__stackvar.__filter_stack_data, \ tp_locvar, _args); \ lttng_list_for_each_entry_rcu(bc_runtime, &__event->bytecode_runtime_head, node) { \ - if (unlikely(bc_runtime->filter(bc_runtime, \ + if (unlikely(bc_runtime->filter(bc_runtime, &__lttng_probe_ctx, \ __stackvar.__filter_stack_data) & LTTNG_FILTER_RECORD_FLAG)) \ __filter_record = 1; \ } \ @@ -947,7 +951,7 @@ static void __event_probe__##_name(void *__data, _proto) \ __event_len = __event_get_size__##_name(__stackvar.__dynamic_len, \ tp_locvar, _args); \ __event_align = __event_get_align__##_name(tp_locvar, _args); \ - lib_ring_buffer_ctx_init(&__ctx, __chan->chan, __event, __event_len, \ + lib_ring_buffer_ctx_init(&__ctx, __chan->chan, &__lttng_probe_ctx, __event_len, \ __event_align, -1); \ __ret = __chan->ops->event_reserve(&__ctx, __event->id); \ if (__ret < 0) \ @@ -965,6 +969,10 @@ static void __event_probe__##_name(void *__data) \ { \ struct probe_local_vars { _locvar }; \ struct lttng_event *__event = __data; \ + struct lttng_probe_ctx __lttng_probe_ctx = { \ + .event = __event, \ + .interruptible = irqs_disabled(), \ + }; \ struct lttng_channel *__chan = __event->chan; \ struct lttng_session *__session = __chan->session; \ struct lib_ring_buffer_ctx __ctx; \ @@ -999,7 +1007,7 @@ static void __event_probe__##_name(void *__data) \ __event_prepare_filter_stack__##_name(__stackvar.__filter_stack_data, \ tp_locvar); \ lttng_list_for_each_entry_rcu(bc_runtime, &__event->bytecode_runtime_head, node) { \ - if (unlikely(bc_runtime->filter(bc_runtime, \ + if (unlikely(bc_runtime->filter(bc_runtime, &__lttng_probe_ctx, \ __stackvar.__filter_stack_data) & LTTNG_FILTER_RECORD_FLAG)) \ __filter_record = 1; \ } \ @@ -1008,7 +1016,7 @@ static void __event_probe__##_name(void *__data) \ } \ __event_len = __event_get_size__##_name(__stackvar.__dynamic_len, tp_locvar); \ __event_align = __event_get_align__##_name(tp_locvar); \ - lib_ring_buffer_ctx_init(&__ctx, __chan->chan, __event, __event_len, \ + lib_ring_buffer_ctx_init(&__ctx, __chan->chan, &__lttng_probe_ctx, __event_len, \ __event_align, -1); \ __ret = __chan->ops->event_reserve(&__ctx, __event->id); \ if (__ret < 0) \ diff --git a/probes/lttng-ftrace.c b/probes/lttng-ftrace.c index bc4bd5ba..090843c9 100644 --- a/probes/lttng-ftrace.c +++ b/probes/lttng-ftrace.c @@ -43,6 +43,10 @@ static void lttng_ftrace_handler(unsigned long ip, unsigned long parent_ip, void **data) { struct lttng_event *event = *data; + struct lttng_probe_ctx lttng_probe_ctx = { + .event = event, + .interruptible = irqs_disabled(), + }; struct lttng_channel *chan = event->chan; struct lib_ring_buffer_ctx ctx; struct { @@ -58,7 +62,7 @@ void lttng_ftrace_handler(unsigned long ip, unsigned long parent_ip, void **data if (unlikely(!ACCESS_ONCE(event->enabled))) return; - lib_ring_buffer_ctx_init(&ctx, chan->chan, event, + lib_ring_buffer_ctx_init(&ctx, chan->chan, <tng_probe_ctx, sizeof(payload), lttng_alignof(payload), -1); ret = chan->ops->event_reserve(&ctx, event->id); if (ret < 0) diff --git a/probes/lttng-kprobes.c b/probes/lttng-kprobes.c index 742af678..f4e4f2ea 100644 --- a/probes/lttng-kprobes.c +++ b/probes/lttng-kprobes.c @@ -26,6 +26,7 @@ #include "../lttng-events.h" #include "../wrapper/ringbuffer/frontend_types.h" #include "../wrapper/vmalloc.h" +#include "../wrapper/irqflags.h" #include "../lttng-tracer.h" static @@ -33,6 +34,10 @@ int lttng_kprobes_handler_pre(struct kprobe *p, struct pt_regs *regs) { struct lttng_event *event = container_of(p, struct lttng_event, u.kprobe.kp); + struct lttng_probe_ctx lttng_probe_ctx = { + .event = event, + .interruptible = lttng_regs_irqs_disabled(regs), + }; struct lttng_channel *chan = event->chan; struct lib_ring_buffer_ctx ctx; int ret; @@ -45,7 +50,7 @@ int lttng_kprobes_handler_pre(struct kprobe *p, struct pt_regs *regs) if (unlikely(!ACCESS_ONCE(event->enabled))) return 0; - lib_ring_buffer_ctx_init(&ctx, chan->chan, event, sizeof(data), + lib_ring_buffer_ctx_init(&ctx, chan->chan, <tng_probe_ctx, sizeof(data), lttng_alignof(data), -1); ret = chan->ops->event_reserve(&ctx, event->id); if (ret < 0) diff --git a/probes/lttng-kretprobes.c b/probes/lttng-kretprobes.c index 52b3f781..eb3f6857 100644 --- a/probes/lttng-kretprobes.c +++ b/probes/lttng-kretprobes.c @@ -27,6 +27,7 @@ #include "../lttng-events.h" #include "../wrapper/ringbuffer/frontend_types.h" #include "../wrapper/vmalloc.h" +#include "../wrapper/irqflags.h" #include "../lttng-tracer.h" enum lttng_kretprobe_type { @@ -50,6 +51,10 @@ int _lttng_kretprobes_handler(struct kretprobe_instance *krpi, container_of(krpi->rp, struct lttng_krp, krp); struct lttng_event *event = lttng_krp->event[type]; + struct lttng_probe_ctx lttng_probe_ctx = { + .event = event, + .interruptible = lttng_regs_irqs_disabled(regs), + }; struct lttng_channel *chan = event->chan; struct lib_ring_buffer_ctx ctx; int ret; @@ -68,7 +73,7 @@ int _lttng_kretprobes_handler(struct kretprobe_instance *krpi, payload.ip = (unsigned long) krpi->rp->kp.addr; payload.parent_ip = (unsigned long) krpi->ret_addr; - lib_ring_buffer_ctx_init(&ctx, chan->chan, event, sizeof(payload), + lib_ring_buffer_ctx_init(&ctx, chan->chan, <tng_probe_ctx, sizeof(payload), lttng_alignof(payload), -1); ret = chan->ops->event_reserve(&ctx, event->id); if (ret < 0) diff --git a/wrapper/irqflags.h b/wrapper/irqflags.h new file mode 100644 index 00000000..77f83829 --- /dev/null +++ b/wrapper/irqflags.h @@ -0,0 +1,53 @@ +#ifndef _LTTNG_WRAPPER_IRQFLAGS_H +#define _LTTNG_WRAPPER_IRQFLAGS_H + +/* + * wrapper/irqflags.h + * + * wrapper around IRQ flags. + * + * Copyright (C) 2015 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#ifdef CONFIG_X86 + +static inline +int lttng_regs_irqs_disabled(struct pt_regs *regs) +{ + unsigned long flags = regs->flags; + + return arch_irqs_disabled_flags(flags); +} + +#else +/* + * lttng_regs_irqs_disabled() returns -1 if irqoff state is unknown. + * TODO: should implement lttng_regs_irqs_disabled for each architecture + * to add interruptible context for kprobes and kretprobes. + */ + +static inline +int lttng_regs_irqs_disabled(struct pt_regs *regs) +{ + return -1; +} +#endif + +#endif /* _LTTNG_WRAPPER_IRQFLAGS_H */