Introduce lazy system call event creation
[lttng-modules.git] / src / lttng-events.c
index d1a0706e0b9793b525e5c66212ac23b9e85d0614..3f9d0f9a91fdf7b50b7a647d1aea55413d8412b0 100644 (file)
@@ -52,6 +52,7 @@
 static LIST_HEAD(sessions);
 static LIST_HEAD(event_notifier_groups);
 static LIST_HEAD(lttng_transport_list);
+static LIST_HEAD(lttng_counter_transport_list);
 /*
  * Protect the sessions and metadata caches.
  */
@@ -197,6 +198,61 @@ err:
        return NULL;
 }
 
+static
+struct lttng_counter_transport *lttng_counter_transport_find(const char *name)
+{
+       struct lttng_counter_transport *transport;
+
+       list_for_each_entry(transport, &lttng_counter_transport_list, node) {
+               if (!strcmp(transport->name, name))
+                       return transport;
+       }
+       return NULL;
+}
+
+struct lttng_counter *lttng_kernel_counter_create(
+               const char *counter_transport_name,
+               size_t number_dimensions, const size_t *dimensions_sizes)
+{
+       struct lttng_counter *counter = NULL;
+       struct lttng_counter_transport *counter_transport = NULL;
+
+       counter_transport = lttng_counter_transport_find(counter_transport_name);
+       if (!counter_transport) {
+               printk(KERN_WARNING "LTTng: counter transport %s not found.\n",
+                      counter_transport_name);
+               goto notransport;
+       }
+       if (!try_module_get(counter_transport->owner)) {
+               printk(KERN_WARNING "LTTng: Can't lock counter transport module.\n");
+               goto notransport;
+       }
+
+       counter = lttng_kvzalloc(sizeof(struct lttng_counter), GFP_KERNEL);
+       if (!counter)
+               goto nomem;
+
+       /* Create event notifier error counter. */
+       counter->ops = &counter_transport->ops;
+       counter->transport = counter_transport;
+
+       counter->counter = counter->ops->counter_create(
+                       number_dimensions, dimensions_sizes, 0);
+       if (!counter->counter) {
+               goto create_error;
+       }
+
+       return counter;
+
+create_error:
+       lttng_kvfree(counter);
+nomem:
+       if (counter_transport)
+               module_put(counter_transport->owner);
+notransport:
+       return NULL;
+}
+
 struct lttng_event_notifier_group *lttng_event_notifier_group_create(void)
 {
        struct lttng_transport *transport = NULL;
@@ -281,7 +337,7 @@ void lttng_session_destroy(struct lttng_session *session)
        mutex_lock(&sessions_mutex);
        WRITE_ONCE(session->active, 0);
        list_for_each_entry(chan, &session->chan, list) {
-               ret = lttng_syscalls_unregister_event(chan);
+               ret = lttng_syscalls_unregister_channel(chan);
                WARN_ON(ret);
        }
        list_for_each_entry(event, &session->events, list) {
@@ -330,7 +386,7 @@ void lttng_event_notifier_group_destroy(
 
        mutex_lock(&sessions_mutex);
 
-       ret = lttng_syscalls_unregister_event_notifier(event_notifier_group);
+       ret = lttng_syscalls_unregister_event_notifier_group(event_notifier_group);
        WARN_ON(ret);
 
        list_for_each_entry_safe(event_notifier, tmpevent_notifier,
@@ -354,6 +410,14 @@ void lttng_event_notifier_group_destroy(
                        &event_notifier_group->event_notifiers_head, list)
                _lttng_event_notifier_destroy(event_notifier);
 
+       if (event_notifier_group->error_counter) {
+               struct lttng_counter *error_counter = event_notifier_group->error_counter;
+               error_counter->ops->counter_destroy(error_counter->counter);
+               module_put(error_counter->transport->owner);
+               lttng_kvfree(error_counter);
+               event_notifier_group->error_counter = NULL;
+       }
+
        event_notifier_group->ops->channel_destroy(event_notifier_group->chan);
        module_put(event_notifier_group->transport->owner);
        list_del(&event_notifier_group->node);
@@ -759,6 +823,7 @@ void _lttng_metadata_channel_hangup(struct lttng_metadata_stream *stream)
        wake_up_interruptible(&stream->read_wait);
 }
 
+
 /*
  * Supports event creation while tracing session is active.
  * Needs to be called with sessions mutex held.
@@ -1000,7 +1065,8 @@ full:
 
 struct lttng_event_notifier *_lttng_event_notifier_create(
                const struct lttng_event_desc *event_desc,
-               uint64_t token, struct lttng_event_notifier_group *event_notifier_group,
+               uint64_t token, uint64_t error_counter_index,
+               struct lttng_event_notifier_group *event_notifier_group,
                struct lttng_kernel_event_notifier *event_notifier_param,
                void *filter, enum lttng_kernel_instrumentation itype)
 {
@@ -1048,11 +1114,14 @@ struct lttng_event_notifier *_lttng_event_notifier_create(
 
        event_notifier->group = event_notifier_group;
        event_notifier->user_token = token;
+       event_notifier->error_counter_index = error_counter_index;
+       event_notifier->num_captures = 0;
        event_notifier->filter = filter;
        event_notifier->instrumentation = itype;
        event_notifier->evtype = LTTNG_TYPE_EVENT;
        event_notifier->send_notification = lttng_event_notifier_notification_send;
        INIT_LIST_HEAD(&event_notifier->filter_bytecode_runtime_head);
+       INIT_LIST_HEAD(&event_notifier->capture_bytecode_runtime_head);
        INIT_LIST_HEAD(&event_notifier->enablers_ref_head);
 
        switch (itype) {
@@ -1162,6 +1231,35 @@ struct lttng_event_notifier *_lttng_event_notifier_create(
 
        list_add(&event_notifier->list, &event_notifier_group->event_notifiers_head);
        hlist_add_head(&event_notifier->hlist, head);
+
+       /*
+        * Clear the error counter bucket. The sessiond keeps track of which
+        * bucket is currently in use. We trust it.
+        */
+       if (event_notifier_group->error_counter) {
+               size_t dimension_index[1];
+
+               /*
+                * Check that the index is within the boundary of the counter.
+                */
+               if (event_notifier->error_counter_index >= event_notifier_group->error_counter_len) {
+                       printk(KERN_INFO "LTTng: event_notifier: Error counter index out-of-bound: counter-len=%zu, index=%llu\n",
+                               event_notifier_group->error_counter_len, event_notifier->error_counter_index);
+                       ret = -EINVAL;
+                       goto register_error;
+               }
+
+               dimension_index[0] = event_notifier->error_counter_index;
+               ret = event_notifier_group->error_counter->ops->counter_clear(
+                               event_notifier_group->error_counter->counter,
+                               dimension_index);
+               if (ret) {
+                       printk(KERN_INFO "LTTng: event_notifier: Unable to clear error counter bucket %llu\n",
+                               event_notifier->error_counter_index);
+                       goto register_error;
+               }
+       }
+
        return event_notifier;
 
 register_error:
@@ -1172,6 +1270,28 @@ type_error:
        return ERR_PTR(ret);
 }
 
+int lttng_kernel_counter_read(struct lttng_counter *counter,
+               const size_t *dim_indexes, int32_t cpu,
+               int64_t *val, bool *overflow, bool *underflow)
+{
+       return counter->ops->counter_read(counter->counter, dim_indexes,
+                       cpu, val, overflow, underflow);
+}
+
+int lttng_kernel_counter_aggregate(struct lttng_counter *counter,
+               const size_t *dim_indexes, int64_t *val,
+               bool *overflow, bool *underflow)
+{
+       return counter->ops->counter_aggregate(counter->counter, dim_indexes,
+                       val, overflow, underflow);
+}
+
+int lttng_kernel_counter_clear(struct lttng_counter *counter,
+               const size_t *dim_indexes)
+{
+       return counter->ops->counter_clear(counter->counter, dim_indexes);
+}
+
 struct lttng_event *lttng_event_create(struct lttng_channel *chan,
                                struct lttng_kernel_event *event_param,
                                void *filter,
@@ -1189,7 +1309,8 @@ struct lttng_event *lttng_event_create(struct lttng_channel *chan,
 
 struct lttng_event_notifier *lttng_event_notifier_create(
                const struct lttng_event_desc *event_desc,
-               uint64_t id, struct lttng_event_notifier_group *event_notifier_group,
+               uint64_t id, uint64_t error_counter_index,
+               struct lttng_event_notifier_group *event_notifier_group,
                struct lttng_kernel_event_notifier *event_notifier_param,
                void *filter, enum lttng_kernel_instrumentation itype)
 {
@@ -1197,7 +1318,8 @@ struct lttng_event_notifier *lttng_event_notifier_create(
 
        mutex_lock(&sessions_mutex);
        event_notifier = _lttng_event_notifier_create(event_desc, id,
-               event_notifier_group, event_notifier_param, filter, itype);
+               error_counter_index, event_notifier_group,
+               event_notifier_param, filter, itype);
        mutex_unlock(&sessions_mutex);
        return event_notifier;
 }
@@ -1927,6 +2049,7 @@ void lttng_create_tracepoint_event_notifier_if_missing(struct lttng_event_notifi
                         */
                        event_notifier = _lttng_event_notifier_create(desc,
                                event_notifier_enabler->base.user_token,
+                               event_notifier_enabler->error_counter_index,
                                event_notifier_group, NULL, NULL,
                                LTTNG_KERNEL_TRACEPOINT);
                        if (IS_ERR(event_notifier)) {
@@ -1942,7 +2065,7 @@ void lttng_create_syscall_event_if_missing(struct lttng_event_enabler *event_ena
 {
        int ret;
 
-       ret = lttng_syscalls_register_event(event_enabler->chan, NULL);
+       ret = lttng_syscalls_register_event(event_enabler, NULL);
        WARN_ON_ONCE(ret);
 }
 
@@ -1992,14 +2115,17 @@ int lttng_event_enabler_ref_events(struct lttng_event_enabler *event_enabler)
        struct lttng_event *event;
 
        if (base_enabler->event_param.instrumentation == LTTNG_KERNEL_SYSCALL &&
-                       base_enabler->event_param.u.syscall.entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT &&
                        base_enabler->event_param.u.syscall.abi == LTTNG_KERNEL_SYSCALL_ABI_ALL &&
                        base_enabler->event_param.u.syscall.match == LTTNG_KERNEL_SYSCALL_MATCH_NAME &&
                        !strcmp(base_enabler->event_param.name, "*")) {
-               if (base_enabler->enabled)
-                       WRITE_ONCE(chan->syscall_all, 1);
-               else
-                       WRITE_ONCE(chan->syscall_all, 0);
+               int enabled = base_enabler->enabled;
+               enum lttng_kernel_syscall_entryexit entryexit = base_enabler->event_param.u.syscall.entryexit;
+
+               if (entryexit == LTTNG_KERNEL_SYSCALL_ENTRY || entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT)
+                       WRITE_ONCE(chan->syscall_all_entry, enabled);
+
+               if (entryexit == LTTNG_KERNEL_SYSCALL_EXIT || entryexit == LTTNG_KERNEL_SYSCALL_ENTRYEXIT)
+                       WRITE_ONCE(chan->syscall_all_exit, enabled);
        }
 
        /* First ensure that probe events are created for this enabler. */
@@ -2120,6 +2246,13 @@ int lttng_event_notifier_enabler_ref_event_notifiers(
                lttng_enabler_link_bytecode(event_notifier->desc,
                        lttng_static_ctx, &event_notifier->filter_bytecode_runtime_head,
                        &lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)->filter_bytecode_head);
+
+               /* Link capture bytecodes if not linked yet. */
+               lttng_enabler_link_bytecode(event_notifier->desc,
+                       lttng_static_ctx, &event_notifier->capture_bytecode_runtime_head,
+                       &event_notifier_enabler->capture_bytecode_head);
+
+               event_notifier->num_captures = event_notifier_enabler->num_captures;
        }
        return 0;
 }
@@ -2225,7 +2358,7 @@ int lttng_enabler_attach_filter_bytecode(struct lttng_enabler *enabler,
        ret = get_user(bytecode_len, &bytecode->len);
        if (ret)
                return ret;
-       bytecode_node = kzalloc(sizeof(*bytecode_node) + bytecode_len,
+       bytecode_node = lttng_kvzalloc(sizeof(*bytecode_node) + bytecode_len,
                        GFP_KERNEL);
        if (!bytecode_node)
                return -ENOMEM;
@@ -2243,7 +2376,7 @@ int lttng_enabler_attach_filter_bytecode(struct lttng_enabler *enabler,
        return 0;
 
 error_free:
-       kfree(bytecode_node);
+       lttng_kvfree(bytecode_node);
        return ret;
 }
 
@@ -2289,7 +2422,7 @@ void lttng_enabler_destroy(struct lttng_enabler *enabler)
        /* Destroy filter bytecode */
        list_for_each_entry_safe(filter_node, tmp_filter_node,
                        &enabler->filter_bytecode_head, node) {
-               kfree(filter_node);
+               lttng_kvfree(filter_node);
        }
 }
 
@@ -2318,6 +2451,10 @@ struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
 
        event_notifier_enabler->base.format_type = format_type;
        INIT_LIST_HEAD(&event_notifier_enabler->base.filter_bytecode_head);
+       INIT_LIST_HEAD(&event_notifier_enabler->capture_bytecode_head);
+
+       event_notifier_enabler->error_counter_index = event_notifier_param->error_counter_index;
+       event_notifier_enabler->num_captures = 0;
 
        memcpy(&event_notifier_enabler->base.event_param, &event_notifier_param->event,
                sizeof(event_notifier_enabler->base.event_param));
@@ -2375,6 +2512,48 @@ error:
        return ret;
 }
 
+int lttng_event_notifier_enabler_attach_capture_bytecode(
+               struct lttng_event_notifier_enabler *event_notifier_enabler,
+               struct lttng_kernel_capture_bytecode __user *bytecode)
+{
+       struct lttng_bytecode_node *bytecode_node;
+       struct lttng_enabler *enabler =
+                       lttng_event_notifier_enabler_as_enabler(event_notifier_enabler);
+       uint32_t bytecode_len;
+       int ret;
+
+       ret = get_user(bytecode_len, &bytecode->len);
+       if (ret)
+               return ret;
+
+       bytecode_node = lttng_kvzalloc(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->type = LTTNG_BYTECODE_NODE_TYPE_CAPTURE;
+       bytecode_node->enabler = enabler;
+
+       /* Enforce length based on allocated size */
+       bytecode_node->bc.len = bytecode_len;
+       list_add_tail(&bytecode_node->node, &event_notifier_enabler->capture_bytecode_head);
+
+       event_notifier_enabler->num_captures++;
+
+       lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
+       goto end;
+
+error_free:
+       lttng_kvfree(bytecode_node);
+end:
+       return ret;
+}
+
 int lttng_event_notifier_add_callsite(struct lttng_event_notifier *event_notifier,
                struct lttng_kernel_event_callsite __user *callsite)
 {
@@ -2565,6 +2744,11 @@ void lttng_event_notifier_group_sync_enablers(struct lttng_event_notifier_group
                list_for_each_entry(runtime,
                                &event_notifier->filter_bytecode_runtime_head, node)
                        lttng_bytecode_filter_sync_state(runtime);
+
+               /* Enable captures */
+               list_for_each_entry(runtime,
+                               &event_notifier->capture_bytecode_runtime_head, node)
+                       lttng_bytecode_capture_sync_state(runtime);
        }
 }
 
@@ -3819,6 +4003,29 @@ void lttng_transport_unregister(struct lttng_transport *transport)
 }
 EXPORT_SYMBOL_GPL(lttng_transport_unregister);
 
+void lttng_counter_transport_register(struct lttng_counter_transport *transport)
+{
+       /*
+        * Make sure no page fault can be triggered by the module about to be
+        * registered. We deal with this here so we don't have to call
+        * vmalloc_sync_mappings() in each module's init.
+        */
+       wrapper_vmalloc_sync_mappings();
+
+       mutex_lock(&sessions_mutex);
+       list_add_tail(&transport->node, &lttng_counter_transport_list);
+       mutex_unlock(&sessions_mutex);
+}
+EXPORT_SYMBOL_GPL(lttng_counter_transport_register);
+
+void lttng_counter_transport_unregister(struct lttng_counter_transport *transport)
+{
+       mutex_lock(&sessions_mutex);
+       list_del(&transport->node);
+       mutex_unlock(&sessions_mutex);
+}
+EXPORT_SYMBOL_GPL(lttng_counter_transport_unregister);
+
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0))
 
 enum cpuhp_state lttng_hp_prepare;
This page took 0.029046 seconds and 4 git commands to generate.