Implement detailed syscall event probe
[lttng-modules.git] / ltt-events.c
index 40e8e459183efacae2744fcc6a6071bd9625e5b1..f9688f549be3bee9f105dd87b29130ef2839431d 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
-#include <linux/uuid.h>
+#include "wrapper/uuid.h"
 #include "wrapper/vmalloc.h"   /* for wrapper_vmalloc_sync_all() */
 #include "ltt-events.h"
 #include "ltt-tracer.h"
@@ -34,8 +34,6 @@ int _ltt_event_metadata_statedump(struct ltt_session *session,
 static
 int _ltt_session_metadata_statedump(struct ltt_session *session);
 
-
-static
 void synchronize_trace(void)
 {
        synchronize_sched();
@@ -68,6 +66,10 @@ void ltt_session_destroy(struct ltt_session *session)
 
        mutex_lock(&sessions_mutex);
        ACCESS_ONCE(session->active) = 0;
+       list_for_each_entry(chan, &session->chan, list) {
+               ret = lttng_syscalls_unregister(chan);
+               WARN_ON(ret);
+       }
        list_for_each_entry(event, &session->events, list) {
                ret = _ltt_event_unregister(event);
                WARN_ON(ret);
@@ -82,7 +84,7 @@ void ltt_session_destroy(struct ltt_session *session)
        kfree(session);
 }
 
-int ltt_session_start(struct ltt_session *session)
+int ltt_session_enable(struct ltt_session *session)
 {
        int ret = 0;
        struct ltt_channel *chan;
@@ -108,18 +110,15 @@ int ltt_session_start(struct ltt_session *session)
 
        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) {
+       if (ret)
                ACCESS_ONCE(session->active) = 0;
-               synchronize_trace();    /* Wait for in-flight events to complete */
-       }
 end:
        mutex_unlock(&sessions_mutex);
        return ret;
 }
 
-int ltt_session_stop(struct ltt_session *session)
+int ltt_session_disable(struct ltt_session *session)
 {
        int ret = 0;
 
@@ -129,12 +128,59 @@ int ltt_session_stop(struct ltt_session *session)
                goto end;
        }
        ACCESS_ONCE(session->active) = 0;
-       synchronize_trace();    /* Wait for in-flight events to complete */
 end:
        mutex_unlock(&sessions_mutex);
        return ret;
 }
 
+int ltt_channel_enable(struct ltt_channel *channel)
+{
+       int old;
+
+       if (channel == channel->session->metadata)
+               return -EPERM;
+       old = xchg(&channel->enabled, 1);
+       if (old)
+               return -EEXIST;
+       return 0;
+}
+
+int ltt_channel_disable(struct ltt_channel *channel)
+{
+       int old;
+
+       if (channel == channel->session->metadata)
+               return -EPERM;
+       old = xchg(&channel->enabled, 0);
+       if (!old)
+               return -EEXIST;
+       return 0;
+}
+
+int ltt_event_enable(struct ltt_event *event)
+{
+       int old;
+
+       if (event->chan == event->chan->session->metadata)
+               return -EPERM;
+       old = xchg(&event->enabled, 1);
+       if (old)
+               return -EEXIST;
+       return 0;
+}
+
+int ltt_event_disable(struct ltt_event *event)
+{
+       int old;
+
+       if (event->chan == event->chan->session->metadata)
+               return -EPERM;
+       old = xchg(&event->enabled, 0);
+       if (!old)
+               return -EEXIST;
+       return 0;
+}
+
 static struct ltt_transport *ltt_transport_find(const char *name)
 {
        struct ltt_transport *transport;
@@ -154,7 +200,7 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session,
                                       unsigned int read_timer_interval)
 {
        struct ltt_channel *chan;
-       struct ltt_transport *transport;
+       struct ltt_transport *transport = NULL;
 
        mutex_lock(&sessions_mutex);
        if (session->been_active)
@@ -165,6 +211,10 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session,
                       transport_name);
                goto notransport;
        }
+       if (!try_module_get(transport->owner)) {
+               printk(KERN_WARNING "LTT : Can't lock transport module.\n");
+               goto notransport;
+       }
        chan = kzalloc(sizeof(struct ltt_channel), GFP_KERNEL);
        if (!chan)
                goto nomem;
@@ -180,7 +230,9 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session,
                        read_timer_interval);
        if (!chan->chan)
                goto create_error;
+       chan->enabled = 1;
        chan->ops = &transport->ops;
+       chan->transport = transport;
        list_add(&chan->list, &session->chan);
        mutex_unlock(&sessions_mutex);
        return chan;
