Implement event counter creation
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Thu, 10 Feb 2022 21:36:47 +0000 (16:36 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 15 Jul 2024 20:58:48 +0000 (16:58 -0400)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: I5b407513c5c64ae418fc1846ae10f3fa99609796

include/lttng/events-internal.h
src/lttng-abi.c
src/lttng-events.c
src/lttng-syscalls.c

index 10005a4f900b01ea252221fe850bfb8065670265..f1f1f11f651ad586e11aadf4eaa8a67b48d6532b 100644 (file)
@@ -908,7 +908,7 @@ struct lttng_event_recorder_enabler *lttng_event_recorder_enabler_create(
                struct lttng_kernel_abi_event *event_param,
                struct lttng_kernel_channel_buffer *chan);
 void lttng_event_enabler_session_add(struct lttng_kernel_session *session,
-               struct lttng_event_recorder_enabler *event_enabler);
+               struct lttng_event_enabler_session_common *event_enabler);
 
 struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
                enum lttng_enabler_format_type format_type,
@@ -1223,6 +1223,12 @@ int format_event_key(struct lttng_event_enabler_common *event_enabler, char *key
                     const char *event_name);
 bool lttng_event_enabler_event_name_key_match_event(struct lttng_event_enabler_common *event_enabler,
                const char *event_name, const char *key_string, struct lttng_kernel_event_common *event);
+struct lttng_event_counter_enabler *lttng_event_counter_enabler_create(
+               enum lttng_enabler_format_type format_type,
+               struct lttng_kernel_abi_event *event_param,
+               const struct lttng_kernel_abi_counter_key *abi_key,
+               const struct lttng_counter_key *kernel_key,
+               struct lttng_kernel_channel_counter *chan);
 
 #define lttng_kernel_static_ctx_field(_event_field, _get_size, _record, _get_value, _destroy, _priv)   \
        __LTTNG_COMPOUND_LITERAL(const struct lttng_kernel_ctx_field, {                                 \
index 02eb71a7dbf58c931b55bafe9414257bf3fe8523..de75642b7f237dea6b4324a1a25706f1de2dfd23 100644 (file)
@@ -38,6 +38,7 @@
 #include <wrapper/compiler_attributes.h>
 #include <wrapper/poll.h>
 #include <wrapper/kref.h>
+#include <wrapper/uaccess.h>
 #include <lttng/string-utils.h>
 #include <lttng/abi.h>
 #include <lttng/abi-old.h>
@@ -72,6 +73,11 @@ static struct file_operations lttng_stream_ring_buffer_file_operations;
 static int put_u64(uint64_t val, unsigned long arg);
 static int put_u32(uint32_t val, unsigned long arg);
 
+static
+int lttng_abi_create_event_counter_enabler(struct file *channel_file,
+                          struct lttng_kernel_abi_event *event_param,
+                          const struct lttng_kernel_abi_counter_key *key_param);
+
 static int validate_zeroed_padding(char *p, size_t len)
 {
        size_t i;
@@ -723,6 +729,37 @@ long lttng_counter_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        indexes[i] = local_counter_clear.index.dimension_indexes[i];
                return lttng_kernel_counter_clear(counter, indexes);
        }
+       case LTTNG_KERNEL_ABI_COUNTER_EVENT:
+       {
+               struct lttng_kernel_abi_counter_event *counter_event_param;
+               struct lttng_kernel_abi_counter_event __user *ucounter_event_param =
+                               (struct lttng_kernel_abi_counter_event __user *) arg;
+               struct lttng_kernel_abi_event *event_param;
+               struct lttng_kernel_abi_counter_key *key_param;
+               long ret;
+
+               counter_event_param = kzalloc(sizeof(*counter_event_param), GFP_KERNEL);
+               if (!counter_event_param)
+                       return -ENOMEM;
+               if (copy_from_user(counter_event_param, ucounter_event_param,
+                               sizeof(*counter_event_param)))
+                       return -EFAULT;
+               if (validate_zeroed_padding(counter_event_param->padding,
+                               sizeof(counter_event_param->padding)))
+                       return -EINVAL;
+               if (validate_zeroed_padding(counter_event_param->event.padding,
+                               sizeof(counter_event_param->event.padding)))
+                       return -EINVAL;
+               event_param = &counter_event_param->event;
+               key_param = &counter_event_param->key;
+               ret = lttng_abi_create_event_counter_enabler(file, event_param, key_param);
+               kfree(counter_event_param);
+               return ret;
+       }
+       case LTTNG_KERNEL_ABI_ENABLE:
+               return lttng_channel_enable(&counter->parent);
+       case LTTNG_KERNEL_ABI_DISABLE:
+               return lttng_channel_disable(&counter->parent);
        default:
                return -ENOSYS;
        }
@@ -1867,7 +1904,7 @@ int lttng_abi_create_event_recorder_enabler(struct file *channel_file,
                ret = event_fd;
                goto fd_error;
        }
-       event_file = anon_inode_getfile("[lttng_event]",
+       event_file = anon_inode_getfile("[lttng_event_recorder]",
                                        fops, NULL, O_RDWR);
        if (IS_ERR(event_file)) {
                ret = PTR_ERR(event_file);
@@ -1901,7 +1938,7 @@ int lttng_abi_create_event_recorder_enabler(struct file *channel_file,
                                event_param, channel);
                }
                if (event_enabler)
-                       lttng_event_enabler_session_add(channel->parent.session, event_enabler);
+                       lttng_event_enabler_session_add(channel->parent.session, &event_enabler->parent);
                priv = event_enabler;
                break;
        }
@@ -1958,6 +1995,151 @@ fd_error:
        return ret;
 }
 
