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,
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, { \
#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>
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;
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;
}
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);
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;
}
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)
{
}
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;
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,
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);
}
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);
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));
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,
}
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;