@@ -188,6 +240,8 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session,
 create_error:
        kfree(chan);
 nomem:
+       if (transport)
+               module_put(transport->owner);
 notransport:
 active:
        mutex_unlock(&sessions_mutex);
@@ -201,6 +255,7 @@ static
 void _ltt_channel_destroy(struct ltt_channel *chan)
 {
        chan->ops->channel_destroy(chan->chan);
+       module_put(chan->transport->owner);
        list_del(&chan->list);
        lttng_destroy_context(chan->ctx);
        kfree(chan);
@@ -232,6 +287,7 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan,
        event->chan = chan;
        event->filter = filter;
        event->id = chan->free_event_id++;
+       event->enabled = 1;
        event->instrumentation = event_param->instrumentation;
        /* Populate ltt_event structure before tracepoint registration. */
        smp_wmb();
@@ -257,6 +313,49 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan,
                ret = try_module_get(event->desc->owner);
                WARN_ON_ONCE(!ret);
                break;
+       case LTTNG_KERNEL_KRETPROBE:
+       {
+               struct ltt_event *event_return;
+
+               /* kretprobe defines 2 events */
+               event_return =
+                       kmem_cache_zalloc(event_cache, GFP_KERNEL);
+               if (!event_return)
+                       goto register_error;
+               event_return->chan = chan;
+               event_return->filter = filter;
+               event_return->id = chan->free_event_id++;
+               event_return->enabled = 1;
+               event_return->instrumentation = event_param->instrumentation;
+               /*
+                * Populate ltt_event structure before kretprobe registration.
+                */
+               smp_wmb();
+               ret = lttng_kretprobes_register(event_param->name,
+                               event_param->u.kretprobe.symbol_name,
+                               event_param->u.kretprobe.offset,
+                               event_param->u.kretprobe.addr,
+                               event, event_return);
+               if (ret) {
+                       kmem_cache_free(event_cache, event_return);
+                       goto register_error;
+               }
+               /* Take 2 refs on the module: one per event. */
+               ret = try_module_get(event->desc->owner);
+               WARN_ON_ONCE(!ret);
+               ret = try_module_get(event->desc->owner);
+               WARN_ON_ONCE(!ret);
+               ret = _ltt_event_metadata_statedump(chan->session, chan,
+                                                   event_return);
+               if (ret) {
+                       kmem_cache_free(event_cache, event_return);
+                       module_put(event->desc->owner);
+                       module_put(event->desc->owner);
+                       goto statedump_error;
+               }
+               list_add(&event_return->list, &chan->session->events);
+               break;
+       }
        case LTTNG_KERNEL_FUNCTION:
                ret = lttng_ftrace_register(event_param->name,
                                event_param->u.ftrace.symbol_name,
@@ -266,6 +365,8 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan,
                ret = try_module_get(event->desc->owner);
                WARN_ON_ONCE(!ret);
                break;
+       case LTTNG_KERNEL_NOOP:
+               break;
        default:
                WARN_ON_ONCE(1);
        }
@@ -309,6 +410,10 @@ int _ltt_event_unregister(struct ltt_event *event)
                lttng_kprobes_unregister(event);
                ret = 0;
                break;
+       case LTTNG_KERNEL_KRETPROBE:
+               lttng_kretprobes_unregister(event);
+               ret = 0;
+               break;
        case LTTNG_KERNEL_FUNCTION:
                lttng_ftrace_unregister(event);
                ret = 0;
@@ -333,6 +438,10 @@ void _ltt_event_destroy(struct ltt_event *event)
                module_put(event->desc->owner);
                lttng_kprobes_destroy_private(event);
                break;
+       case LTTNG_KERNEL_KRETPROBE:
+               module_put(event->desc->owner);
+               lttng_kretprobes_destroy_private(event);
+               break;
        case LTTNG_KERNEL_FUNCTION:
                module_put(event->desc->owner);
                lttng_ftrace_destroy_private(event);
@@ -384,7 +493,7 @@ int lttng_metadata_printf(struct ltt_session *session,
                 * we need to bail out after timeout or being
                 * interrupted.
                 */
-               waitret = wait_event_interruptible_timeout(*chan->ops->get_reader_wait_queue(chan->chan),
+               waitret = wait_event_interruptible_timeout(*chan->ops->get_writer_buf_wait_queue(chan->chan, -1),
                        ({
                                ret = chan->ops->event_reserve(&ctx, 0);
                                ret != -ENOBUFS || !ret;
This page took 0.026617 seconds and 4 git commands to generate.