From 6ef1e2f5e5bfe671b761ac128bcfb5a03b3b3f90 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 10 Feb 2022 16:36:47 -0500 Subject: [PATCH] Implement event counter creation Signed-off-by: Mathieu Desnoyers Change-Id: I5b407513c5c64ae418fc1846ae10f3fa99609796 --- include/lttng/events-internal.h | 8 +- src/lttng-abi.c | 186 +++++++++++++++++++++++++++++++- src/lttng-events.c | 101 +++++++++++++++-- src/lttng-syscalls.c | 51 ++++++++- 4 files changed, 334 insertions(+), 12 deletions(-) diff --git a/include/lttng/events-internal.h b/include/lttng/events-internal.h index 10005a4f..f1f1f11f 100644 --- a/include/lttng/events-internal.h +++ b/include/lttng/events-internal.h @@ -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, { \ diff --git a/src/lttng-abi.c b/src/lttng-abi.c index 02eb71a7..de75642b 100644 --- a/src/lttng-abi.c +++ b/src/lttng-abi.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -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 = <tng_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 = <tng_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) { diff --git a/src/lttng-events.c b/src/lttng-events.c index 241c7964..14605a30 100644 --- a/src/lttng-events.c +++ b/src/lttng-events.c @@ -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); } diff --git a/src/lttng-syscalls.c b/src/lttng-syscalls.c index 7904108d..4e404e57 100644 --- a/src/lttng-syscalls.c +++ b/src/lttng-syscalls.c @@ -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; -- 2.34.1