+static
+int lttng_abi_create_event_counter_enabler(struct file *channel_file,
+                          struct lttng_kernel_abi_event *event_param,
+                          const struct lttng_kernel_abi_counter_key *key_param)
+{
+       const struct file_operations *fops;
+       struct lttng_kernel_channel_counter *channel = channel_file->private_data;
+       int event_fd, ret;
+       struct file *event_file;
+       void *priv;
+
+       event_param->name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
+       switch (event_param->instrumentation) {
+       case LTTNG_KERNEL_ABI_KRETPROBE:
+               event_param->u.kretprobe.symbol_name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
+               break;
+       case LTTNG_KERNEL_ABI_KPROBE:
+               event_param->u.kprobe.symbol_name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
+               break;
+       case LTTNG_KERNEL_ABI_FUNCTION:
+               WARN_ON_ONCE(1);
+               /* Not implemented. */
+               break;
+       default:
+               break;
+       }
+
+       switch (event_param->instrumentation) {
+       case LTTNG_KERNEL_ABI_TRACEPOINT:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_SYSCALL:
+               fops = &lttng_event_session_enabler_fops;
+               break;
+       case LTTNG_KERNEL_ABI_KPROBE:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KRETPROBE:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_UPROBE:
+               fops = &lttng_event_session_fops;
+               break;
+
+       case LTTNG_KERNEL_ABI_FUNCTION:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_NOOP:
+               lttng_fallthrough;
+       default:
+               return -EINVAL;
+       }
+
+       event_fd = get_unused_fd_flags(0);
+       if (event_fd < 0) {
+               ret = event_fd;
+               goto fd_error;
+       }
+       event_file = anon_inode_getfile("[lttng_event_counter]",
+                                       fops, NULL, O_RDWR);
+       if (IS_ERR(event_file)) {
+               ret = PTR_ERR(event_file);
+               goto file_error;
+       }
+       /* The event holds a reference on the channel */
+       if (!atomic_long_add_unless(&channel_file->f_count, 1, LONG_MAX)) {
+               ret = -EOVERFLOW;
+               goto refcount_error;
+       }
+       ret = lttng_abi_validate_event_param(event_param);
+       if (ret)
+               goto event_error;
+
+       switch (event_param->instrumentation) {
+       case LTTNG_KERNEL_ABI_TRACEPOINT:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_SYSCALL:
+       {
+               struct lttng_event_counter_enabler *event_enabler;
+
+               if (strutils_is_star_glob_pattern(event_param->name)) {
+                       /*
+                        * If the event name is a star globbing pattern,
+                        * we create the special star globbing enabler.
+                        */
+                       event_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_STAR_GLOB,
+                               event_param, key_param, NULL, channel);
+               } else {
+                       event_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_param, key_param, NULL, channel);
+               }
+               if (event_enabler)
+                       lttng_event_enabler_session_add(channel->parent.session, &event_enabler->parent);
+               priv = event_enabler;
+               break;
+       }
+
+       case LTTNG_KERNEL_ABI_KPROBE:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KRETPROBE:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_UPROBE:
+       {
+               struct lttng_kernel_event_common *event;
+               struct lttng_event_counter_enabler *event_enabler;
+
+               event_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_param, key_param, NULL, channel);
+               if (!event_enabler) {
+                       ret = -ENOMEM;
+                       goto event_error;
+               }
+               /*
+                * We tolerate no failure path after event creation. It
+                * will stay invariant for the rest of the session.
+                */
+               event = lttng_kernel_event_create(&event_enabler->parent.parent, NULL);
+               WARN_ON_ONCE(IS_ERR(event));
+               lttng_event_enabler_destroy(&event_enabler->parent.parent);
+               if (IS_ERR(event)) {
+                       ret = PTR_ERR(event);
+                       goto event_error;
+               }
+               priv = event;
+               break;
+       }
+
+       case LTTNG_KERNEL_ABI_FUNCTION:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_NOOP:
+               lttng_fallthrough;
+       default:
+               ret = -EINVAL;
+               goto event_error;
+       }
+       event_file->private_data = priv;
+       fd_install(event_fd, event_file);
+       return event_fd;
+
+event_error:
+       atomic_long_dec(&channel_file->f_count);
+refcount_error:
+       fput(event_file);
+file_error:
+       put_unused_fd(event_fd);
+fd_error:
+       return ret;
+}
+
 static
 long lttng_event_notifier_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
