Fix: use lttng hlist wrapper in wildcard and filter
[lttng-modules.git] / lttng-events.c
index d09d4c2e81fa9560da8767863f31f0aca19358aa..65bd0bf9ae6d45c4bbc0395d63211e9642330a59 100644 (file)
@@ -492,7 +492,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan,
        name_len = strlen(event_name);
        hash = jhash(event_name, name_len, 0);
        head = &session->events_ht.table[hash & (LTTNG_EVENT_HT_SIZE - 1)];
-       hlist_for_each_entry(event, head, hlist) {
+       lttng_hlist_for_each_entry(event, head, hlist) {
                WARN_ON_ONCE(!event->desc);
                if (!strncmp(event->desc->name, event_name,
                                        LTTNG_KERNEL_SYM_NAME_LEN - 1)
@@ -512,6 +512,7 @@ struct lttng_event *_lttng_event_create(struct lttng_channel *chan,
        event->id = chan->free_event_id++;
        event->instrumentation = itype;
        event->evtype = LTTNG_TYPE_EVENT;
+       INIT_LIST_HEAD(&event->bytecode_runtime_head);
        INIT_LIST_HEAD(&event->enablers_ref_head);
 
        switch (itype) {
@@ -670,14 +671,31 @@ static
 void register_event(struct lttng_event *event)
 {
        const struct lttng_event_desc *desc;
-       int ret;
+       int ret = -EINVAL;
 
-       WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_TRACEPOINT);
        if (event->registered)
                return;
+
        desc = event->desc;
-       ret = lttng_wrapper_tracepoint_probe_register(desc->kname,
-               desc->probe_callback, event);
+       switch (event->instrumentation) {
+       case LTTNG_KERNEL_TRACEPOINT:
+               ret = lttng_wrapper_tracepoint_probe_register(desc->kname,
+                                                 desc->probe_callback,
+                                                 event);
+               break;
+       case LTTNG_KERNEL_SYSCALL:
+               ret = lttng_syscall_filter_enable(event->chan,
+                       desc->name);
+               break;
+       case LTTNG_KERNEL_KPROBE:
+       case LTTNG_KERNEL_KRETPROBE:
+       case LTTNG_KERNEL_FUNCTION:
+       case LTTNG_KERNEL_NOOP:
+               ret = 0;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+       }
        if (!ret)
                event->registered = 1;
 }
@@ -687,18 +705,18 @@ void register_event(struct lttng_event *event)
  */
 int _lttng_event_unregister(struct lttng_event *event)
 {
+       const struct lttng_event_desc *desc;
        int ret = -EINVAL;
 
        if (!event->registered)
                return 0;
 
+       desc = event->desc;
        switch (event->instrumentation) {
        case LTTNG_KERNEL_TRACEPOINT:
                ret = lttng_wrapper_tracepoint_probe_unregister(event->desc->kname,
                                                  event->desc->probe_callback,
                                                  event);
-               if (ret)
-                       return ret;
                break;
        case LTTNG_KERNEL_KPROBE:
                lttng_kprobes_unregister(event);
@@ -712,8 +730,11 @@ int _lttng_event_unregister(struct lttng_event *event)
                lttng_ftrace_unregister(event);
                ret = 0;
                break;
-       case LTTNG_KERNEL_NOOP:
        case LTTNG_KERNEL_SYSCALL:
+               ret = lttng_syscall_filter_disable(event->chan,
+                       desc->name);
+               break;
+       case LTTNG_KERNEL_NOOP:
                ret = 0;
                break;
        default:
@@ -990,23 +1011,20 @@ fd_error:
  * Enabler management.
  */
 static
-int lttng_desc_match_wildcard_enabler(const struct lttng_event_desc *desc,
-               struct lttng_enabler *enabler)
+int lttng_match_enabler_wildcard(const char *desc_name,
+               const char *name)
 {
-       WARN_ON_ONCE(enabler->type != LTTNG_ENABLER_WILDCARD);
        /* Compare excluding final '*' */
-       if (strncmp(desc->name, enabler->event_param.name,
-                       strlen(enabler->event_param.name) - 1))
+       if (strncmp(desc_name, name, strlen(name) - 1))
                return 0;
        return 1;
 }
 
 static
-int lttng_desc_match_name_enabler(const struct lttng_event_desc *desc,
-               struct lttng_enabler *enabler)
+int lttng_match_enabler_name(const char *desc_name,
+               const char *name)
 {
-       WARN_ON_ONCE(enabler->type != LTTNG_ENABLER_NAME);
-       if (strcmp(desc->name, enabler->event_param.name))
+       if (strcmp(desc_name, name))
                return 0;
        return 1;
 }
@@ -1015,11 +1033,37 @@ static
 int lttng_desc_match_enabler(const struct lttng_event_desc *desc,
                struct lttng_enabler *enabler)
 {
+       const char *desc_name, *enabler_name;
+
+       enabler_name = enabler->event_param.name;
+       switch (enabler->event_param.instrumentation) {
+       case LTTNG_KERNEL_TRACEPOINT:
+               desc_name = desc->name;
+               break;
+       case LTTNG_KERNEL_SYSCALL:
+               desc_name = desc->name;
+               if (!strncmp(desc_name, "compat_", strlen("compat_")))
+                       desc_name += strlen("compat_");
+               if (!strncmp(desc_name, "syscall_exit_",
+                               strlen("syscall_exit_"))) {
+                       desc_name += strlen("syscall_exit_");
+               } else if (!strncmp(desc_name, "syscall_entry_",
+                               strlen("syscall_entry_"))) {
+                       desc_name += strlen("syscall_entry_");
+               } else {
+                       WARN_ON_ONCE(1);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
        switch (enabler->type) {
        case LTTNG_ENABLER_WILDCARD:
-               return lttng_desc_match_wildcard_enabler(desc, enabler);
+               return lttng_match_enabler_wildcard(desc_name, enabler_name);
        case LTTNG_ENABLER_NAME:
-               return lttng_desc_match_name_enabler(desc, enabler);
+               return lttng_match_enabler_name(desc_name, enabler_name);
        default:
                return -EINVAL;
        }
@@ -1087,7 +1131,7 @@ void lttng_create_tracepoint_if_missing(struct lttng_enabler *enabler)
                         */
                        hash = jhash(event_name, name_len, 0);
                        head = &session->events_ht.table[hash & (LTTNG_EVENT_HT_SIZE - 1)];
-                       hlist_for_each_entry(event, head, hlist) {
+                       lttng_hlist_for_each_entry(event, head, hlist) {
                                if (event->desc == desc
                                                && event->chan == enabler->chan)
                                        found = 1;
@@ -1174,6 +1218,11 @@ int lttng_enabler_ref_events(struct lttng_enabler *enabler)
                                &event->enablers_ref_head);
                }
 
+               /*
+                * Link filter bytecodes if not linked yet.
+                */
+               lttng_enabler_event_link_bytecode(event, enabler);
+
                /* TODO: merge event context. */
        }
        return 0;
@@ -1203,11 +1252,12 @@ struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type,
        if (!enabler)
                return NULL;
        enabler->type = type;
+       INIT_LIST_HEAD(&enabler->filter_bytecode_head);
        memcpy(&enabler->event_param, event_param,
                sizeof(enabler->event_param));
        enabler->chan = chan;
        /* ctx left NULL */
-       enabler->enabled = 1;
+       enabler->enabled = 0;
        enabler->evtype = LTTNG_TYPE_ENABLER;
        mutex_lock(&sessions_mutex);
        list_add(&enabler->node, &enabler->chan->session->enablers_head);
@@ -1234,6 +1284,36 @@ int lttng_enabler_disable(struct lttng_enabler *enabler)
        return 0;
 }
 
+int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler,
+               struct lttng_kernel_filter_bytecode __user *bytecode)
+{
+       struct lttng_filter_bytecode_node *bytecode_node;
+       uint32_t bytecode_len;
+       int ret;
+
+       ret = get_user(bytecode_len, &bytecode->len);
+       if (ret)
+               return ret;
+       bytecode_node = kzalloc(sizeof(*bytecode_node) + bytecode_len,
+                       GFP_KERNEL);
+       if (!bytecode_node)
+               return -ENOMEM;
+       ret = copy_from_user(&bytecode_node->bc, bytecode,
+               sizeof(*bytecode) + bytecode_len);
+       if (ret)
+               goto error_free;
+       bytecode_node->enabler = enabler;
+       /* Enforce length based on allocated size */
+       bytecode_node->bc.len = bytecode_len;
+       list_add_tail(&bytecode_node->node, &enabler->filter_bytecode_head);
+       lttng_session_lazy_sync_enablers(enabler->chan->session);
+       return 0;
+
+error_free:
+       kfree(bytecode_node);
+       return ret;
+}
+
 int lttng_enabler_attach_context(struct lttng_enabler *enabler,
                struct lttng_kernel_context *context_param)
 {
@@ -1243,6 +1323,14 @@ int lttng_enabler_attach_context(struct lttng_enabler *enabler,
 static
 void lttng_enabler_destroy(struct lttng_enabler *enabler)
 {
+       struct lttng_filter_bytecode_node *filter_node, *tmp_filter_node;
+
+       /* Destroy filter bytecode */
+       list_for_each_entry_safe(filter_node, tmp_filter_node,
+                       &enabler->filter_bytecode_head, node) {
+               kfree(filter_node);
+       }
+
        /* Destroy contexts */
        lttng_destroy_context(enabler->ctx);
 
@@ -1270,9 +1358,12 @@ void lttng_session_sync_enablers(struct lttng_session *session)
         */
        list_for_each_entry(event, &session->events, list) {
                struct lttng_enabler_ref *enabler_ref;
-               int enabled = 0;
+               struct lttng_bytecode_runtime *runtime;
+               int enabled = 0, has_enablers_without_bytecode = 0;
 
-               if (event->instrumentation == LTTNG_KERNEL_TRACEPOINT) {
+               switch (event->instrumentation) {
+               case LTTNG_KERNEL_TRACEPOINT:
+               case LTTNG_KERNEL_SYSCALL:
                        /* Enable events */
                        list_for_each_entry(enabler_ref,
                                        &event->enablers_ref_head, node) {
@@ -1281,7 +1372,8 @@ void lttng_session_sync_enablers(struct lttng_session *session)
                                        break;
                                }
                        }
-               } else {
+                       break;
+               default:
                        /* Not handled with lazy sync. */
                        continue;
                }
@@ -1302,6 +1394,23 @@ void lttng_session_sync_enablers(struct lttng_session *session)
                } else {
                        _lttng_event_unregister(event);
                }
+
+               /* Check if has enablers without bytecode enabled */
+               list_for_each_entry(enabler_ref,
+                               &event->enablers_ref_head, node) {
+                       if (enabler_ref->ref->enabled
+                                       && list_empty(&enabler_ref->ref->filter_bytecode_head)) {
+                               has_enablers_without_bytecode = 1;
+                               break;
+                       }
+               }
+               event->has_enablers_without_bytecode =
+                       has_enablers_without_bytecode;
+
+               /* Enable filters */
+               list_for_each_entry(runtime,
+                               &event->bytecode_runtime_head, node)
+                       lttng_filter_sync_state(runtime);
        }
 }
 
@@ -2007,9 +2116,12 @@ static int __init lttng_events_init(void)
        if (ret)
                return ret;
 
-       ret = lttng_tracepoint_init();
+       ret = lttng_context_init();
        if (ret)
                return ret;
+       ret = lttng_tracepoint_init();
+       if (ret)
+               goto error_tp;
        event_cache = KMEM_CACHE(lttng_event, 0);
        if (!event_cache) {
                ret = -ENOMEM;
@@ -2029,6 +2141,8 @@ error_abi:
        kmem_cache_destroy(event_cache);
 error_kmem:
        lttng_tracepoint_exit();
+error_tp:
+       lttng_context_exit();
        return ret;
 }
 
@@ -2044,6 +2158,7 @@ static void __exit lttng_events_exit(void)
                lttng_session_destroy(session);
        kmem_cache_destroy(event_cache);
        lttng_tracepoint_exit();
+       lttng_context_exit();
 }
 
 module_exit(lttng_events_exit);
This page took 0.027233 seconds and 4 git commands to generate.