Implement kernel filter support
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 11 Nov 2014 21:31:40 +0000 (16:31 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Tue, 11 Nov 2014 21:31:40 +0000 (16:31 -0500)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
15 files changed:
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/event.c
src/bin/lttng-sessiond/event.h
src/bin/lttng-sessiond/kernel.c
src/bin/lttng-sessiond/kernel.h
src/bin/lttng-sessiond/save.c
src/bin/lttng-sessiond/trace-kernel.c
src/bin/lttng-sessiond/trace-kernel.h
src/bin/lttng/commands/enable_events.c
src/common/kernel-ctl/kernel-ctl.c
src/common/kernel-ctl/kernel-ctl.h
src/common/kernel-ctl/kernel-ioctl.h
src/common/lttng-kernel.h
src/lib/lttng-ctl/filter/filter-bytecode.h
tests/unit/test_kernel_data.c

index 7eea28121e3e55394c67fc96ad484d4574b5f4da..95e371d7b66fe527da607a7c60d0c49b871a2e63 100644 (file)
@@ -1485,18 +1485,48 @@ int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
                switch (event->type) {
                case LTTNG_EVENT_ALL:
                {
+                       char *filter_expression_a = NULL;
+                       struct lttng_filter_bytecode *filter_a = NULL;
+
+                       /*
+                        * We need to duplicate filter_expression and filter,
+                        * because ownership is passed to first enable
+                        * event.
+                        */
+                       if (filter_expression) {
+                               filter_expression_a = strdup(filter_expression);
+                               if (!filter_expression_a) {
+                                       ret = LTTNG_ERR_FATAL;
+                                       goto error;
+                               }
+                       }
+                       if (filter) {
+                               filter_a = zmalloc(sizeof(*filter_a) + filter->len);
+                               if (!filter_a) {
+                                       free(filter_expression_a);
+                                       ret = LTTNG_ERR_FATAL;
+                                       goto error;
+                               }
+                               memcpy(filter_a, filter, sizeof(*filter_a) + filter->len);
+                       }
                        event->type = LTTNG_EVENT_TRACEPOINT;   /* Hack */
-                       ret = event_kernel_enable_event(kchan, event);
+                       ret = event_kernel_enable_event(kchan, event,
+                               filter_expression, filter);
                        if (ret != LTTNG_OK) {
                                if (channel_created) {
                                        /* Let's not leak a useless channel. */
                                        kernel_destroy_channel(kchan);
                                }
+                               free(filter_expression_a);
+                               free(filter_a);
                                goto error;
                        }
                        event->type = LTTNG_EVENT_SYSCALL;      /* Hack */
-                       ret = event_kernel_enable_event(kchan, event);
+                       ret = event_kernel_enable_event(kchan, event,
+                               filter_expression_a, filter_a);
                        if (ret != LTTNG_OK) {
+                               free(filter_expression_a);
+                               free(filter_a);
                                goto error;
                        }
                        break;
@@ -1505,7 +1535,8 @@ int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
                case LTTNG_EVENT_FUNCTION:
                case LTTNG_EVENT_FUNCTION_ENTRY:
                case LTTNG_EVENT_TRACEPOINT:
-                       ret = event_kernel_enable_event(kchan, event);
+                       ret = event_kernel_enable_event(kchan, event,
+                               filter_expression, filter);
                        if (ret != LTTNG_OK) {
                                if (channel_created) {
                                        /* Let's not leak a useless channel. */
@@ -1515,7 +1546,8 @@ int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
                        }
                        break;
                case LTTNG_EVENT_SYSCALL:
-                       ret = event_kernel_enable_event(kchan, event);
+                       ret = event_kernel_enable_event(kchan, event,
+                               filter_expression, filter);
                        if (ret != LTTNG_OK) {
                                goto error;
                        }
index 0efdc9253d59adc98da8508c8909b9a6d9e58f06..32efcdbf210ee5d5a2b5d99cdfcf2a2a2f1e4279 100644 (file)
@@ -129,7 +129,8 @@ int event_kernel_disable_event_all(struct ltt_kernel_channel *kchan)
  * We own filter_expression and filter.
  */
 int event_kernel_enable_event(struct ltt_kernel_channel *kchan,
-               struct lttng_event *event)
+               struct lttng_event *event, char *filter_expression,
+               struct lttng_filter_bytecode *filter)
 {
        int ret;
        struct ltt_kernel_event *kevent;
@@ -137,10 +138,11 @@ int event_kernel_enable_event(struct ltt_kernel_channel *kchan,
        assert(kchan);
        assert(event);
 
-       kevent = trace_kernel_get_event_by_name(event->name, kchan,
-                       event->type);
+       kevent = trace_kernel_find_event(event->name, kchan,
+                       event->type, filter);
        if (kevent == NULL) {
-               ret = kernel_create_event(event, kchan);
+               ret = kernel_create_event(event, kchan,
+                       filter_expression, filter);
                if (ret < 0) {
                        switch (-ret) {
                        case EEXIST:
index 536b2be707d05dd4feb6483575109db718d8faf2..cc4a3fa02e0d3f79b5ec52733828aaa35397f0a0 100644 (file)
@@ -28,7 +28,8 @@ int event_kernel_disable_event_type(struct ltt_kernel_channel *kchan,
 int event_kernel_disable_event_all(struct ltt_kernel_channel *kchan);
 
 int event_kernel_enable_event(struct ltt_kernel_channel *kchan,
-               struct lttng_event *event);
+               struct lttng_event *event, char *filter_expression,
+               struct lttng_filter_bytecode *filter);
 
 int event_ust_enable_tracepoint(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan, struct lttng_event *event,
index bf9f8b623288eb2e7eb58652bb5f26493ecf399e..45d958546f2cae75d938a8960af3c3fd5690be64 100644 (file)
@@ -177,7 +177,9 @@ error:
  * We own filter_expression and filter.
  */
 int kernel_create_event(struct lttng_event *ev,
-               struct ltt_kernel_channel *channel)
+               struct ltt_kernel_channel *channel,
+               char *filter_expression,
+               struct lttng_filter_bytecode *filter)
 {
        int ret;
        struct ltt_kernel_event *event;
@@ -185,7 +187,8 @@ int kernel_create_event(struct lttng_event *ev,
        assert(ev);
        assert(channel);
 
-       event = trace_kernel_create_event(ev);
+       event = trace_kernel_create_event(ev, filter_expression,
+                       filter);
        if (event == NULL) {
                ret = -1;
                goto error;
@@ -217,6 +220,26 @@ int kernel_create_event(struct lttng_event *ev,
                PERROR("fcntl session fd");
        }
 
+       if (filter) {
+               ret = kernctl_filter(event->fd, filter);
+               if (ret) {
+                       goto filter_error;
+               }
+       }
+
+       ret = kernctl_enable(event->fd);
+       if (ret < 0) {
+               switch (errno) {
+               case EEXIST:
+                       ret = LTTNG_ERR_KERN_EVENT_EXIST;
+                       break;
+               default:
+                       PERROR("enable kernel event");
+                       break;
+               }
+               goto enable_error;
+       }
+
        /* Add event to event list */
        cds_list_add(&event->list, &channel->events_list.head);
        channel->event_count++;
@@ -225,6 +248,16 @@ int kernel_create_event(struct lttng_event *ev,
 
        return 0;
 
+enable_error:
+filter_error:
+       {
+               int closeret;
+
+               closeret = close(event->fd);
+               if (closeret) {
+                       PERROR("close event fd");
+               }
+       }
 free_event:
        free(event);
 error:
index 2f7cc15fb285c8b1316949ec0929075e434e6c6e..2a9a76f92337dec6e07e67e9b3bc73ec54682426 100644 (file)
@@ -37,7 +37,8 @@ int kernel_add_channel_context(struct ltt_kernel_channel *chan,
 int kernel_create_session(struct ltt_session *session, int tracer_fd);
 int kernel_create_channel(struct ltt_kernel_session *session,
                struct lttng_channel *chan);
-int kernel_create_event(struct lttng_event *ev, struct ltt_kernel_channel *channel);
+int kernel_create_event(struct lttng_event *ev, struct ltt_kernel_channel *channel,
+               char *filter_expression, struct lttng_filter_bytecode *filter);
 int kernel_disable_channel(struct ltt_kernel_channel *chan);
 int kernel_disable_event(struct ltt_kernel_event *event);
 int kernel_enable_event(struct ltt_kernel_event *event);
index 6cb220c2f28d1e56bffeef8dbf49a68d4cd6d516..0c6894b0a91507125cc5f3310fb486af9aa3b52a 100644 (file)
@@ -510,7 +510,13 @@ int save_kernel_syscall(struct config_writer *writer,
                struct ltt_kernel_event *kevent;
 
                /* Create a temporary kevent in order to save it. */
-               kevent = trace_kernel_create_event(&events[i]);
+               /*
+                * TODO: struct lttng_event does not really work for a filter,
+                * but unfortunately, it is exposed as external API (and used as
+                * internal representation. Using NULL meanwhile.
+                */
+               kevent = trace_kernel_create_event(&events[i],
+                       NULL, NULL);
                if (!kevent) {
                        ret = -ENOMEM;
                        goto end;
index ab3282a17f189b9c7b288fab65a5dd224f38fe2b..33a9e7e5578daf8454e5ccc97bc3d97d85e7934f 100644 (file)
@@ -58,6 +58,49 @@ struct ltt_kernel_channel *trace_kernel_get_channel_by_name(
        return NULL;
 }
 
+/*
+ * Find the event for the given channel.
+ */
+struct ltt_kernel_event *trace_kernel_find_event(
+               char *name, struct ltt_kernel_channel *channel,
+               enum lttng_event_type type,
+               struct lttng_filter_bytecode *filter)
+{
+       struct ltt_kernel_event *ev;
+       int found = 0;
+
+       assert(name);
+       assert(channel);
+
+       cds_list_for_each_entry(ev, &channel->events_list.head, list) {
+               if (type != LTTNG_EVENT_ALL && ev->type != type) {
+                       continue;
+               }
+               if (strcmp(name, ev->event->name)) {
+                       continue;
+               }
+               if ((ev->filter && !filter) || (!ev->filter && filter)) {
+                       continue;
+               }
+               if (ev->filter && filter) {
+                       if (ev->filter->len != filter->len ||
+                                       memcmp(ev->filter->data, filter->data,
+                                               filter->len) != 0) {
+                               continue;
+                       }
+               }
+               found = 1;
+               break;
+       }
+       if (found) {
+               DBG("Found event %s for channel %s", name,
+                       channel->channel->name);
+               return ev;
+       } else {
+               return NULL;
+       }
+}
+
 /*
  * Find the event name for the given channel.
  */
@@ -66,21 +109,28 @@ struct ltt_kernel_event *trace_kernel_get_event_by_name(
                enum lttng_event_type type)
 {
        struct ltt_kernel_event *ev;
+       int found = 0;
 
        assert(name);
        assert(channel);
 
        cds_list_for_each_entry(ev, &channel->events_list.head, list) {
-               if (type != LTTNG_EVENT_ALL && ev->type != type)
+               if (type != LTTNG_EVENT_ALL && ev->type != type) {
                        continue;
-               if (strcmp(name, ev->event->name) == 0) {
-                       DBG("Found event by name %s for channel %s", name,
-                                       channel->channel->name);
-                       return ev;
                }
+               if (strcmp(name, ev->event->name)) {
+                       continue;
+               }
+               found = 1;
+               break;
+       }
+       if (found) {
+               DBG("Found event %s for channel %s", name,
+                       channel->channel->name);
+               return ev;
+       } else {
+               return NULL;
        }
-
-       return NULL;
 }
 
 /*
@@ -211,7 +261,8 @@ error:
  *
  * Return pointer to structure or NULL.
  */
-struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev)
+struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev,
+               char *filter_expression, struct lttng_filter_bytecode *filter)
 {
        struct ltt_kernel_event *lke;
        struct lttng_kernel_event *attr;
@@ -270,6 +321,8 @@ struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev)
        lke->fd = -1;
        lke->event = attr;
        lke->enabled = 1;
+       lke->filter_expression = filter_expression;
+       lke->filter = filter;
 
        return lke;
 
@@ -401,6 +454,9 @@ void trace_kernel_destroy_event(struct ltt_kernel_event *event)
        /* Remove from event list */
        cds_list_del(&event->list);
 
+       free(event->filter_expression);
+       free(event->filter);
+
        free(event->event);
        free(event);
 }
index 5c518135d0144b71aef0369f8f4527e84d92ebb2..9d50f4c79f86dd40a30f674c6cce8b5a6a35451b 100644 (file)
@@ -54,6 +54,8 @@ struct ltt_kernel_event {
        enum lttng_event_type type;
        struct lttng_kernel_event *event;
        struct cds_list_head list;
+       char *filter_expression;
+       struct lttng_filter_bytecode *filter;
 };
 
 /* Kernel channel */
@@ -125,6 +127,10 @@ struct ltt_kernel_session {
 struct ltt_kernel_event *trace_kernel_get_event_by_name(
                char *name, struct ltt_kernel_channel *channel,
                enum lttng_event_type type);
+struct ltt_kernel_event *trace_kernel_find_event(
+               char *name, struct ltt_kernel_channel *channel,
+               enum lttng_event_type type,
+               struct lttng_filter_bytecode *filter);
 struct ltt_kernel_channel *trace_kernel_get_channel_by_name(
                char *name, struct ltt_kernel_session *session);
 
@@ -134,7 +140,8 @@ struct ltt_kernel_channel *trace_kernel_get_channel_by_name(
 struct ltt_kernel_session *trace_kernel_create_session(void);
 struct ltt_kernel_channel *trace_kernel_create_channel(
                struct lttng_channel *chan);
-struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev);
+struct ltt_kernel_event *trace_kernel_create_event(struct lttng_event *ev,
+               char *filter_expression, struct lttng_filter_bytecode *filter);
 struct ltt_kernel_metadata *trace_kernel_create_metadata(void);
 struct ltt_kernel_stream *trace_kernel_create_stream(const char *name,
                unsigned int count);
index 0de6c8d08b1a55b3dfbb30b484e95de506fed830..ab32994bdd95dc290a03986670c1450060f96445 100644 (file)
@@ -713,11 +713,6 @@ static int enable_events(char *session_name)
        memset(&dom, 0, sizeof(dom));
 
        if (opt_kernel) {
-               if (opt_filter) {
-                       ERR("Filter not implement for kernel tracing yet");
-                       ret = CMD_ERROR;
-                       goto error;
-               }
                if (opt_loglevel) {
                        WARN("Kernel loglevels are not supported.");
                }
index 51d01341338441bc3faffbf5f3d9fb5c52b29486..28ed06cbdaa50b5494c698b296e1bc576cdcfd6c 100644 (file)
@@ -22,6 +22,7 @@
 #include <sys/ioctl.h>
 #include <string.h>
 #include <common/align.h>
+#include <errno.h>
 
 #include "kernel-ctl.h"
 #include "kernel-ioctl.h"
@@ -298,6 +299,25 @@ int kernctl_stop_session(int fd)
                        LTTNG_KERNEL_SESSION_STOP);
 }
 
+int kernctl_filter(int fd, struct lttng_filter_bytecode *filter)
+{
+       struct lttng_kernel_filter_bytecode *kb;
+       uint32_t len;
+       int ret;
+
+       /* Translate bytecode to kernel bytecode */
+       kb = zmalloc(sizeof(*kb) + filter->len);
+       if (!kb)
+               return -ENOMEM;
+       kb->len = len = filter->len;
+       kb->reloc_offset = filter->reloc_table_offset;
+       kb->seqnum = filter->seqnum;
+       memcpy(kb->data, filter->data, len);
+       ret = ioctl(fd, LTTNG_KERNEL_FILTER, kb);
+       free(kb);
+       return ret;
+}
+
 int kernctl_tracepoint_list(int fd)
 {
        return compat_ioctl_no_arg(fd, LTTNG_KERNEL_OLD_TRACEPOINT_LIST,
index d8e69809e97fa22bb51f21adbaf9f0bba91c6e55..b71b28530521273e9f937d1256b98be26a5e0a3f 100644 (file)
@@ -22,6 +22,7 @@
 #include <lttng/lttng.h>
 #include <common/lttng-kernel.h>
 #include <common/lttng-kernel-old.h>
+#include <common/sessiond-comm/sessiond-comm.h>        /* for struct lttng_filter_bytecode */
 
 int kernctl_create_session(int fd);
 int kernctl_open_metadata(int fd, struct lttng_channel_attr *chops);
@@ -35,6 +36,9 @@ int kernctl_disable(int fd);
 int kernctl_start_session(int fd);
 int kernctl_stop_session(int fd);
 
+/* Apply on event FD */
+int kernctl_filter(int fd, struct lttng_filter_bytecode *filter);
+
 int kernctl_tracepoint_list(int fd);
 int kernctl_syscall_list(int fd);
 int kernctl_tracer_version(int fd, struct lttng_kernel_tracer_version *v);
index 671a76972e4f2b388635beb78ba035a620c6d1c7..e469b5fe5bbcc49ed719a0067a4ff96db683038c 100644 (file)
 #define LTTNG_KERNEL_ENABLE                    _IO(0xF6, 0x82)
 #define LTTNG_KERNEL_DISABLE                   _IO(0xF6, 0x83)
 
+/* Event FD ioctl */
+#define LTTNG_KERNEL_FILTER                    _IO(0xF6, 0x90)
+
 #endif /* _LTT_KERNEL_IOCTL_H */
index 8336248427e66b28c84000d6dbe853f868941065..f1144de7f53750499baec8ba3eddd64b0933550c 100644 (file)
@@ -152,4 +152,12 @@ struct lttng_kernel_channel {
        char padding[LTTNG_KERNEL_CHANNEL_PADDING1];
 } LTTNG_PACKED;
 
+#define KERNEL_FILTER_BYTECODE_MAX_LEN         65536
+struct lttng_kernel_filter_bytecode {
+       uint32_t len;
+       uint32_t reloc_offset;
+       uint64_t seqnum;
+       char data[0];
+} LTTNG_PACKED;
+
 #endif /* _LTTNG_KERNEL_H */
index b9991284f636c3c0f82af1e9f7863fedacd2bd74..cdc334555de37daeb5c77d12374f3b7fbc5523c5 100644 (file)
@@ -149,6 +149,10 @@ enum filter_op {
        FILTER_OP_GET_CONTEXT_REF_S64           = 72,
        FILTER_OP_GET_CONTEXT_REF_DOUBLE        = 73,
 
+       /* load userspace field ref */
+       FILTER_OP_LOAD_FIELD_REF_USER_STRING    = 74,
+       FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE  = 75,
+
        NR_FILTER_OPS,
 };
 
index ca53c7d4853195d67aac1bd0ea673b640fb47f6a..603d54cb251333e28bd37e5c62e8cc7009f2d911 100644 (file)
@@ -139,7 +139,7 @@ static void test_create_kernel_event(void)
        ev.type = LTTNG_EVENT_TRACEPOINT;
        ev.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
 
-       event = trace_kernel_create_event(&ev);
+       event = trace_kernel_create_event(&ev, NULL, NULL);
        ok(event != NULL, "Create kernel event");
 
        ok(event->fd == -1 &&
This page took 0.036227 seconds and 4 git commands to generate.