index 241c7964b194c042387aff9cc2e652400836ed87..14605a30e2405fcec445be835127378a4dee7168 100644 (file)
@@ -1421,10 +1421,7 @@ struct lttng_kernel_event_common *_lttng_kernel_event_create(struct lttng_event_
        }
 
        case LTTNG_KERNEL_ABI_SYSCALL:
-               /*
-                * Needs to be explicitly enabled after creation, since
-                * we may want to apply filters.
-                */
+               /* Event will be enabled by enabler sync. */
                event->enabled = 0;
                event->priv->registered = 0;
                event->priv->desc = event_desc;
@@ -2371,6 +2368,62 @@ int lttng_fix_pending_event_notifiers(void)
        return 0;
 }
 
+static
+int copy_abi_counter_key(struct lttng_counter_key *key,
+                    const struct lttng_kernel_abi_counter_key *key_param)
+{
+       size_t i, j, nr_dimensions;
+
+       nr_dimensions = key_param->nr_dimensions;
+       if (nr_dimensions > LTTNG_KERNEL_ABI_COUNTER_DIMENSION_MAX)
+               return -EINVAL;
+       key->nr_dimensions = nr_dimensions;
+       for (i = 0; i < nr_dimensions; i++) {
+               const struct lttng_kernel_abi_counter_key_dimension *udim =
+                       &key_param->key_dimensions[i];
+               struct lttng_counter_key_dimension *dim =
+                       &key->key_dimensions[i];
+               size_t nr_key_tokens;
+
+               nr_key_tokens = udim->nr_key_tokens;
+               if (!nr_key_tokens || nr_key_tokens > LTTNG_KERNEL_ABI_NR_KEY_TOKEN)
+                       return -EINVAL;
+               dim->nr_key_tokens = nr_key_tokens;
+               for (j = 0; j < nr_key_tokens; j++) {
+                       const struct lttng_kernel_abi_key_token *utoken =
+                               &udim->key_tokens[j];
+                       struct lttng_key_token *token =
+                               &dim->key_tokens[j];
+
+                       switch (utoken->type) {
+                       case LTTNG_KERNEL_ABI_KEY_TOKEN_STRING:
+                       {
+                               long ret;
+
+                               token->type = LTTNG_KERNEL_ABI_KEY_TOKEN_STRING;
+                               ret = strncpy_from_user(token->arg.string,
+                                       (char __user *)(unsigned long)utoken->arg.string_ptr,
+                                       LTTNG_KERNEL_ABI_KEY_TOKEN_STRING_LEN_MAX);
+                               if (ret < 0)
+                                       return -EFAULT;
+                               if (!ret || ret == LTTNG_KERNEL_ABI_KEY_TOKEN_STRING_LEN_MAX)
+                                       return -EINVAL;
+                               break;
+                       }
+                       case LTTNG_KERNEL_ABI_KEY_TOKEN_EVENT_NAME:
+                               token->type = LTTNG_KERNEL_ABI_KEY_TOKEN_EVENT_NAME;
+                               break;
+                       case LTTNG_KERNEL_ABI_KEY_TOKEN_PROVIDER_NAME:
+                               printk(KERN_ERR "LTTng: Provider name token not supported.\n");
+                               lttng_fallthrough;
+                       default:
+                               return -EINVAL;
+                       }
+               }
+       }
+       return 0;
+}
+
 struct lttng_event_recorder_enabler *lttng_event_recorder_enabler_create(
                enum lttng_enabler_format_type format_type,
                struct lttng_kernel_abi_event *event_param,
@@ -2394,12 +2447,46 @@ struct lttng_event_recorder_enabler *lttng_event_recorder_enabler_create(
        return event_enabler;
 }
 
+struct lttng_event_counter_enabler *lttng_event_counter_enabler_create(
+               enum lttng_enabler_format_type format_type,
+               struct lttng_kernel_abi_event *event_param,
+               const struct lttng_kernel_abi_counter_key *abi_key,
+               const struct lttng_counter_key *kernel_key,
+               struct lttng_kernel_channel_counter *chan)
+{
+       struct lttng_event_counter_enabler *event_enabler;
+
+       event_enabler = kzalloc(sizeof(*event_enabler), GFP_KERNEL);
+       if (!event_enabler)
+               return NULL;
+       event_enabler->parent.parent.enabler_type = LTTNG_EVENT_ENABLER_TYPE_COUNTER;
+       event_enabler->parent.parent.format_type = format_type;
+       INIT_LIST_HEAD(&event_enabler->parent.parent.filter_bytecode_head);
+       memcpy(&event_enabler->parent.parent.event_param, event_param,
+               sizeof(event_enabler->parent.parent.event_param));
+       event_enabler->chan = chan;
+       event_enabler->parent.chan = &chan->parent;
+       if (abi_key) {
+               if (copy_abi_counter_key(&event_enabler->key, abi_key)) {
+                       kfree(event_enabler);
+                       return NULL;
+               }
+       } else {
+               memcpy(&event_enabler->key, kernel_key, sizeof(*kernel_key));
+       }
+
+       /* ctx left NULL */
+       event_enabler->parent.parent.enabled = 0;
+       event_enabler->parent.parent.user_token = event_param->token;
+       return event_enabler;
+}
+
 void lttng_event_enabler_session_add(struct lttng_kernel_session *session,
-               struct lttng_event_recorder_enabler *event_enabler)
+               struct lttng_event_enabler_session_common *event_enabler)
 {
        mutex_lock(&sessions_mutex);
-       list_add(&event_enabler->parent.parent.node, &session->priv->enablers_head);
-       event_enabler->parent.parent.published = true;
+       list_add(&event_enabler->parent.node, &session->priv->enablers_head);
+       event_enabler->parent.published = true;
        lttng_session_lazy_sync_event_enablers(session);
        mutex_unlock(&sessions_mutex);
 }
index 7904108debcf3339b66dc6ed5c7da99e8ed17dba..4e404e5741a797d1d7fcb3ced1b899daac5ed9e5 100644 (file)
@@ -571,6 +571,7 @@ void lttng_syscall_event_enabler_create_event(struct lttng_event_enabler_common
                strncpy(ev.name, desc->event_name, LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1);
                ev.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
                ev.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
+               ev.token = syscall_event_enabler->user_token;
                event_recorder_enabler = lttng_event_recorder_enabler_create(LTTNG_ENABLER_FORMAT_NAME, &ev,
                                syscall_event_recorder_enabler->chan);
                WARN_ON_ONCE(!event_recorder_enabler);
@@ -592,7 +593,6 @@ void lttng_syscall_event_enabler_create_event(struct lttng_event_enabler_common
                        container_of(syscall_event_enabler, struct lttng_event_notifier_enabler, parent);
                struct lttng_event_notifier_enabler *event_notifier_enabler;
                struct lttng_kernel_abi_event_notifier event_notifier_param;
-               uint64_t user_token = syscall_event_enabler->user_token;
                uint64_t error_counter_index = syscall_event_notifier_enabler->error_counter_index;
 
                memset(&event_notifier_param, 0, sizeof(event_notifier_param));
@@ -618,7 +618,7 @@ void lttng_syscall_event_enabler_create_event(struct lttng_event_enabler_common
                        LTTNG_KERNEL_ABI_SYM_NAME_LEN - strlen(event_notifier_param.event.name) - 1);
                event_notifier_param.event.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
                event_notifier_param.event.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
-               event_notifier_param.event.token = user_token;
+               event_notifier_param.event.token = syscall_event_enabler->user_token;
                event_notifier_param.error_counter_index = error_counter_index;
 
                event_notifier_enabler = lttng_event_notifier_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
@@ -633,6 +633,53 @@ void lttng_syscall_event_enabler_create_event(struct lttng_event_enabler_common
                }
                event->priv->u.syscall.syscall_id = syscall_nr;
                break;
+       case LTTNG_EVENT_ENABLER_TYPE_COUNTER:
+       {
+               struct lttng_event_counter_enabler *syscall_event_counter_enabler =
+                       container_of(syscall_event_enabler, struct lttng_event_counter_enabler, parent.parent);
+               struct lttng_event_counter_enabler *event_counter_enabler;
+               struct lttng_kernel_abi_event ev;
+
+               /* We need to create an event for this syscall/enabler. */
+               memset(&ev, 0, sizeof(ev));
+               switch (type) {
+               case SC_TYPE_ENTRY:
+                       ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
+                       ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
+                       break;
+               case SC_TYPE_EXIT:
+                       ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
+                       ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_NATIVE;
+                       break;
+               case SC_TYPE_COMPAT_ENTRY:
+                       ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_ENTRY;
+                       ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
+                       break;
+               case SC_TYPE_COMPAT_EXIT:
+                       ev.u.syscall.entryexit = LTTNG_KERNEL_ABI_SYSCALL_EXIT;
+                       ev.u.syscall.abi = LTTNG_KERNEL_ABI_SYSCALL_ABI_COMPAT;
+                       break;
+               }
+               strncpy(ev.name, desc->event_name, LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1);
+               ev.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
+               ev.instrumentation = LTTNG_KERNEL_ABI_SYSCALL;
+               ev.token = syscall_event_enabler->user_token;
+               event_counter_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_NAME, &ev,
+                               NULL, &syscall_event_counter_enabler->key, syscall_event_counter_enabler->chan);
+               WARN_ON_ONCE(!event_counter_enabler);
+               if (!event_counter_enabler)
+                       return;
+               event = _lttng_kernel_event_create(&event_counter_enabler->parent.parent, desc);
+               lttng_event_enabler_destroy(&event_counter_enabler->parent.parent);
+               if (IS_ERR(event)) {
+                       if (PTR_ERR(event) != -EEXIST)
+                               printk(KERN_INFO "Unable to create event counter %s\n", desc->event_name);
+                       return;
+               }
+               event->priv->u.syscall.syscall_id = syscall_nr;
+               break;
+       }
+
        }
        default:
                break;
This page took 0.032791 seconds and 4 git commands to generate.