Fix: scsi: sd: Atomic write support added in 6.11-rc1
[lttng-modules.git] / src / lttng-abi.c
index aa1b0195eff6515ddee759871cc3fd4e25ee2f51..5a3b616fddc7d9daac92c3cf422a48cd641b9eab 100644 (file)
@@ -23,6 +23,7 @@
  *     - Takes instrumentation source specific arguments.
  */
 
+#include <asm/barrier.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/anon_inodes.h>
 #include <ringbuffer/vfs.h>
 #include <ringbuffer/backend.h>
 #include <ringbuffer/frontend.h>
+#include <wrapper/compiler_attributes.h>
 #include <wrapper/poll.h>
-#include <wrapper/file.h>
 #include <wrapper/kref.h>
-#include <wrapper/barrier.h>
+#include <wrapper/uaccess.h>
 #include <lttng/string-utils.h>
 #include <lttng/abi.h>
 #include <lttng/abi-old.h>
@@ -65,13 +66,21 @@ static const struct file_operations lttng_session_fops;
 static const struct file_operations lttng_event_notifier_group_fops;
 static const struct file_operations lttng_channel_fops;
 static const struct file_operations lttng_metadata_fops;
-static const struct file_operations lttng_event_recorder_event_fops;
-static const struct file_operations lttng_event_recorder_enabler_fops;
+static const struct file_operations lttng_event_session_fops;
+static const struct file_operations lttng_event_session_enabler_fops;
 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_counter_event *counter_event);
+static
+long lttng_abi_session_create_counter(
+               struct lttng_kernel_session *session,
+               const struct lttng_kernel_counter_conf *counter_conf);
+
 static int validate_zeroed_padding(char *p, size_t len)
 {
        size_t i;
@@ -98,7 +107,7 @@ int lttng_abi_create_session(void)
        session = lttng_session_create();
        if (!session)
                return -ENOMEM;
-       session_fd = lttng_get_unused_fd();
+       session_fd = get_unused_fd_flags(0);
        if (session_fd < 0) {
                ret = session_fd;
                goto fd_error;
@@ -121,6 +130,7 @@ fd_error:
        return ret;
 }
 
+static
 void event_notifier_send_notification_work_wakeup(struct irq_work *entry)
 {
        struct lttng_event_notifier_group *event_notifier_group =
@@ -140,7 +150,7 @@ int lttng_abi_create_event_notifier_group(void)
        if (!event_notifier_group)
                return -ENOMEM;
 
-       event_notifier_group_fd = lttng_get_unused_fd();
+       event_notifier_group_fd = get_unused_fd_flags(0);
        if (event_notifier_group_fd < 0) {
                ret = event_notifier_group_fd;
                goto fd_error;
@@ -173,7 +183,7 @@ int lttng_abi_tracepoint_list(void)
        struct file *tracepoint_list_file;
        int file_fd, ret;
 
-       file_fd = lttng_get_unused_fd();
+       file_fd = get_unused_fd_flags(0);
        if (file_fd < 0) {
                ret = file_fd;
                goto fd_error;
@@ -213,7 +223,7 @@ int lttng_abi_syscall_list(void)
        struct file *syscall_list_file;
        int file_fd, ret;
 
-       file_fd = lttng_get_unused_fd();
+       file_fd = get_unused_fd_flags(0);
        if (file_fd < 0) {
                ret = file_fd;
                goto fd_error;
@@ -491,12 +501,12 @@ int lttng_abi_create_channel(struct file *session_file,
        struct lttng_kernel_session *session = session_file->private_data;
        const struct file_operations *fops = NULL;
        const char *transport_name;
-       struct lttng_channel *chan;
+       struct lttng_kernel_channel_buffer *chan;
        struct file *chan_file;
        int chan_fd;
        int ret = 0;
 
-       chan_fd = lttng_get_unused_fd();
+       chan_fd = get_unused_fd_flags(0);
        if (chan_fd < 0) {
                ret = chan_fd;
                goto fd_error;
@@ -549,7 +559,7 @@ int lttng_abi_create_channel(struct file *session_file,
         * We tolerate no failure path after channel creation. It will stay
         * invariant for the rest of the session.
         */
-       chan = lttng_channel_create(session, transport_name, NULL,
+       chan = lttng_channel_buffer_create(session, transport_name, NULL,
                                  chan_param->subbuf_size,
                                  chan_param->num_subbuf,
                                  chan_param->switch_timer_interval,
@@ -559,7 +569,7 @@ int lttng_abi_create_channel(struct file *session_file,
                ret = -EINVAL;
                goto chan_error;
        }
-       chan->file = chan_file;
+       chan->priv->parent.file = chan_file;
        chan_file->private_data = chan;
        fd_install(chan_fd, chan_file);
 
@@ -612,118 +622,674 @@ int lttng_abi_session_set_creation_time(struct lttng_kernel_session *session,
 static
 int lttng_counter_release(struct inode *inode, struct file *file)
 {
-       struct lttng_counter *counter = file->private_data;
+       struct lttng_kernel_channel_counter *counter = file->private_data;
 
        if (counter) {
                /*
                 * Do not destroy the counter itself. Wait of the owner
                 * (event_notifier group) to be destroyed.
                 */
-               fput(counter->owner);
+               fput(counter->priv->owner);
        }
 
        return 0;
 }
 
 static
-long lttng_counter_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+int copy_user_event_param_ext(struct lttng_kernel_abi_event_ext *event_param_ext,
+                       struct lttng_kernel_abi_event *event_param)
 {
-       struct lttng_counter *counter = file->private_data;
-       size_t indexes[LTTNG_KERNEL_ABI_COUNTER_DIMENSION_MAX] = { 0 };
-       int i;
+       struct lttng_kernel_abi_event_ext __user *uevent_ext =
+               (struct lttng_kernel_abi_event_ext __user *) (unsigned long) event_param->event_ext;
+       uint32_t len;
+       int ret;
 
-       switch (cmd) {
-       case LTTNG_KERNEL_ABI_COUNTER_READ:
+       /* Use zeroed defaults if extension parameters are not set. */
+       if (!uevent_ext)
+               return 0;
+       ret = get_user(len, &uevent_ext->len);
+       if (ret)
+               return ret;
+       if (len > PAGE_SIZE)
+               return -E2BIG;
+       ret = lttng_copy_struct_from_user(event_param_ext, sizeof(*event_param_ext), uevent_ext, len);
+       if (ret)
+               return ret;
+       /* Ensure that len is consistent with the initial get_user(). */
+       event_param_ext->len = len;
+
+       /* Validate that we know of all flags and enum values used. */
+       switch (event_param_ext->match_check) {
+       case LTTNG_KERNEL_ABI_MATCH_DEFAULT:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_MATCH_IMMEDIATE:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_MATCH_LAZY:
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static
+int user_event_param_ext_get_match_check(const struct lttng_kernel_abi_event_ext *event_param_ext,
+               enum lttng_kernel_abi_match_check *_match_check)
+{
+       enum lttng_kernel_abi_match_check match_check = LTTNG_KERNEL_ABI_MATCH_DEFAULT;
+
+       if (event_param_ext->len < offsetofend(struct lttng_kernel_abi_event_ext, match_check))
+               goto end;
+       match_check = event_param_ext->match_check;
+end:
+       *_match_check = match_check;
+       return 0;
+}
+
+static
+int create_counter_key_from_abi_dimensions(struct lttng_kernel_counter_key **_counter_key,
+               uint32_t nr_dimensions, void __user *ptr)
+{
+       struct lttng_kernel_abi_counter_key_dimension __user *udimension;
+       struct lttng_kernel_abi_counter_key_dimension kdimension = {};
+       struct lttng_kernel_counter_key *counter_key = NULL;
+       struct lttng_key_token *token_array = NULL;
+       uint32_t i;
+       int ret = 0;
+
+       if (!nr_dimensions || nr_dimensions > LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS)
+               return -EINVAL;
+       counter_key = kzalloc(sizeof(*counter_key), GFP_KERNEL);
+       if (!counter_key)
+               return -ENOMEM;
+       counter_key->nr_dimensions = nr_dimensions;
+       /* Only a single dimension is supported. */
+       if (WARN_ON_ONCE(nr_dimensions != 1)) {
+               ret = -EINVAL;
+               goto error;
+       }
+       udimension = (struct lttng_kernel_abi_counter_key_dimension __user *)ptr;
+       ret = lttng_copy_struct_from_user(&kdimension, sizeof(kdimension), udimension, sizeof(*udimension));
+       if (ret)
+               goto error;
+       if (kdimension.len > PAGE_SIZE) {
+               ret = -E2BIG;
+               goto error;
+       }
+       switch (kdimension.key_type) {
+       case LTTNG_KERNEL_ABI_KEY_TYPE_TOKENS:
        {
-               struct lttng_kernel_abi_counter_read local_counter_read;
-               struct lttng_kernel_abi_counter_read __user *ucounter_read =
-                               (struct lttng_kernel_abi_counter_read __user *) arg;
-               bool overflow, underflow;
-               int64_t value;
-               int32_t cpu;
-               int ret;
+               struct lttng_kernel_abi_counter_key_dimension_tokens kdimension_tokens = {};
+               struct lttng_kernel_abi_counter_key_dimension_tokens __user *udimension_tokens;
+               struct lttng_kernel_abi_key_token __user *utoken;
+               uint32_t nr_tokens;
+
+               udimension_tokens = (struct lttng_kernel_abi_counter_key_dimension_tokens __user *)ptr;
+               ret = lttng_copy_struct_from_user(&kdimension_tokens, sizeof(kdimension_tokens),
+                               udimension_tokens, kdimension.len);
+               if (ret)
+                       goto error;
+               nr_tokens = kdimension_tokens.nr_key_tokens;
+               if (nr_tokens > LTTNG_KERNEL_COUNTER_MAX_TOKENS) {
+                       ret = -EINVAL;
+                       goto error;
+               }
+               token_array = kzalloc(nr_tokens * sizeof(*token_array), GFP_KERNEL);
+               if (!token_array) {
+                       ret = -ENOMEM;
+                       goto error;
+               }
+               counter_key->dimension_array[0].token_array = token_array;
+               counter_key->dimension_array[0].nr_key_tokens = nr_tokens;
+               utoken = (struct lttng_kernel_abi_key_token __user *)((unsigned long)ptr + kdimension.len);
+               for (i = 0; i < nr_tokens; i++) {
+                       struct lttng_kernel_abi_key_token ktoken = {};
+                       struct lttng_key_token *key_token = &token_array[i];
+                       uint32_t token_len = 0;
+
+                       ret = lttng_copy_struct_from_user(&ktoken, sizeof(ktoken), utoken, sizeof(*utoken));
+                       if (ret)
+                               goto error;
+                       token_len += ktoken.len;
+                       switch (ktoken.type) {
+                       case LTTNG_KERNEL_ABI_KEY_TOKEN_STRING:
+                       {
+                               struct lttng_kernel_abi_key_token_string __user *utoken_string;
+                               struct lttng_kernel_abi_key_token_string *ktoken_string;
+                               char __user *string_ptr;
+                               size_t string_len;
+
+                               utoken_string = (struct lttng_kernel_abi_key_token_string __user *) utoken;
+                               ret = lttng_copy_struct_from_user(&ktoken_string, sizeof(ktoken_string),
+                                               utoken_string, ktoken.len);
+                               if (ret)
+                                       goto error;
+                               string_ptr = (char __user *) ((unsigned long)utoken_string + ktoken.len);
+                               string_len = ktoken_string->string_len;
+                               key_token->type = LTTNG_KEY_TOKEN_STRING;
+                               if (!string_len || string_len > PAGE_SIZE) {
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+                               key_token->str = kzalloc(string_len, GFP_KERNEL);
+                               if (!key_token->str) {
+                                       ret = -ENOMEM;
+                                       goto error;
+                               }
+                               ret = copy_from_user(key_token->str, string_ptr, string_len);
+                               if (ret)
+                                       goto error;
+                               if (key_token->str[string_len - 1] != '\0') {
+                                       ret = -EINVAL;
+                                       goto error;
+                               }
+                               token_len += string_len;
+                               break;
+                       }
+                       case LTTNG_KERNEL_ABI_KEY_TOKEN_EVENT_NAME:
+                               key_token->type = LTTNG_KEY_TOKEN_EVENT_NAME;
+                               break;
+
+                       case LTTNG_KERNEL_ABI_KEY_TOKEN_PROVIDER_NAME:
+                               lttng_fallthrough;
+                       default:
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       utoken = (struct lttng_kernel_abi_key_token __user *)((unsigned long)utoken + token_len);
+               }
 
-               if (copy_from_user(&local_counter_read, ucounter_read,
-                                       sizeof(local_counter_read)))
-                       return -EFAULT;
-               if (validate_zeroed_padding(local_counter_read.padding,
-                               sizeof(local_counter_read.padding)))
-                       return -EINVAL;
+               break;
+       }
+       case LTTNG_KERNEL_ABI_KEY_TYPE_INTEGER:
+       default:
+               ret = -EINVAL;
+               goto error;
+       }
+       *_counter_key = counter_key;
+       return 0;
+
+error:
+       destroy_counter_key(counter_key);
+       return ret;
+}
+
+int create_counter_key_from_kernel(struct lttng_kernel_counter_key **_new_key,
+               const struct lttng_kernel_counter_key *src_key)
+{
+       struct lttng_kernel_counter_key *new_key;
+       int i, ret = 0;
+
+       new_key = kzalloc(sizeof(*new_key), GFP_KERNEL);
+       if (!new_key)
+               return -ENOMEM;
+       new_key->nr_dimensions = src_key->nr_dimensions;
+       for (i = 0; i < src_key->nr_dimensions; i++) {
+               struct lttng_kernel_counter_key_dimension *new_dimension = &new_key->dimension_array[i];
+               const struct lttng_kernel_counter_key_dimension *src_dimension = &src_key->dimension_array[i];
+               uint32_t nr_tokens = src_dimension->nr_key_tokens;
+               int j;
+
+               new_dimension->nr_key_tokens = nr_tokens;
+               new_dimension->token_array = kzalloc(nr_tokens * sizeof(*new_dimension->token_array), GFP_KERNEL);
+               if (!new_dimension->token_array) {
+                       ret = -ENOMEM;
+                       goto error;
+               }
+               for (j = 0; j < nr_tokens; j++) {
+                       struct lttng_key_token *new_key_token = &new_dimension->token_array[j];
+                       struct lttng_key_token *src_key_token = &src_dimension->token_array[j];
+
+                       switch (src_key_token->type) {
+                       case LTTNG_KEY_TOKEN_STRING:
+                               new_key_token->type = LTTNG_KEY_TOKEN_STRING;
+                               new_key_token->str = kstrdup(src_key_token->str, GFP_KERNEL);
+                               if (!new_key_token->str) {
+                                       ret = -ENOMEM;
+                                       goto error;
+                               }
+                               break;
+                       case LTTNG_KEY_TOKEN_EVENT_NAME:
+                               new_key_token->type = LTTNG_KEY_TOKEN_EVENT_NAME;
+                               break;
+
+                       default:
+                               ret = -EINVAL;
+                               goto error;
+                       }
+               }
+       }
+       *_new_key = new_key;
+       return 0;
+
+error:
+       destroy_counter_key(new_key);
+       return ret;
+}
+
+void destroy_counter_key(struct lttng_kernel_counter_key *counter_key)
+{
+       int i;
+
+       if (!counter_key)
+               return;
+       for (i = 0; i < counter_key->nr_dimensions; i++) {
+               struct lttng_kernel_counter_key_dimension *dimension = &counter_key->dimension_array[i];
+               uint32_t nr_tokens = dimension->nr_key_tokens;
+               int j;
+
+               for (j = 0; j < nr_tokens; j++) {
+                       struct lttng_key_token *key_token = &dimension->token_array[j];
+
+                       switch (key_token->type) {
+                       case LTTNG_KEY_TOKEN_STRING:
+                               kfree(key_token->str);
+                               break;
+
+                       case LTTNG_KEY_TOKEN_EVENT_NAME:
+                               lttng_fallthrough;
+                       case LTTNG_KEY_TOKEN_UNKNOWN:
+                               break;
+
+                       default:
+                               WARN_ON_ONCE(1);
+                       }
+               }
+               kfree(dimension->token_array);
+       }
+       kfree(counter_key);
+}
+
+static
+long lttng_counter_ioctl_abi_old_counter_read(struct lttng_kernel_channel_counter *counter,
+               unsigned int cmd, unsigned long arg)
+{
+       size_t indexes[LTTNG_KERNEL_ABI_OLD_COUNTER_DIMENSION_MAX] = {};
+       struct lttng_kernel_abi_old_counter_read local_counter_read;
+       struct lttng_kernel_abi_old_counter_read __user *ucounter_read =
+                       (struct lttng_kernel_abi_old_counter_read __user *) arg;
+       bool overflow, underflow;
+       int64_t value;
+       int32_t cpu;
+       int ret, i;
+
+       if (copy_from_user(&local_counter_read, ucounter_read,
+                               sizeof(local_counter_read)))
+               return -EFAULT;
+       if (validate_zeroed_padding(local_counter_read.padding,
+                       sizeof(local_counter_read.padding)))
+               return -EINVAL;
+       if (local_counter_read.index.number_dimensions > LTTNG_KERNEL_ABI_OLD_COUNTER_DIMENSION_MAX)
+               return -EINVAL;
+       /* Cast all indexes into size_t. */
+       for (i = 0; i < local_counter_read.index.number_dimensions; i++)
+               indexes[i] = local_counter_read.index.dimension_indexes[i];
+       cpu = local_counter_read.cpu;
+
+       ret = lttng_kernel_counter_read(counter, indexes, cpu, &value, &overflow, &underflow);
+       if (ret)
+               return ret;
+       local_counter_read.value.value = value;
+       local_counter_read.value.overflow = overflow;
+       local_counter_read.value.underflow = underflow;
+
+       if (copy_to_user(&ucounter_read->value, &local_counter_read.value,
+                               sizeof(local_counter_read.value)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static
+long lttng_counter_ioctl_abi_old_counter_aggregate(struct lttng_kernel_channel_counter *counter,
+               unsigned int cmd, unsigned long arg)
+{
+       size_t indexes[LTTNG_KERNEL_ABI_OLD_COUNTER_DIMENSION_MAX] = {};
+       struct lttng_kernel_abi_old_counter_aggregate local_counter_aggregate;
+       struct lttng_kernel_abi_old_counter_aggregate __user *ucounter_aggregate =
+                       (struct lttng_kernel_abi_old_counter_aggregate __user *) arg;
+       bool overflow, underflow;
+       int64_t value;
+       int ret, i;
+
+       if (copy_from_user(&local_counter_aggregate, ucounter_aggregate,
+                               sizeof(local_counter_aggregate)))
+               return -EFAULT;
+       if (validate_zeroed_padding(local_counter_aggregate.padding,
+                       sizeof(local_counter_aggregate.padding)))
+               return -EINVAL;
+       if (local_counter_aggregate.index.number_dimensions > LTTNG_KERNEL_ABI_OLD_COUNTER_DIMENSION_MAX)
+               return -EINVAL;
+       /* Cast all indexes into size_t. */
+       for (i = 0; i < local_counter_aggregate.index.number_dimensions; i++)
+               indexes[i] = local_counter_aggregate.index.dimension_indexes[i];
 
-               /* Cast all indexes into size_t. */
-               for (i = 0; i < local_counter_read.index.number_dimensions; i++)
-                       indexes[i] = (size_t) local_counter_read.index.dimension_indexes[i];
-               cpu = local_counter_read.cpu;
+       ret = lttng_kernel_counter_aggregate(counter, indexes, &value, &overflow, &underflow);
+       if (ret)
+               return ret;
+       local_counter_aggregate.value.value = value;
+       local_counter_aggregate.value.overflow = overflow;
+       local_counter_aggregate.value.underflow = underflow;
 
-               ret = lttng_kernel_counter_read(counter, indexes, cpu, &value,
-                               &overflow, &underflow);
+       if (copy_to_user(&ucounter_aggregate->value, &local_counter_aggregate.value,
+                               sizeof(local_counter_aggregate.value)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static
+long lttng_counter_ioctl_abi_old_counter_clear(struct lttng_kernel_channel_counter *counter,
+               unsigned int cmd, unsigned long arg)
+{
+       size_t indexes[LTTNG_KERNEL_ABI_OLD_COUNTER_DIMENSION_MAX] = {};
+       struct lttng_kernel_abi_old_counter_clear local_counter_clear;
+       struct lttng_kernel_abi_old_counter_clear __user *ucounter_clear =
+                       (struct lttng_kernel_abi_old_counter_clear __user *) arg;
+       int i;
+
+       if (copy_from_user(&local_counter_clear, ucounter_clear,
+                               sizeof(local_counter_clear)))
+               return -EFAULT;
+       if (validate_zeroed_padding(local_counter_clear.padding,
+                       sizeof(local_counter_clear.padding)))
+               return -EINVAL;
+       if (local_counter_clear.index.number_dimensions > LTTNG_KERNEL_ABI_OLD_COUNTER_DIMENSION_MAX)
+               return -EINVAL;
+       /* Cast all indexes into size_t. */
+       for (i = 0; i < local_counter_clear.index.number_dimensions; i++)
+               indexes[i] = local_counter_clear.index.dimension_indexes[i];
+       return lttng_kernel_counter_clear(counter, indexes);
+}
+
+static
+long lttng_counter_ioctl_abi_counter_read(struct lttng_kernel_channel_counter *counter,
+               unsigned int cmd, unsigned long arg)
+{
+       size_t indexes[LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS] = {};
+       struct lttng_kernel_abi_counter_read kcounter_read = {};
+       struct lttng_kernel_abi_counter_read __user *ucounter_read =
+                       (struct lttng_kernel_abi_counter_read __user *) arg;
+       uint32_t len, number_dimensions;
+       bool overflow, underflow;
+       int64_t value;
+       int32_t cpu;
+       int ret, i;
+
+       ret = get_user(len, &ucounter_read->len);
+       if (ret)
+               return ret;
+       if (len > PAGE_SIZE)
+               return -E2BIG;
+       if (len < offsetofend(struct lttng_kernel_abi_counter_read, value))
+               return -EINVAL;
+       ret = lttng_copy_struct_from_user(&kcounter_read, sizeof(kcounter_read),
+                       ucounter_read, len);
+       if (ret)
+               return ret;
+       number_dimensions = kcounter_read.index.number_dimensions;
+       if (!number_dimensions || number_dimensions > LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS)
+               return -EINVAL;
+       /* Cast all indexes into size_t. */
+       for (i = 0; i < number_dimensions; i++) {
+               uint64_t __user *ptr = ((uint64_t __user *)(unsigned long)kcounter_read.index.ptr) + i;
+               uint64_t index;
+
+               ret = get_user(index, ptr);
                if (ret)
                        return ret;
-               local_counter_read.value.value = value;
-               local_counter_read.value.overflow = overflow;
-               local_counter_read.value.underflow = underflow;
+               indexes[i] = index;
+       }
+       cpu = kcounter_read.cpu;
+       ret = lttng_kernel_counter_read(counter, indexes, cpu, &value, &overflow, &underflow);
+       if (ret)
+               return ret;
+       kcounter_read.value.value = value;
+       kcounter_read.value.flags |= underflow ? LTTNG_KERNEL_ABI_COUNTER_VALUE_FLAG_UNDERFLOW : 0;
+       kcounter_read.value.flags |= overflow ? LTTNG_KERNEL_ABI_COUNTER_VALUE_FLAG_OVERFLOW : 0;
 
-               if (copy_to_user(&ucounter_read->value, &local_counter_read.value,
-                                       sizeof(local_counter_read.value)))
-                       return -EFAULT;
+       if (copy_to_user(&ucounter_read->value, &kcounter_read.value, sizeof(kcounter_read.value)))
+               return -EFAULT;
 
-               return 0;
+       return 0;
+}
+
+static
+long lttng_counter_ioctl_abi_counter_aggregate(struct lttng_kernel_channel_counter *counter,
+               unsigned int cmd, unsigned long arg)
+{
+       size_t indexes[LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS] = {};
+       struct lttng_kernel_abi_counter_aggregate kcounter_aggregate = {};
+       struct lttng_kernel_abi_counter_aggregate __user *ucounter_aggregate =
+                       (struct lttng_kernel_abi_counter_aggregate __user *) arg;
+       uint32_t len, number_dimensions;
+       bool overflow, underflow;
+       int64_t value;
+       int ret, i;
+
+       ret = get_user(len, &ucounter_aggregate->len);
+       if (ret)
+               return ret;
+       if (len > PAGE_SIZE)
+               return -E2BIG;
+       if (len < offsetofend(struct lttng_kernel_abi_counter_aggregate, value))
+               return -EINVAL;
+       ret = lttng_copy_struct_from_user(&kcounter_aggregate, sizeof(kcounter_aggregate),
+                       ucounter_aggregate, len);
+       if (ret)
+               return ret;
+       number_dimensions = kcounter_aggregate.index.number_dimensions;
+       if (!number_dimensions || number_dimensions > LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS)
+               return -EINVAL;
+       /* Cast all indexes into size_t. */
+       for (i = 0; i < number_dimensions; i++) {
+               uint64_t __user *ptr = ((uint64_t __user *)(unsigned long)kcounter_aggregate.index.ptr) + i;
+               uint64_t index;
+
+               ret = get_user(index, ptr);
+               if (ret)
+                       return ret;
+               indexes[i] = index;
        }
-       case LTTNG_KERNEL_ABI_COUNTER_AGGREGATE:
-       {
-               struct lttng_kernel_abi_counter_aggregate local_counter_aggregate;
-               struct lttng_kernel_abi_counter_aggregate __user *ucounter_aggregate =
-                               (struct lttng_kernel_abi_counter_aggregate __user *) arg;
-               bool overflow, underflow;
-               int64_t value;
-               int ret;
+       ret = lttng_kernel_counter_aggregate(counter, indexes, &value, &overflow, &underflow);
+       if (ret)
+               return ret;
+       kcounter_aggregate.value.value = value;
+       kcounter_aggregate.value.flags |= underflow ? LTTNG_KERNEL_ABI_COUNTER_VALUE_FLAG_UNDERFLOW : 0;
+       kcounter_aggregate.value.flags |= overflow ? LTTNG_KERNEL_ABI_COUNTER_VALUE_FLAG_OVERFLOW : 0;
 
-               if (copy_from_user(&local_counter_aggregate, ucounter_aggregate,
-                                       sizeof(local_counter_aggregate)))
-                       return -EFAULT;
-               if (validate_zeroed_padding(local_counter_aggregate.padding,
-                               sizeof(local_counter_aggregate.padding)))
-                       return -EINVAL;
+       if (copy_to_user(&ucounter_aggregate->value, &kcounter_aggregate.value, sizeof(kcounter_aggregate.value)))
+               return -EFAULT;
 
-               /* Cast all indexes into size_t. */
-               for (i = 0; i < local_counter_aggregate.index.number_dimensions; i++)
-                       indexes[i] = (size_t) local_counter_aggregate.index.dimension_indexes[i];
+       return 0;
+}
 
-               ret = lttng_kernel_counter_aggregate(counter, indexes, &value,
-                               &overflow, &underflow);
+static
+long lttng_counter_ioctl_abi_counter_clear(struct lttng_kernel_channel_counter *counter,
+               unsigned int cmd, unsigned long arg)
+{
+       size_t indexes[LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS] = {};
+       struct lttng_kernel_abi_counter_clear kcounter_clear = {};
+       struct lttng_kernel_abi_counter_clear __user *ucounter_clear =
+                       (struct lttng_kernel_abi_counter_clear __user *) arg;
+       uint32_t len, number_dimensions;
+       int ret, i;
+
+       ret = get_user(len, &ucounter_clear->len);
+       if (ret)
+               return ret;
+       if (len > PAGE_SIZE)
+               return -E2BIG;
+       if (len < offsetofend(struct lttng_kernel_abi_counter_clear, index))
+               return -EINVAL;
+       ret = lttng_copy_struct_from_user(&kcounter_clear, sizeof(kcounter_clear),
+                       ucounter_clear, len);
+       if (ret)
+               return ret;
+       number_dimensions = kcounter_clear.index.number_dimensions;
+       if (!number_dimensions || number_dimensions > LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS)
+               return -EINVAL;
+       /* Cast all indexes into size_t. */
+       for (i = 0; i < number_dimensions; i++) {
+               uint64_t __user *ptr = ((uint64_t __user *)(unsigned long)kcounter_clear.index.ptr) + i;
+               uint64_t index;
+
+               ret = get_user(index, ptr);
                if (ret)
                        return ret;
-               local_counter_aggregate.value.value = value;
-               local_counter_aggregate.value.overflow = overflow;
-               local_counter_aggregate.value.underflow = underflow;
+               indexes[i] = index;
+       }
+       return lttng_kernel_counter_clear(counter, indexes);
+}
 
-               if (copy_to_user(&ucounter_aggregate->value, &local_counter_aggregate.value,
-                                       sizeof(local_counter_aggregate.value)))
-                       return -EFAULT;
+static
+long lttng_counter_ioctl_abi_counter_event(struct file *file,
+               struct lttng_kernel_channel_counter *counter,
+               unsigned int cmd, unsigned long arg)
+{
+       struct lttng_kernel_abi_counter_event __user *ucounter_event =
+                       (struct lttng_kernel_abi_counter_event __user *) arg;
+       struct lttng_kernel_abi_counter_event kcounter_event = {};
+       struct lttng_kernel_counter_event *counter_event;
+       uint32_t len;
+       int ret;
 
-               return 0;
+       ret = get_user(len, &ucounter_event->len);
+       if (ret)
+               return ret;
+       if (len > PAGE_SIZE)
+               return -E2BIG;
+       if (len < offsetofend(struct lttng_kernel_abi_counter_event, number_key_dimensions))
+               return -EINVAL;
+       counter_event = kzalloc(sizeof(*counter_event), GFP_KERNEL);
+       if (!counter_event)
+               return -ENOMEM;
+       ret = lttng_copy_struct_from_user(&kcounter_event, sizeof(kcounter_event),
+                       ucounter_event, len);
+       if (ret)
+               goto end_counter_event;
+       memcpy(&counter_event->event_param, &kcounter_event.event, sizeof(counter_event->event_param));
+       ret = copy_user_event_param_ext(&counter_event->event_param_ext, &kcounter_event.event);
+       if (ret)
+               goto end_counter_event;
+       switch (kcounter_event.action) {
+       case LTTNG_KERNEL_ABI_COUNTER_ACTION_INCREMENT:
+               /* No specific data for this action. */
+               break;
+       default:
+               ret = -EINVAL;
+               goto end_counter_event;
        }
-       case LTTNG_KERNEL_ABI_COUNTER_CLEAR:
-       {
-               struct lttng_kernel_abi_counter_clear local_counter_clear;
-               struct lttng_kernel_abi_counter_clear __user *ucounter_clear =
-                               (struct lttng_kernel_abi_counter_clear __user *) arg;
+       ret = create_counter_key_from_abi_dimensions(&counter_event->counter_key,
+                       kcounter_event.number_key_dimensions,
+                       (void __user *) arg + len);
+       if (ret)
+               goto end_counter_event;
+       ret = lttng_abi_create_event_counter_enabler(file, counter_event);
+       destroy_counter_key(counter_event->counter_key);
+end_counter_event:
+       kfree(counter_event);
+       return ret;
+}
 
-               if (copy_from_user(&local_counter_clear, ucounter_clear,
-                                       sizeof(local_counter_clear)))
-                       return -EFAULT;
-               if (validate_zeroed_padding(local_counter_clear.padding,
-                               sizeof(local_counter_clear.padding)))
-                       return -EINVAL;
+static
+long lttng_counter_ioctl_abi_counter_map_descriptor(struct lttng_kernel_channel_counter *counter,
+               unsigned int cmd, unsigned long arg)
+{
+       struct lttng_kernel_abi_counter_map_descriptor __user *udescriptor =
+               (struct lttng_kernel_abi_counter_map_descriptor __user *) arg;
+       struct lttng_kernel_abi_counter_map_descriptor kdescriptor = {};
+       struct lttng_counter_map_descriptor *descriptor;
+       char key[LTTNG_KERNEL_COUNTER_KEY_LEN] = {};
+       uint64_t array_indexes[1];
+       size_t key_strlen;
+       uint32_t len;
+       int ret;
 
-               /* Cast all indexes into size_t. */
-               for (i = 0; i < local_counter_clear.index.number_dimensions; i++)
-                       indexes[i] = (size_t) local_counter_clear.index.dimension_indexes[i];
+       ret = get_user(len, &udescriptor->len);
+       if (ret)
+               return ret;
+       if (len > PAGE_SIZE)
+               return -E2BIG;
+       if (len < offsetofend(struct lttng_kernel_abi_counter_map_descriptor, array_indexes_len))
+               return -EINVAL;
+       ret = lttng_copy_struct_from_user(&kdescriptor, sizeof(kdescriptor), udescriptor, len);
+       if (ret)
+               return ret;
+       mutex_lock(&counter->priv->map.lock);
+       if (kdescriptor.descriptor_index >= counter->priv->map.nr_descriptors) {
+               ret = -EOVERFLOW;
+               goto map_descriptor_error_unlock;
+       }
+       if (kdescriptor.array_indexes_len < 1) {
+               ret = -EINVAL;
+               goto map_descriptor_error_unlock;
+       }
+       kdescriptor.array_indexes_len = 1;
+       descriptor = &counter->priv->map.descriptors[kdescriptor.descriptor_index];
+       kdescriptor.dimension = 0;
+       kdescriptor.user_token = descriptor->user_token;
+       memcpy(&key, descriptor->key, LTTNG_KERNEL_COUNTER_KEY_LEN);
+       array_indexes[0] = descriptor->array_index;
+       mutex_unlock(&counter->priv->map.lock);
+
+       key_strlen = strlen(key) + 1;
+       if (kdescriptor.key_string_len < key_strlen)
+               return -ENOSPC;
+       kdescriptor.key_string_len = key_strlen;
+       if (copy_to_user((char __user *)(unsigned long)kdescriptor.key_string, key, key_strlen))
+               return -EFAULT;
+       if (copy_to_user((uint64_t __user *)(unsigned long)kdescriptor.array_indexes, array_indexes, sizeof(uint64_t)))
+               return -EFAULT;
+       if (copy_to_user(udescriptor, &kdescriptor, min(sizeof(kdescriptor), (size_t)len)))
+               return -EFAULT;
+       return 0;
 
-               return lttng_kernel_counter_clear(counter, indexes);
+map_descriptor_error_unlock:
+       mutex_unlock(&counter->priv->map.lock);
+       return ret;
+}
+
+static
+long lttng_counter_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct lttng_kernel_channel_counter *counter = file->private_data;
+
+       switch (cmd) {
+       case LTTNG_KERNEL_ABI_OLD_COUNTER_READ:
+               return lttng_counter_ioctl_abi_old_counter_read(counter, cmd, arg);
+       case LTTNG_KERNEL_ABI_OLD_COUNTER_AGGREGATE:
+               return lttng_counter_ioctl_abi_old_counter_aggregate(counter, cmd, arg);
+       case LTTNG_KERNEL_ABI_OLD_COUNTER_CLEAR:
+               return lttng_counter_ioctl_abi_old_counter_clear(counter, cmd, arg);
+       case LTTNG_KERNEL_ABI_COUNTER_READ:
+               return lttng_counter_ioctl_abi_counter_read(counter, cmd, arg);
+       case LTTNG_KERNEL_ABI_COUNTER_AGGREGATE:
+               return lttng_counter_ioctl_abi_counter_aggregate(counter, cmd, arg);
+       case LTTNG_KERNEL_ABI_COUNTER_CLEAR:
+               return lttng_counter_ioctl_abi_counter_clear(counter, cmd, arg);
+       case LTTNG_KERNEL_ABI_COUNTER_EVENT:
+               return lttng_counter_ioctl_abi_counter_event(file, counter, cmd, arg);
+       case LTTNG_KERNEL_ABI_ENABLE:
+               return lttng_channel_enable(&counter->parent);
+       case LTTNG_KERNEL_ABI_DISABLE:
+               return lttng_channel_disable(&counter->parent);
+       case LTTNG_KERNEL_ABI_SYSCALL_MASK:
+               return lttng_syscall_table_get_active_mask(&counter->priv->parent.syscall_table,
+                       (struct lttng_kernel_abi_syscall_mask __user *) arg);
+       case LTTNG_KERNEL_ABI_COUNTER_MAP_NR_DESCRIPTORS:
+       {
+               uint64_t __user *user_nr_descriptors = (uint64_t __user *) arg;
+               uint64_t nr_descriptors;
+
+               mutex_lock(&counter->priv->map.lock);
+               nr_descriptors = counter->priv->map.nr_descriptors;
+               mutex_unlock(&counter->priv->map.lock);
+               return put_user(nr_descriptors, user_nr_descriptors);
        }
+       case LTTNG_KERNEL_ABI_COUNTER_MAP_DESCRIPTOR:
+               return lttng_counter_ioctl_abi_counter_map_descriptor(counter, cmd, arg);
        default:
-               WARN_ON_ONCE(1);
                return -ENOSYS;
        }
 }
@@ -759,6 +1325,130 @@ enum tracker_type get_tracker_type(struct lttng_kernel_abi_tracker_args *tracker
        }
 }
 
+static
+int lttng_abi_copy_user_old_counter_conf(struct lttng_kernel_counter_conf *counter_conf,
+               struct lttng_kernel_abi_old_counter_conf __user *old_ucounter_conf)
+{
+       struct lttng_kernel_abi_old_counter_conf old_kcounter_conf;
+       struct lttng_kernel_counter_dimension *dimension;
+       int ret;
+
+       memset(counter_conf, 0, sizeof(*counter_conf));
+       ret = copy_from_user(&old_kcounter_conf, old_ucounter_conf,
+                       sizeof(old_kcounter_conf));
+       if (ret)
+               return ret;
+       if (!old_kcounter_conf.number_dimensions ||
+                       old_kcounter_conf.number_dimensions > LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS)
+               return -EINVAL;
+       switch (old_kcounter_conf.arithmetic) {
+       case LTTNG_KERNEL_ABI_COUNTER_ARITHMETIC_MODULAR:
+               counter_conf->arithmetic = LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR;
+               break;
+       default:
+               return -EINVAL;
+       }
+       switch (old_kcounter_conf.bitness) {
+       case LTTNG_KERNEL_ABI_COUNTER_BITNESS_32:
+               counter_conf->bitness = LTTNG_KERNEL_COUNTER_BITNESS_32;
+               break;
+       case LTTNG_KERNEL_ABI_COUNTER_BITNESS_64:
+               counter_conf->bitness = LTTNG_KERNEL_COUNTER_BITNESS_64;
+               break;
+       default:
+               return -EINVAL;
+       }
+       counter_conf->global_sum_step = old_kcounter_conf.global_sum_step;
+       counter_conf->flags |= old_kcounter_conf.coalesce_hits ?
+                                       LTTNG_KERNEL_COUNTER_CONF_FLAG_COALESCE_HITS : 0;
+       dimension = &counter_conf->dimension_array[0];
+       dimension->flags |= old_kcounter_conf.dimensions[0].has_underflow ?
+                                       LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_UNDERFLOW : 0;
+       dimension->flags |= old_kcounter_conf.dimensions[0].has_overflow ?
+                                       LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_OVERFLOW : 0;
+       dimension->size = old_kcounter_conf.dimensions[0].size;
+       dimension->underflow_index = old_kcounter_conf.dimensions[0].underflow_index;
+       dimension->overflow_index = old_kcounter_conf.dimensions[0].overflow_index;
+       return 0;
+}
+
+static
+int lttng_abi_copy_user_counter_conf(struct lttng_kernel_counter_conf *counter_conf,
+               struct lttng_kernel_abi_counter_conf __user *ucounter_conf)
+{
+       uint32_t len, number_dimensions;
+       struct lttng_kernel_abi_counter_conf kcounter_conf = {};
+       struct lttng_kernel_counter_dimension *dimension;
+       struct lttng_kernel_abi_counter_dimension kdimension = {};
+       struct lttng_kernel_abi_counter_dimension __user *udimension;
+       int ret;
+
+       memset(counter_conf, 0, sizeof(*counter_conf));
+       ret = get_user(len, &ucounter_conf->len);
+       if (ret)
+               return ret;
+       if (len < offsetofend(struct lttng_kernel_abi_counter_conf, dimension_array))
+               return -EINVAL;
+       if (len > PAGE_SIZE)
+               return -EINVAL;
+
+       ret = lttng_copy_struct_from_user(&kcounter_conf, sizeof(kcounter_conf), ucounter_conf, len);
+       if (ret)
+               return ret;
+
+       /* Validate flags and enumerations */
+       switch (kcounter_conf.arithmetic) {
+       case LTTNG_KERNEL_ABI_COUNTER_ARITHMETIC_MODULAR:
+               counter_conf->arithmetic = LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR;
+               break;
+       default:
+               return -EINVAL;
+       }
+       switch (kcounter_conf.bitness) {
+       case LTTNG_KERNEL_ABI_COUNTER_BITNESS_32:
+               counter_conf->bitness = LTTNG_KERNEL_COUNTER_BITNESS_32;
+               break;
+       case LTTNG_KERNEL_ABI_COUNTER_BITNESS_64:
+               counter_conf->bitness = LTTNG_KERNEL_COUNTER_BITNESS_64;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (kcounter_conf.flags & ~LTTNG_KERNEL_ABI_COUNTER_CONF_FLAG_COALESCE_HITS)
+               return -EINVAL;
+       counter_conf->global_sum_step = kcounter_conf.global_sum_step;
+       counter_conf->flags |= (kcounter_conf.flags & LTTNG_KERNEL_ABI_COUNTER_CONF_FLAG_COALESCE_HITS) ?
+                                       LTTNG_KERNEL_COUNTER_CONF_FLAG_COALESCE_HITS : 0;
+
+       number_dimensions = kcounter_conf.dimension_array.number_dimensions;
+       if (!number_dimensions || number_dimensions > LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS)
+               return -EINVAL;
+       dimension = &counter_conf->dimension_array[0];
+       len = kcounter_conf.dimension_array.elem_len;
+       if (len > PAGE_SIZE)
+               return -E2BIG;
+       if (len < offsetofend(struct lttng_kernel_abi_counter_dimension, overflow_index))
+               return -EINVAL;
+       udimension = (struct lttng_kernel_abi_counter_dimension __user *)(unsigned long)kcounter_conf.dimension_array.ptr;
+       ret = lttng_copy_struct_from_user(&kdimension, sizeof(kdimension), udimension, len);
+       if (ret)
+               return ret;
+
+       /* Validate flags */
+       if (kdimension.flags & ~(LTTNG_KERNEL_ABI_COUNTER_DIMENSION_FLAG_UNDERFLOW |
+                                       LTTNG_KERNEL_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW))
+               return -EINVAL;
+
+       dimension->flags |= (kdimension.flags & LTTNG_KERNEL_ABI_COUNTER_DIMENSION_FLAG_UNDERFLOW) ?
+                                       LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_UNDERFLOW : 0;
+       dimension->flags |= (kdimension.flags & LTTNG_KERNEL_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW) ?
+                                       LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_OVERFLOW : 0;
+       dimension->size = kdimension.size;
+       dimension->underflow_index = kdimension.underflow_index;
+       dimension->overflow_index = kdimension.overflow_index;
+       return 0;
+}
+
 /**
  *     lttng_session_ioctl - lttng session fd ioctl
  *
@@ -792,6 +1482,7 @@ long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        struct lttng_kernel_session *session = file->private_data;
        struct lttng_kernel_abi_channel chan_param;
        struct lttng_kernel_abi_old_channel old_chan_param;
+       int ret;
 
        /*
         * Handle backward compatibility. OLD commands have wrong
@@ -958,6 +1649,16 @@ long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        return -EFAULT;
                return lttng_abi_session_set_creation_time(session, &time);
        }
+       case LTTNG_KERNEL_ABI_COUNTER:
+       {
+               struct lttng_kernel_counter_conf counter_conf;
+
+               ret = lttng_abi_copy_user_counter_conf(&counter_conf,
+                               (struct lttng_kernel_abi_counter_conf __user *) arg);
+               if (ret)
+                       return ret;
+               return lttng_abi_session_create_counter(session, &counter_conf);
+       }
        default:
                return -ENOIOCTLCMD;
        }
@@ -999,8 +1700,8 @@ ssize_t lttng_event_notifier_group_notif_read(struct file *filp, char __user *us
                size_t count, loff_t *ppos)
 {
        struct lttng_event_notifier_group *event_notifier_group = filp->private_data;
-       struct channel *chan = event_notifier_group->chan;
-       struct lib_ring_buffer *buf = event_notifier_group->buf;
+       struct lttng_kernel_ring_buffer_channel *chan = event_notifier_group->chan;
+       struct lttng_kernel_ring_buffer *buf = event_notifier_group->buf;
        ssize_t read_count = 0, len;
        size_t read_offset;
 
@@ -1010,7 +1711,7 @@ ssize_t lttng_event_notifier_group_notif_read(struct file *filp, char __user *us
 
        /* Finish copy of previous record */
        if (*ppos != 0) {
-               if (read_count < count) {
+               if (count != 0) {
                        len = chan->iter.len_left;
                        read_offset = *ppos;
                        goto skip_get_next;
@@ -1090,7 +1791,8 @@ nodata:
        chan->iter.len_left = 0;
 
 put_record:
-       lib_ring_buffer_put_current_record(buf);
+       if (*ppos == 0)
+               lib_ring_buffer_put_current_record(buf);
        return read_count;
 }
 
@@ -1105,9 +1807,9 @@ unsigned int lttng_event_notifier_group_notif_poll(struct file *filp,
 {
        unsigned int mask = 0;
        struct lttng_event_notifier_group *event_notifier_group = filp->private_data;
-       struct channel *chan = event_notifier_group->chan;
-       struct lib_ring_buffer *buf = event_notifier_group->buf;
-       const struct lib_ring_buffer_config *config = &chan->backend.config;
+       struct lttng_kernel_ring_buffer_channel *chan = event_notifier_group->chan;
+       struct lttng_kernel_ring_buffer *buf = event_notifier_group->buf;
+       const struct lttng_kernel_ring_buffer_config *config = &chan->backend.config;
        int finalized, disabled;
        unsigned long consumed, offset;
        size_t subbuffer_header_size = config->cb.subbuffer_header_size();
@@ -1179,7 +1881,7 @@ retry:
 static int lttng_event_notifier_group_notif_open(struct inode *inode, struct file *file)
 {
        struct lttng_event_notifier_group *event_notifier_group = inode->i_private;
-       struct lib_ring_buffer *buf = event_notifier_group->buf;
+       struct lttng_kernel_ring_buffer *buf = event_notifier_group->buf;
 
        file->private_data = event_notifier_group;
        return lib_ring_buffer_open(inode, file, buf);
@@ -1195,7 +1897,7 @@ static int lttng_event_notifier_group_notif_open(struct inode *inode, struct fil
 static int lttng_event_notifier_group_notif_release(struct inode *inode, struct file *file)
 {
        struct lttng_event_notifier_group *event_notifier_group = file->private_data;
-       struct lib_ring_buffer *buf = event_notifier_group->buf;
+       struct lttng_kernel_ring_buffer *buf = event_notifier_group->buf;
        int ret;
 
        ret = lib_ring_buffer_release(inode, file, buf);
@@ -1225,7 +1927,7 @@ unsigned int lttng_metadata_ring_buffer_poll(struct file *filp,
                poll_table *wait)
 {
        struct lttng_metadata_stream *stream = filp->private_data;
-       struct lib_ring_buffer *buf = stream->priv;
+       struct lttng_kernel_ring_buffer *buf = stream->priv;
        int finalized;
        unsigned int mask = 0;
 
@@ -1301,7 +2003,7 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp,
 {
        int ret;
        struct lttng_metadata_stream *stream = filp->private_data;
-       struct lib_ring_buffer *buf = stream->priv;
+       struct lttng_kernel_ring_buffer *buf = stream->priv;
        unsigned int rb_cmd;
        bool coherent;
 
@@ -1314,8 +2016,8 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp,
        case LTTNG_KERNEL_ABI_RING_BUFFER_GET_NEXT_SUBBUF:
        {
                struct lttng_metadata_stream *stream = filp->private_data;
-               struct lib_ring_buffer *buf = stream->priv;
-               struct channel *chan = buf->backend.chan;
+               struct lttng_kernel_ring_buffer *buf = stream->priv;
+               struct lttng_kernel_ring_buffer_channel *chan = buf->backend.chan;
 
                ret = lttng_metadata_output_channel(stream, chan, NULL);
                if (ret > 0) {
@@ -1332,12 +2034,13 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp,
                 */
                return -ENOSYS;
        }
-       case LTTNG_KERNEL_ABI_RING_BUFFER_FLUSH_EMPTY:  /* Fall-through. */
+       case LTTNG_KERNEL_ABI_RING_BUFFER_FLUSH_EMPTY:
+               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_RING_BUFFER_FLUSH:
        {
                struct lttng_metadata_stream *stream = filp->private_data;
-               struct lib_ring_buffer *buf = stream->priv;
-               struct channel *chan = buf->backend.chan;
+               struct lttng_kernel_ring_buffer *buf = stream->priv;
+               struct lttng_kernel_ring_buffer_channel *chan = buf->backend.chan;
 
                /*
                 * Before doing the actual ring buffer flush, write up to one
@@ -1363,8 +2066,8 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp,
        case LTTNG_KERNEL_ABI_RING_BUFFER_GET_NEXT_SUBBUF_METADATA_CHECK:
        {
                struct lttng_metadata_stream *stream = filp->private_data;
-               struct lib_ring_buffer *buf = stream->priv;
-               struct channel *chan = buf->backend.chan;
+               struct lttng_kernel_ring_buffer *buf = stream->priv;
+               struct lttng_kernel_ring_buffer_channel *chan = buf->backend.chan;
 
                ret = lttng_metadata_output_channel(stream, chan, &coherent);
                if (ret > 0) {
@@ -1410,7 +2113,7 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp,
 {
        int ret;
        struct lttng_metadata_stream *stream = filp->private_data;
-       struct lib_ring_buffer *buf = stream->priv;
+       struct lttng_kernel_ring_buffer *buf = stream->priv;
        unsigned int rb_cmd;
        bool coherent;
 
@@ -1423,8 +2126,8 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp,
        case LTTNG_KERNEL_ABI_RING_BUFFER_GET_NEXT_SUBBUF:
        {
                struct lttng_metadata_stream *stream = filp->private_data;
-               struct lib_ring_buffer *buf = stream->priv;
-               struct channel *chan = buf->backend.chan;
+               struct lttng_kernel_ring_buffer *buf = stream->priv;
+               struct lttng_kernel_ring_buffer_channel *chan = buf->backend.chan;
 
                ret = lttng_metadata_output_channel(stream, chan, NULL);
                if (ret > 0) {
@@ -1441,12 +2144,13 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp,
                 */
                return -ENOSYS;
        }
-       case LTTNG_KERNEL_ABI_RING_BUFFER_FLUSH_EMPTY:  /* Fall-through. */
+       case LTTNG_KERNEL_ABI_RING_BUFFER_FLUSH_EMPTY:
+               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_RING_BUFFER_FLUSH:
        {
                struct lttng_metadata_stream *stream = filp->private_data;
-               struct lib_ring_buffer *buf = stream->priv;
-               struct channel *chan = buf->backend.chan;
+               struct lttng_kernel_ring_buffer *buf = stream->priv;
+               struct lttng_kernel_ring_buffer_channel *chan = buf->backend.chan;
 
                /*
                 * Before doing the actual ring buffer flush, write up to one
@@ -1472,8 +2176,8 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp,
        case LTTNG_KERNEL_ABI_RING_BUFFER_GET_NEXT_SUBBUF_METADATA_CHECK:
        {
                struct lttng_metadata_stream *stream = filp->private_data;
-               struct lib_ring_buffer *buf = stream->priv;
-               struct channel *chan = buf->backend.chan;
+               struct lttng_kernel_ring_buffer *buf = stream->priv;
+               struct lttng_kernel_ring_buffer_channel *chan = buf->backend.chan;
 
                ret = lttng_metadata_output_channel(stream, chan, &coherent);
                if (ret > 0) {
@@ -1521,7 +2225,7 @@ static
 int lttng_metadata_ring_buffer_open(struct inode *inode, struct file *file)
 {
        struct lttng_metadata_stream *stream = inode->i_private;
-       struct lib_ring_buffer *buf = stream->priv;
+       struct lttng_kernel_ring_buffer *buf = stream->priv;
 
        file->private_data = buf;
        /*
@@ -1539,10 +2243,10 @@ static
 int lttng_metadata_ring_buffer_release(struct inode *inode, struct file *file)
 {
        struct lttng_metadata_stream *stream = file->private_data;
-       struct lib_ring_buffer *buf = stream->priv;
+       struct lttng_kernel_ring_buffer *buf = stream->priv;
 
        mutex_lock(&stream->metadata_cache->lock);
-       list_del(&stream->list);
+       list_del(&stream->node);
        mutex_unlock(&stream->metadata_cache->lock);
        kref_put(&stream->metadata_cache->refcount, metadata_cache_destroy);
        module_put(stream->transport->owner);
@@ -1556,7 +2260,7 @@ ssize_t lttng_metadata_ring_buffer_splice_read(struct file *in, loff_t *ppos,
                unsigned int flags)
 {
        struct lttng_metadata_stream *stream = in->private_data;
-       struct lib_ring_buffer *buf = stream->priv;
+       struct lttng_kernel_ring_buffer *buf = stream->priv;
 
        return lib_ring_buffer_splice_read(in, ppos, pipe, len,
                        flags, buf);
@@ -1567,7 +2271,7 @@ int lttng_metadata_ring_buffer_mmap(struct file *filp,
                struct vm_area_struct *vma)
 {
        struct lttng_metadata_stream *stream = filp->private_data;
-       struct lib_ring_buffer *buf = stream->priv;
+       struct lttng_kernel_ring_buffer *buf = stream->priv;
 
        return lib_ring_buffer_mmap(filp, vma, buf);
 }
@@ -1594,7 +2298,7 @@ int lttng_abi_create_stream_fd(struct file *channel_file, void *stream_priv,
        int stream_fd, ret;
        struct file *stream_file;
 
-       stream_fd = lttng_get_unused_fd();
+       stream_fd = get_unused_fd_flags(0);
        if (stream_fd < 0) {
                ret = stream_fd;
                goto fd_error;
@@ -1627,12 +2331,12 @@ fd_error:
 static
 int lttng_abi_open_stream(struct file *channel_file)
 {
-       struct lttng_channel *channel = channel_file->private_data;
-       struct lib_ring_buffer *buf;
+       struct lttng_kernel_channel_buffer *channel = channel_file->private_data;
+       struct lttng_kernel_ring_buffer *buf;
        int ret;
        void *stream_priv;
 
-       buf = channel->ops->priv->buffer_read_open(channel->chan);
+       buf = channel->ops->priv->buffer_read_open(channel->priv->rb_chan);
        if (!buf)
                return -ENOENT;
 
@@ -1653,14 +2357,14 @@ fd_error:
 static
 int lttng_abi_open_metadata_stream(struct file *channel_file)
 {
-       struct lttng_channel *channel = channel_file->private_data;
-       struct lttng_kernel_session *session = channel->session;
-       struct lib_ring_buffer *buf;
+       struct lttng_kernel_channel_buffer *channel = channel_file->private_data;
+       struct lttng_kernel_session *session = channel->parent.session;
+       struct lttng_kernel_ring_buffer *buf;
        int ret;
        struct lttng_metadata_stream *metadata_stream;
        void *stream_priv;
 
-       buf = channel->ops->priv->buffer_read_open(channel->chan);
+       buf = channel->ops->priv->buffer_read_open(channel->priv->rb_chan);
        if (!buf)
                return -ENOENT;
 
@@ -1674,7 +2378,7 @@ int lttng_abi_open_metadata_stream(struct file *channel_file)
        init_waitqueue_head(&metadata_stream->read_wait);
        metadata_stream->priv = buf;
        stream_priv = metadata_stream;
-       metadata_stream->transport = channel->transport;
+       metadata_stream->transport = channel->priv->transport;
        /* Initial state is an empty metadata, considered as incoherent. */
        metadata_stream->coherent = false;
 
@@ -1700,7 +2404,7 @@ int lttng_abi_open_metadata_stream(struct file *channel_file)
                goto fd_error;
 
        mutex_lock(&session->priv->metadata_cache->lock);
-       list_add(&metadata_stream->list,
+       list_add(&metadata_stream->node,
                &session->priv->metadata_cache->metadata_stream);
        mutex_unlock(&session->priv->metadata_cache->lock);
        return ret;
@@ -1720,8 +2424,8 @@ static
 int lttng_abi_open_event_notifier_group_stream(struct file *notif_file)
 {
        struct lttng_event_notifier_group *event_notifier_group = notif_file->private_data;
-       struct channel *chan = event_notifier_group->chan;
-       struct lib_ring_buffer *buf;
+       struct lttng_kernel_ring_buffer_channel *chan = event_notifier_group->chan;
+       struct lttng_kernel_ring_buffer *buf;
        int ret;
        void *stream_priv;
 
@@ -1751,64 +2455,345 @@ refcount_error:
        return ret;
 }
 
-static
-int lttng_abi_validate_event_param(struct lttng_kernel_abi_event *event_param)
-{
-       /* Limit ABI to implemented features. */
+static
+int lttng_abi_validate_event_param(struct lttng_kernel_abi_event *event_param,
+               struct lttng_kernel_abi_event_ext *event_param_ext)
+{
+       enum lttng_kernel_abi_match_check match_check;
+
+       if (user_event_param_ext_get_match_check(event_param_ext, &match_check))
+               return -EINVAL;
+
+       /* Limit ABI to implemented features. */
+       switch (event_param->instrumentation) {
+       case LTTNG_KERNEL_ABI_SYSCALL:
+               switch (event_param->u.syscall.entryexit) {
+               case LTTNG_KERNEL_ABI_SYSCALL_ENTRYEXIT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_SYSCALL_ENTRY:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_SYSCALL_EXIT:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               switch (event_param->u.syscall.abi) {
+               case LTTNG_KERNEL_ABI_SYSCALL_ABI_ALL:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               switch (event_param->u.syscall.match) {
+               case LTTNG_KERNEL_ABI_SYSCALL_MATCH_NAME:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               switch (match_check) {
+               case LTTNG_KERNEL_ABI_MATCH_DEFAULT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_MATCH_LAZY:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case LTTNG_KERNEL_ABI_KRETPROBE:
+               switch (event_param->u.kretprobe.entryexit) {
+               case LTTNG_KERNEL_ABI_KRETPROBE_ENTRYEXIT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_KRETPROBE_ENTRY:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_KRETPROBE_EXIT:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               switch (match_check) {
+               case LTTNG_KERNEL_ABI_MATCH_DEFAULT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_MATCH_IMMEDIATE:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case LTTNG_KERNEL_ABI_TRACEPOINT:
+               switch (match_check) {
+               case LTTNG_KERNEL_ABI_MATCH_DEFAULT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_MATCH_LAZY:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case LTTNG_KERNEL_ABI_KPROBE:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_UPROBE:
+               switch (match_check) {
+               case LTTNG_KERNEL_ABI_MATCH_DEFAULT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_MATCH_IMMEDIATE:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+
+       case LTTNG_KERNEL_ABI_FUNCTION:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_NOOP:
+               lttng_fallthrough;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static
+int lttng_abi_validate_event_match(struct lttng_kernel_abi_event *event_param,
+               struct lttng_kernel_abi_event_ext *event_param_ext)
+{
+       enum lttng_kernel_abi_match_check match_check;
+       int ret;
+
+       if (user_event_param_ext_get_match_check(event_param_ext, &match_check))
+               return -EINVAL;
+
+       /* Validate match */
+       if (match_check == LTTNG_KERNEL_ABI_MATCH_DEFAULT) {
+               switch (event_param->instrumentation) {
+               case LTTNG_KERNEL_ABI_TRACEPOINT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_SYSCALL:
+                       match_check = LTTNG_KERNEL_ABI_MATCH_LAZY;
+                       break;
+               case LTTNG_KERNEL_ABI_KPROBE:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_KRETPROBE:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_UPROBE:
+                       match_check = LTTNG_KERNEL_ABI_MATCH_IMMEDIATE;
+                       break;
+
+               case LTTNG_KERNEL_ABI_FUNCTION:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_NOOP:
+                       lttng_fallthrough;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       if (match_check == LTTNG_KERNEL_ABI_MATCH_IMMEDIATE) {
+               switch (event_param->instrumentation) {
+                       break;
+               case LTTNG_KERNEL_ABI_KPROBE:
+                       ret = lttng_kprobes_match_check(event_param->u.kprobe.symbol_name,
+                                       event_param->u.kprobe.offset,
+                                       event_param->u.kprobe.addr);
+                       if (ret)
+                               return ret;
+                       break;
+               case LTTNG_KERNEL_ABI_KRETPROBE:
+                       ret = lttng_kretprobes_match_check(event_param->u.kretprobe.symbol_name,
+                                       event_param->u.kretprobe.offset,
+                                       event_param->u.kretprobe.addr);
+                       if (ret)
+                               return ret;
+                       break;
+               case LTTNG_KERNEL_ABI_UPROBE:
+                       /*
+                        * uprobes are immediately created, which includes match checking.
+                        */
+                       break;
+
+               case LTTNG_KERNEL_ABI_TRACEPOINT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_SYSCALL:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_FUNCTION:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_NOOP:
+                       lttng_fallthrough;
+               default:
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+static
+int lttng_abi_create_event_recorder_enabler(struct file *channel_file,
+                          struct lttng_kernel_abi_event *event_param,
+                          struct lttng_kernel_abi_event_ext *event_param_ext)
+{
+       const struct file_operations *fops;
+       struct lttng_kernel_channel_buffer *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:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KPROBE:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KRETPROBE:
+               fops = &lttng_event_session_enabler_fops;
+               break;
+
+       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_recorder]",
+                                       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, event_param_ext);
+       if (ret)
+               goto event_error;
+       ret = lttng_abi_validate_event_match(event_param, event_param_ext);
+       if (ret)
+               goto event_error;
+
        switch (event_param->instrumentation) {
+       case LTTNG_KERNEL_ABI_TRACEPOINT:
+               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
-               switch (event_param->u.syscall.entryexit) {
-               case LTTNG_KERNEL_ABI_SYSCALL_ENTRY:    /* Fall-through */
-               case LTTNG_KERNEL_ABI_SYSCALL_EXIT:             /* Fall-through */
-               case LTTNG_KERNEL_ABI_SYSCALL_ENTRYEXIT:
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               switch (event_param->u.syscall.abi) {
-               case LTTNG_KERNEL_ABI_SYSCALL_ABI_ALL:
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               switch (event_param->u.syscall.match) {
-               case LTTNG_KERNEL_ABI_SYSCALL_MATCH_NAME:
-                       break;
-               default:
-                       return -EINVAL;
+       {
+               struct lttng_event_recorder_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_recorder_enabler_create(LTTNG_ENABLER_FORMAT_STAR_GLOB,
+                               event_param, channel);
+               } else {
+                       event_enabler = lttng_event_recorder_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_param, 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:
-               switch (event_param->u.kretprobe.entryexit) {
-               case LTTNG_KERNEL_ABI_SYSCALL_ENTRYEXIT:
-                       break;
-               case LTTNG_KERNEL_ABI_SYSCALL_ENTRY:    /* Fall-through */
-               case LTTNG_KERNEL_ABI_SYSCALL_EXIT:             /* Fall-through */
-               default:
-                       return -EINVAL;
-               }
+       {
+               struct lttng_event_recorder_enabler *event_enabler;
+
+               event_enabler = lttng_event_recorder_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_param, channel);
+               if (event_enabler)
+                       lttng_event_enabler_session_add(channel->parent.session, &event_enabler->parent);
+               priv = event_enabler;
                break;
+       }
 
-       case LTTNG_KERNEL_ABI_TRACEPOINT:       /* Fall-through */
-       case LTTNG_KERNEL_ABI_KPROBE:   /* Fall-through */
        case LTTNG_KERNEL_ABI_UPROBE:
+       {
+               struct lttng_kernel_event_common *event;
+               struct lttng_event_recorder_enabler *event_enabler;
+
+               event_enabler = lttng_event_recorder_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_param, 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, NULL);
+               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: /* Fall-through */
-       case LTTNG_KERNEL_ABI_NOOP:             /* Fall-through */
+       case LTTNG_KERNEL_ABI_FUNCTION:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_NOOP:
+               lttng_fallthrough;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               goto event_error;
        }
-       return 0;
+       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
-int lttng_abi_create_event(struct file *channel_file,
-                          struct lttng_kernel_abi_event *event_param)
+int lttng_abi_create_event_counter_enabler(struct file *channel_file,
+                       struct lttng_kernel_counter_event *counter_event)
 {
        const struct file_operations *fops;
-       struct lttng_channel *channel = channel_file->private_data;
+       struct lttng_kernel_channel_counter *channel = channel_file->private_data;
+       struct lttng_kernel_abi_event *event_param = &counter_event->event_param;
+       struct lttng_kernel_abi_event_ext *event_param_ext = &counter_event->event_param_ext;
+       struct lttng_kernel_counter_key *counter_key = counter_event->counter_key;
        int event_fd, ret;
        struct file *event_file;
        void *priv;
@@ -1830,28 +2815,34 @@ int lttng_abi_create_event(struct file *channel_file,
        }
 
        switch (event_param->instrumentation) {
-       case LTTNG_KERNEL_ABI_TRACEPOINT:               /* Fall-through */
+       case LTTNG_KERNEL_ABI_TRACEPOINT:
+               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
-               fops = &lttng_event_recorder_enabler_fops;
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KPROBE:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KRETPROBE:
+               fops = &lttng_event_session_enabler_fops;
                break;
-       case LTTNG_KERNEL_ABI_KPROBE:                   /* Fall-through */
-       case LTTNG_KERNEL_ABI_KRETPROBE:                /* Fall-through */
+
        case LTTNG_KERNEL_ABI_UPROBE:
-               fops = &lttng_event_recorder_event_fops;
+               fops = &lttng_event_session_fops;
                break;
 
-       case LTTNG_KERNEL_ABI_FUNCTION:                 /* Fall-through */
-       case LTTNG_KERNEL_ABI_NOOP:                     /* Fall-through */
+       case LTTNG_KERNEL_ABI_FUNCTION:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_NOOP:
+               lttng_fallthrough;
        default:
                return -EINVAL;
        }
 
-       event_fd = lttng_get_unused_fd();
+       event_fd = get_unused_fd_flags(0);
        if (event_fd < 0) {
                ret = event_fd;
                goto fd_error;
        }
-       event_file = anon_inode_getfile("[lttng_event]",
+       event_file = anon_inode_getfile("[lttng_event_counter]",
                                        fops, NULL, O_RDWR);
        if (IS_ERR(event_file)) {
                ret = PTR_ERR(event_file);
@@ -1862,44 +2853,68 @@ int lttng_abi_create_event(struct file *channel_file,
                ret = -EOVERFLOW;
                goto refcount_error;
        }
-       ret = lttng_abi_validate_event_param(event_param);
+       ret = lttng_abi_validate_event_param(event_param, event_param_ext);
+       if (ret)
+               goto event_error;
+       ret = lttng_abi_validate_event_match(event_param, event_param_ext);
        if (ret)
                goto event_error;
 
        switch (event_param->instrumentation) {
-       case LTTNG_KERNEL_ABI_TRACEPOINT:               /* Fall-through */
+       case LTTNG_KERNEL_ABI_TRACEPOINT:
+               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
        {
-               struct lttng_event_enabler *event_enabler;
+               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_enabler_create(LTTNG_ENABLER_FORMAT_STAR_GLOB,
-                               event_param, channel);
+                       event_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_STAR_GLOB,
+                               event_param, counter_key, channel);
                } else {
-                       event_enabler = lttng_event_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
-                               event_param, channel);
+                       event_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_param, counter_key, 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:
+       {
+               struct lttng_event_counter_enabler *event_enabler;
+
+               event_enabler = lttng_event_counter_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_param, counter_key, channel);
+               if (event_enabler)
+                       lttng_event_enabler_session_add(channel->parent.session, &event_enabler->parent);
                priv = event_enabler;
                break;
        }
 
-       case LTTNG_KERNEL_ABI_KPROBE:                   /* Fall-through */
-       case LTTNG_KERNEL_ABI_KRETPROBE:                /* Fall-through */
        case LTTNG_KERNEL_ABI_UPROBE:
        {
-               struct lttng_kernel_event_recorder *event;
+               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, counter_key, 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_recorder_create(channel, event_param,
-                               NULL, event_param->instrumentation);
-               WARN_ON_ONCE(!event);
+               event = lttng_kernel_event_create(&event_enabler->parent.parent, NULL, NULL);
+               lttng_event_enabler_destroy(&event_enabler->parent.parent);
                if (IS_ERR(event)) {
                        ret = PTR_ERR(event);
                        goto event_error;
@@ -1908,8 +2923,10 @@ int lttng_abi_create_event(struct file *channel_file,
                break;
        }
 
-       case LTTNG_KERNEL_ABI_FUNCTION:                 /* Fall-through */
-       case LTTNG_KERNEL_ABI_NOOP:                     /* Fall-through */
+       case LTTNG_KERNEL_ABI_FUNCTION:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_NOOP:
+               lttng_fallthrough;
        default:
                ret = -EINVAL;
                goto event_error;
@@ -1931,19 +2948,19 @@ fd_error:
 static
 long lttng_event_notifier_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct lttng_kernel_event_notifier *event_notifier = file->private_data;
+       struct lttng_kernel_event_common *event = file->private_data;
 
        switch (cmd) {
        case LTTNG_KERNEL_ABI_ENABLE:
-               return lttng_event_enable(&event_notifier->parent);
+               return lttng_event_enable(event);
        case LTTNG_KERNEL_ABI_DISABLE:
-               return lttng_event_disable(&event_notifier->parent);
+               return lttng_event_disable(event);
        case LTTNG_KERNEL_ABI_FILTER:
                return -EINVAL;
        case LTTNG_KERNEL_ABI_CAPTURE:
                return -EINVAL;
        case LTTNG_KERNEL_ABI_ADD_CALLSITE:
-               return lttng_event_add_callsite(&event_notifier->parent,
+               return lttng_event_add_callsite(event,
                        (struct lttng_kernel_abi_event_callsite __user *) arg);
        default:
                return -ENOIOCTLCMD;
@@ -1953,21 +2970,24 @@ long lttng_event_notifier_event_ioctl(struct file *file, unsigned int cmd, unsig
 static
 long lttng_event_notifier_enabler_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct lttng_event_notifier_enabler *event_notifier_enabler = file->private_data;
+       struct lttng_event_enabler_common *event = file->private_data;
 
        switch (cmd) {
        case LTTNG_KERNEL_ABI_ENABLE:
-               return lttng_event_notifier_enabler_enable(event_notifier_enabler);
+               return lttng_event_enabler_enable(event);
        case LTTNG_KERNEL_ABI_DISABLE:
-               return lttng_event_notifier_enabler_disable(event_notifier_enabler);
+               return lttng_event_enabler_disable(event);
        case LTTNG_KERNEL_ABI_FILTER:
-               return lttng_event_notifier_enabler_attach_filter_bytecode(
-                               event_notifier_enabler,
+               return lttng_event_enabler_attach_filter_bytecode(event,
                        (struct lttng_kernel_abi_filter_bytecode __user *) arg);
        case LTTNG_KERNEL_ABI_CAPTURE:
+       {
+               struct lttng_event_notifier_enabler *event_notifier_enabler =
+                       container_of(event, struct lttng_event_notifier_enabler, parent);
                return lttng_event_notifier_enabler_attach_capture_bytecode(
                        event_notifier_enabler,
                        (struct lttng_kernel_abi_capture_bytecode __user *) arg);
+       }
        case LTTNG_KERNEL_ABI_ADD_CALLSITE:
                return -EINVAL;
        default:
@@ -1978,20 +2998,26 @@ long lttng_event_notifier_enabler_ioctl(struct file *file, unsigned int cmd, uns
 static
 int lttng_event_notifier_event_release(struct inode *inode, struct file *file)
 {
-       struct lttng_kernel_event_notifier *event_notifier = file->private_data;
+       struct lttng_kernel_event_common *event = file->private_data;
 
-       if (event_notifier)
+       if (event) {
+               struct lttng_kernel_event_notifier *event_notifier =
+                       container_of(event, struct lttng_kernel_event_notifier, parent);
                fput(event_notifier->priv->group->file);
+       }
        return 0;
 }
 
 static
 int lttng_event_notifier_enabler_release(struct inode *inode, struct file *file)
 {
-       struct lttng_event_notifier_enabler *event_notifier_enabler = file->private_data;
+       struct lttng_event_enabler_common *event_enabler = file->private_data;
 
-       if (event_notifier_enabler)
+       if (event_enabler) {
+               struct lttng_event_notifier_enabler *event_notifier_enabler =
+                       container_of(event_enabler, struct lttng_event_notifier_enabler, parent);
                fput(event_notifier_enabler->group->file);
+       }
        return 0;
 }
 
@@ -2015,7 +3041,8 @@ static const struct file_operations lttng_event_notifier_enabler_fops = {
 
 static
 int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
-               struct lttng_kernel_abi_event_notifier *event_notifier_param)
+               struct lttng_kernel_abi_event_notifier *event_notifier_param,
+               struct lttng_kernel_abi_event_ext *event_param_ext)
 {
        struct lttng_event_notifier_group *event_notifier_group =
                        event_notifier_group_file->private_data;
@@ -2026,43 +3053,41 @@ int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
 
        switch (event_notifier_param->event.instrumentation) {
        case LTTNG_KERNEL_ABI_TRACEPOINT:
-       case LTTNG_KERNEL_ABI_UPROBE:
-               break;
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_SYSCALL:
+               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_KPROBE:
-               event_notifier_param->event.u.kprobe.symbol_name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KRETPROBE:
+               fops = &lttng_event_notifier_enabler_fops;
                break;
-       case LTTNG_KERNEL_ABI_SYSCALL:
+
+       case LTTNG_KERNEL_ABI_UPROBE:
+               fops = &lttng_event_notifier_event_fops;
                break;
-       case LTTNG_KERNEL_ABI_KRETPROBE:
-               /* Placing an event notifier on kretprobe is not supported. */
+
        case LTTNG_KERNEL_ABI_FUNCTION:
+               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_NOOP:
+               lttng_fallthrough;
        default:
                ret = -EINVAL;
                goto inval_instr;
        }
 
+       event_notifier_param->event.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
        switch (event_notifier_param->event.instrumentation) {
-       case LTTNG_KERNEL_ABI_TRACEPOINT:               /* Fall-through */
-       case LTTNG_KERNEL_ABI_SYSCALL:
-               fops = &lttng_event_notifier_enabler_fops;
+       case LTTNG_KERNEL_ABI_KRETPROBE:
+               event_notifier_param->event.u.kretprobe.symbol_name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
                break;
-       case LTTNG_KERNEL_ABI_KPROBE:                   /* Fall-through */
-       case LTTNG_KERNEL_ABI_KRETPROBE:                /* Fall-through */
-       case LTTNG_KERNEL_ABI_UPROBE:
-               fops = &lttng_event_notifier_event_fops;
+       case LTTNG_KERNEL_ABI_KPROBE:
+               event_notifier_param->event.u.kprobe.symbol_name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
                break;
-
-       case LTTNG_KERNEL_ABI_FUNCTION:                 /* Fall-through */
-       case LTTNG_KERNEL_ABI_NOOP:                     /* Fall-through */
        default:
-               ret = -EINVAL;
-               goto inval_instr;
+               break;
        }
 
-       event_notifier_param->event.name[LTTNG_KERNEL_ABI_SYM_NAME_LEN - 1] = '\0';
-
-       event_notifier_fd = lttng_get_unused_fd();
+       event_notifier_fd = get_unused_fd_flags(0);
        if (event_notifier_fd < 0) {
                ret = event_notifier_fd;
                goto fd_error;
@@ -2081,12 +3106,16 @@ int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
                goto refcount_error;
        }
 
-       ret = lttng_abi_validate_event_param(&event_notifier_param->event);
+       ret = lttng_abi_validate_event_param(&event_notifier_param->event, event_param_ext);
+       if (ret)
+               goto event_notifier_error;
+       ret = lttng_abi_validate_event_match(&event_notifier_param->event, event_param_ext);
        if (ret)
                goto event_notifier_error;
 
        switch (event_notifier_param->event.instrumentation) {
-       case LTTNG_KERNEL_ABI_TRACEPOINT:               /* Fall-through */
+       case LTTNG_KERNEL_ABI_TRACEPOINT:
+               lttng_fallthrough;
        case LTTNG_KERNEL_ABI_SYSCALL:
        {
                struct lttng_event_notifier_enabler *enabler;
@@ -2097,46 +3126,60 @@ int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
                         * we create the special star globbing enabler.
                         */
                        enabler = lttng_event_notifier_enabler_create(
-                                       event_notifier_group,
                                        LTTNG_ENABLER_FORMAT_STAR_GLOB,
-                                       event_notifier_param);
+                                       event_notifier_param,
+                                       event_notifier_group);
                } else {
                        enabler = lttng_event_notifier_enabler_create(
-                                       event_notifier_group,
                                        LTTNG_ENABLER_FORMAT_NAME,
-                                       event_notifier_param);
+                                       event_notifier_param,
+                                       event_notifier_group);
                }
+               if (enabler)
+                       lttng_event_notifier_enabler_group_add(event_notifier_group, enabler);
+               priv = enabler;
+               break;
+       }
+
+       case LTTNG_KERNEL_ABI_KPROBE:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_KRETPROBE:
+       {
+               struct lttng_event_notifier_enabler *enabler;
+
+               enabler = lttng_event_notifier_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                                       event_notifier_param, event_notifier_group);
+               if (enabler)
+                       lttng_event_notifier_enabler_group_add(event_notifier_group, enabler);
                priv = enabler;
                break;
        }
 
-       case LTTNG_KERNEL_ABI_KPROBE:                   /* Fall-through */
-       case LTTNG_KERNEL_ABI_KRETPROBE:                /* Fall-through */
        case LTTNG_KERNEL_ABI_UPROBE:
        {
-               struct lttng_kernel_event_notifier *event_notifier;
+               struct lttng_kernel_event_common *event;
+               struct lttng_event_notifier_enabler *event_notifier_enabler;
 
-               /*
-                * We tolerate no failure path after event notifier creation.
-                * It will stay invariant for the rest of the session.
-                */
-               event_notifier = lttng_event_notifier_create(NULL,
-                               event_notifier_param->event.token,
-                               event_notifier_param->error_counter_index,
-                               event_notifier_group,
-                               event_notifier_param,
-                               event_notifier_param->event.instrumentation);
-               WARN_ON_ONCE(!event_notifier);
-               if (IS_ERR(event_notifier)) {
-                       ret = PTR_ERR(event_notifier);
+               event_notifier_enabler = lttng_event_notifier_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+                               event_notifier_param, event_notifier_group);
+               if (!event_notifier_enabler) {
+                       ret = -ENOMEM;
                        goto event_notifier_error;
                }
-               priv = event_notifier;
+               event = lttng_kernel_event_create(&event_notifier_enabler->parent, NULL, NULL);
+               lttng_event_enabler_destroy(&event_notifier_enabler->parent);
+               if (IS_ERR(event)) {
+                       ret = PTR_ERR(event);
+                       goto event_notifier_error;
+               }
+               priv = event;
                break;
        }
 
-       case LTTNG_KERNEL_ABI_FUNCTION:                 /* Fall-through */
-       case LTTNG_KERNEL_ABI_NOOP:                     /* Fall-through */
+       case LTTNG_KERNEL_ABI_FUNCTION:
+               lttng_fallthrough;
+       case LTTNG_KERNEL_ABI_NOOP:
+               lttng_fallthrough;
        default:
                ret = -EINVAL;
                goto event_notifier_error;
@@ -2156,34 +3199,105 @@ inval_instr:
        return ret;
 }
 
+static
+long lttng_abi_session_create_counter(
+               struct lttng_kernel_session *session,
+               const struct lttng_kernel_counter_conf *counter_conf)
+{
+       int counter_fd, ret;
+       char *counter_transport_name;
+       struct lttng_kernel_channel_counter *chan_counter = NULL;
+       struct file *counter_file;
+
+       if (counter_conf->arithmetic != LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR) {
+               printk(KERN_ERR "LTTng: Maps: Counter of the wrong arithmetic type.\n");
+               return -EINVAL;
+       }
+
+       switch (counter_conf->bitness) {
+       case LTTNG_KERNEL_COUNTER_BITNESS_64:
+               counter_transport_name = "counter-per-cpu-64-modular";
+               break;
+       case LTTNG_KERNEL_COUNTER_BITNESS_32:
+               counter_transport_name = "counter-per-cpu-32-modular";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       lttng_lock_sessions();
+
+       counter_fd = get_unused_fd_flags(0);
+       if (counter_fd < 0) {
+               ret = counter_fd;
+               goto fd_error;
+       }
+
+       counter_file = anon_inode_getfile("[lttng_counter]",
+                                      &lttng_counter_fops,
+                                      NULL, O_RDONLY);
+       if (IS_ERR(counter_file)) {
+               ret = PTR_ERR(counter_file);
+               goto file_error;
+       }
+
+       if (!atomic_long_add_unless(&session->priv->file->f_count, 1, LONG_MAX)) {
+               ret = -EOVERFLOW;
+               goto refcount_error;
+       }
+
+       chan_counter = lttng_kernel_counter_create(counter_transport_name, 1, counter_conf->dimension_array, 0,
+                               counter_conf->flags & LTTNG_KERNEL_COUNTER_CONF_FLAG_COALESCE_HITS);
+       if (!chan_counter) {
+               ret = -EINVAL;
+               goto create_error;
+       }
+
+       chan_counter->priv->parent.file = counter_file;
+       chan_counter->priv->owner = session->priv->file;
+       chan_counter->parent.session = session;
+       list_add(&chan_counter->priv->parent.node, &session->priv->chan_head);
+       counter_file->private_data = chan_counter;
+
+       fd_install(counter_fd, counter_file);
+       lttng_unlock_sessions();
+
+       return counter_fd;
+
+create_error:
+       atomic_long_dec(&session->priv->file->f_count);
+refcount_error:
+       fput(counter_file);
+file_error:
+       put_unused_fd(counter_fd);
+fd_error:
+       lttng_unlock_sessions();
+       return ret;
+}
+
 static
 long lttng_abi_event_notifier_group_create_error_counter(
                struct file *event_notifier_group_file,
-               const struct lttng_kernel_abi_counter_conf *error_counter_conf)
+               const struct lttng_kernel_counter_conf *counter_conf)
 {
        int counter_fd, ret;
        char *counter_transport_name;
-       size_t counter_len;
-       struct lttng_counter *counter = NULL;
+       struct lttng_kernel_channel_counter *chan_counter = NULL;
        struct file *counter_file;
        struct lttng_event_notifier_group *event_notifier_group =
                        (struct lttng_event_notifier_group *) event_notifier_group_file->private_data;
+       size_t counter_len;
 
-       if (error_counter_conf->arithmetic != LTTNG_KERNEL_ABI_COUNTER_ARITHMETIC_MODULAR) {
+       if (counter_conf->arithmetic != LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR) {
                printk(KERN_ERR "LTTng: event_notifier: Error counter of the wrong arithmetic type.\n");
                return -EINVAL;
        }
 
-       if (error_counter_conf->number_dimensions != 1) {
-               printk(KERN_ERR "LTTng: event_notifier: Error counter has more than one dimension.\n");
-               return -EINVAL;
-       }
-
-       switch (error_counter_conf->bitness) {
-       case LTTNG_KERNEL_ABI_COUNTER_BITNESS_64:
+       switch (counter_conf->bitness) {
+       case LTTNG_KERNEL_COUNTER_BITNESS_64:
                counter_transport_name = "counter-per-cpu-64-modular";
                break;
-       case LTTNG_KERNEL_ABI_COUNTER_BITNESS_32:
+       case LTTNG_KERNEL_COUNTER_BITNESS_32:
                counter_transport_name = "counter-per-cpu-32-modular";
                break;
        default:
@@ -2203,7 +3317,7 @@ long lttng_abi_event_notifier_group_create_error_counter(
                goto fd_error;
        }
 
-       counter_fd = lttng_get_unused_fd();
+       counter_fd = get_unused_fd_flags(0);
        if (counter_fd < 0) {
                ret = counter_fd;
                goto fd_error;
@@ -2217,40 +3331,36 @@ long lttng_abi_event_notifier_group_create_error_counter(
                goto file_error;
        }
 
-       counter_len = error_counter_conf->dimensions[0].size;
-
        if (!atomic_long_add_unless(&event_notifier_group_file->f_count, 1, LONG_MAX)) {
                ret = -EOVERFLOW;
                goto refcount_error;
        }
 
-       counter = lttng_kernel_counter_create(counter_transport_name,
-                       1, &counter_len);
-       if (!counter) {
+       counter_len = counter_conf->dimension_array[0].size;
+       chan_counter = lttng_kernel_counter_create(counter_transport_name, 1, counter_conf->dimension_array, 0, false);
+       if (!chan_counter) {
                ret = -EINVAL;
-               goto counter_error;
+               goto create_error;
        }
 
+       chan_counter->priv->parent.file = counter_file;
+       chan_counter->priv->owner = event_notifier_group->file;
+       counter_file->private_data = chan_counter;
        event_notifier_group->error_counter_len = counter_len;
        /*
         * store-release to publish error counter matches load-acquire
         * in record_error. Ensures the counter is created and the
         * error_counter_len is set before they are used.
         */
-       lttng_smp_store_release(&event_notifier_group->error_counter, counter);
-
-       counter->file = counter_file;
-       counter->owner = event_notifier_group->file;
-       counter_file->private_data = counter;
-       /* Ownership transferred. */
-       counter = NULL;
+       smp_store_release(&event_notifier_group->error_counter,
+                               chan_counter);
 
        fd_install(counter_fd, counter_file);
        lttng_unlock_sessions();
 
        return counter_fd;
 
-counter_error:
+create_error:
        atomic_long_dec(&event_notifier_group_file->f_count);
 refcount_error:
        fput(counter_file);
@@ -2265,6 +3375,8 @@ static
 long lttng_event_notifier_group_ioctl(struct file *file, unsigned int cmd,
                unsigned long arg)
 {
+       int ret;
+
        switch (cmd) {
        case LTTNG_KERNEL_ABI_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD:
        {
@@ -2273,23 +3385,37 @@ long lttng_event_notifier_group_ioctl(struct file *file, unsigned int cmd,
        case LTTNG_KERNEL_ABI_EVENT_NOTIFIER_CREATE:
        {
                struct lttng_kernel_abi_event_notifier uevent_notifier_param;
+               struct lttng_kernel_abi_event_ext uevent_param_ext = {};
+               int ret;
 
                if (copy_from_user(&uevent_notifier_param,
                                (struct lttng_kernel_abi_event_notifier __user *) arg,
                                sizeof(uevent_notifier_param)))
                        return -EFAULT;
-               return lttng_abi_create_event_notifier(file, &uevent_notifier_param);
+               ret = copy_user_event_param_ext(&uevent_param_ext, &uevent_notifier_param.event);
+               if (ret)
+                       return ret;
+               return lttng_abi_create_event_notifier(file, &uevent_notifier_param, &uevent_param_ext);
+       }
+       case LTTNG_KERNEL_ABI_OLD_COUNTER:
+       {
+               struct lttng_kernel_counter_conf counter_conf;
+
+               ret = lttng_abi_copy_user_old_counter_conf(&counter_conf,
+                               (struct lttng_kernel_abi_old_counter_conf __user *) arg);
+               if (ret)
+                       return ret;
+               return lttng_abi_event_notifier_group_create_error_counter(file, &counter_conf);
        }
        case LTTNG_KERNEL_ABI_COUNTER:
        {
-               struct lttng_kernel_abi_counter_conf uerror_counter_conf;
+               struct lttng_kernel_counter_conf counter_conf;
 
-               if (copy_from_user(&uerror_counter_conf,
-                               (struct lttng_kernel_abi_counter_conf __user *) arg,
-                               sizeof(uerror_counter_conf)))
-                       return -EFAULT;
-               return lttng_abi_event_notifier_group_create_error_counter(file,
-                               &uerror_counter_conf);
+               ret = lttng_abi_copy_user_counter_conf(&counter_conf,
+                               (struct lttng_kernel_abi_counter_conf __user *) arg);
+               if (ret)
+                       return ret;
+               return lttng_abi_event_notifier_group_create_error_counter(file, &counter_conf);
        }
        default:
                return -ENOIOCTLCMD;
@@ -2342,7 +3468,7 @@ static const struct file_operations lttng_event_notifier_group_fops = {
 static
 long lttng_channel_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct lttng_channel *channel = file->private_data;
+       struct lttng_kernel_channel_buffer *channel = file->private_data;
 
        switch (cmd) {
        case LTTNG_KERNEL_ABI_OLD_STREAM:
@@ -2405,7 +3531,7 @@ long lttng_channel_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                default:
                        break;
                }
-               ret = lttng_abi_create_event(file, uevent_param);
+               ret = lttng_abi_create_event_recorder_enabler(file, uevent_param, NULL);
 
 old_event_error_free_old_param:
                kfree(old_uevent_param);
@@ -2417,12 +3543,17 @@ old_event_end:
        case LTTNG_KERNEL_ABI_EVENT:
        {
                struct lttng_kernel_abi_event uevent_param;
+               struct lttng_kernel_abi_event_ext uevent_param_ext = {};
+               int ret;
 
                if (copy_from_user(&uevent_param,
                                (struct lttng_kernel_abi_event __user *) arg,
                                sizeof(uevent_param)))
                        return -EFAULT;
-               return lttng_abi_create_event(file, &uevent_param);
+               ret = copy_user_event_param_ext(&uevent_param_ext, &uevent_param);
+               if (ret)
+                       return ret;
+               return lttng_abi_create_event_recorder_enabler(file, &uevent_param, &uevent_param_ext);
        }
        case LTTNG_KERNEL_ABI_OLD_CONTEXT:
        {
@@ -2465,7 +3596,7 @@ old_event_end:
 
                ret = lttng_abi_add_context(file,
                                ucontext_param,
-                               &channel->ctx, channel->session);
+                               &channel->priv->ctx, channel->parent.session);
 
 old_ctx_error_free_old_param:
                kfree(old_ucontext_param);
@@ -2484,16 +3615,16 @@ old_ctx_end:
                        return -EFAULT;
                return lttng_abi_add_context(file,
                                &ucontext_param,
-                               &channel->ctx, channel->session);
+                               &channel->priv->ctx, channel->parent.session);
        }
        case LTTNG_KERNEL_ABI_OLD_ENABLE:
        case LTTNG_KERNEL_ABI_ENABLE:
-               return lttng_channel_enable(channel);
+               return lttng_channel_enable(&channel->parent);
        case LTTNG_KERNEL_ABI_OLD_DISABLE:
        case LTTNG_KERNEL_ABI_DISABLE:
-               return lttng_channel_disable(channel);
+               return lttng_channel_disable(&channel->parent);
        case LTTNG_KERNEL_ABI_SYSCALL_MASK:
-               return lttng_channel_syscall_mask(channel,
+               return lttng_syscall_table_get_active_mask(&channel->priv->parent.syscall_table,
                        (struct lttng_kernel_abi_syscall_mask __user *) arg);
        default:
                return -ENOIOCTLCMD;
@@ -2531,21 +3662,22 @@ long lttng_metadata_ioctl(struct file *file, unsigned int cmd, unsigned long arg
  *     @file: the file
  *     @wait: poll table
  */
+static
 unsigned int lttng_channel_poll(struct file *file, poll_table *wait)
 {
-       struct lttng_channel *channel = file->private_data;
+       struct lttng_kernel_channel_buffer *channel = file->private_data;
        unsigned int mask = 0;
 
        if (file->f_mode & FMODE_READ) {
                poll_wait_set_exclusive(wait);
-               poll_wait(file, channel->ops->priv->get_hp_wait_queue(channel->chan),
+               poll_wait(file, channel->ops->priv->get_hp_wait_queue(channel->priv->rb_chan),
                          wait);
 
-               if (channel->ops->priv->is_disabled(channel->chan))
+               if (channel->ops->priv->is_disabled(channel->priv->rb_chan))
                        return POLLERR;
-               if (channel->ops->priv->is_finalized(channel->chan))
+               if (channel->ops->priv->is_finalized(channel->priv->rb_chan))
                        return POLLHUP;
-               if (channel->ops->priv->buffer_has_read_closed_stream(channel->chan))
+               if (channel->ops->priv->buffer_has_read_closed_stream(channel->priv->rb_chan))
                        return POLLIN | POLLRDNORM;
                return 0;
        }
@@ -2556,21 +3688,21 @@ unsigned int lttng_channel_poll(struct file *file, poll_table *wait)
 static
 int lttng_channel_release(struct inode *inode, struct file *file)
 {
-       struct lttng_channel *channel = file->private_data;
+       struct lttng_kernel_channel_buffer *channel = file->private_data;
 
        if (channel)
-               fput(channel->session->priv->file);
+               fput(channel->parent.session->priv->file);
        return 0;
 }
 
 static
 int lttng_metadata_channel_release(struct inode *inode, struct file *file)
 {
-       struct lttng_channel *channel = file->private_data;
+       struct lttng_kernel_channel_buffer *channel = file->private_data;
 
        if (channel) {
-               fput(channel->session->priv->file);
-               lttng_metadata_channel_destroy(channel);
+               fput(channel->parent.session->priv->file);
+               lttng_metadata_channel_buffer_destroy(channel);
        }
 
        return 0;
@@ -2596,7 +3728,7 @@ static const struct file_operations lttng_metadata_fops = {
 };
 
 /**
- *     lttng_event_recorder_event_ioctl - lttng syscall through ioctl
+ *     lttng_event_ioctl - lttng syscall through ioctl
  *
  *     @file: the file
  *     @cmd: the command
@@ -2611,9 +3743,9 @@ static const struct file_operations lttng_metadata_fops = {
  *             Disable recording for this event (strong disable)
  */
 static
-long lttng_event_recorder_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+long lttng_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct lttng_kernel_event_recorder *event_recorder = file->private_data;
+       struct lttng_kernel_event_common *event = file->private_data;
 
        switch (cmd) {
        case LTTNG_KERNEL_ABI_OLD_CONTEXT:
@@ -2628,14 +3760,14 @@ long lttng_event_recorder_event_ioctl(struct file *file, unsigned int cmd, unsig
        }
        case LTTNG_KERNEL_ABI_OLD_ENABLE:
        case LTTNG_KERNEL_ABI_ENABLE:
-               return lttng_event_enable(&event_recorder->parent);
+               return lttng_event_enable(event);
        case LTTNG_KERNEL_ABI_OLD_DISABLE:
        case LTTNG_KERNEL_ABI_DISABLE:
-               return lttng_event_disable(&event_recorder->parent);
+               return lttng_event_disable(event);
        case LTTNG_KERNEL_ABI_FILTER:
                return -EINVAL;
        case LTTNG_KERNEL_ABI_ADD_CALLSITE:
-               return lttng_event_add_callsite(&event_recorder->parent,
+               return lttng_event_add_callsite(event,
                        (struct lttng_kernel_abi_event_callsite __user *) arg);
        default:
                return -ENOIOCTLCMD;
@@ -2658,9 +3790,9 @@ long lttng_event_recorder_event_ioctl(struct file *file, unsigned int cmd, unsig
  *             Disable recording for this event (strong disable)
  */
 static
-long lttng_event_recorder_enabler_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+long lttng_event_enabler_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       struct lttng_event_enabler *event_enabler = file->private_data;
+       struct lttng_event_enabler_common *event_enabler = file->private_data;
 
        switch (cmd) {
        case LTTNG_KERNEL_ABI_OLD_CONTEXT:
@@ -2680,9 +3812,19 @@ long lttng_event_recorder_enabler_ioctl(struct file *file, unsigned int cmd, uns
        case LTTNG_KERNEL_ABI_DISABLE:
                return lttng_event_enabler_disable(event_enabler);
        case LTTNG_KERNEL_ABI_FILTER:
-               return lttng_event_enabler_attach_filter_bytecode(
-                       event_enabler,
-                       (struct lttng_kernel_abi_filter_bytecode __user *) arg);
+               /*
+                * Filters are only supported by tracepoint and syscall instrumentation.
+                */
+               switch (event_enabler->event_param.instrumentation) {
+               case LTTNG_KERNEL_ABI_TRACEPOINT:
+                       lttng_fallthrough;
+               case LTTNG_KERNEL_ABI_SYSCALL:
+                       return lttng_event_enabler_attach_filter_bytecode(event_enabler,
+                               (struct lttng_kernel_abi_filter_bytecode __user *) arg);
+
+               default:
+                       return -EINVAL;
+               }
        case LTTNG_KERNEL_ABI_ADD_CALLSITE:
                return -EINVAL;
        default:
@@ -2691,40 +3833,46 @@ long lttng_event_recorder_enabler_ioctl(struct file *file, unsigned int cmd, uns
 }
 
 static
-int lttng_event_recorder_event_release(struct inode *inode, struct file *file)
+int lttng_event_session_release(struct inode *inode, struct file *file)
 {
-       struct lttng_kernel_event_recorder *event = file->private_data;
+       struct lttng_kernel_event_common *event = file->private_data;
 
-       if (event)
-               fput(event->chan->file);
+       if (event) {
+               struct lttng_kernel_event_session_common_private *event_session_priv =
+                       container_of(event->priv, struct lttng_kernel_event_session_common_private, parent);
+               fput(event_session_priv->chan->priv->file);
+       }
        return 0;
 }
 
 static
-int lttng_event_recorder_enabler_release(struct inode *inode, struct file *file)
+int lttng_event_session_enabler_release(struct inode *inode, struct file *file)
 {
-       struct lttng_event_enabler *event_enabler = file->private_data;
+       struct lttng_event_enabler_common *event_enabler = file->private_data;
 
-       if (event_enabler)
-               fput(event_enabler->chan->file);
+       if (event_enabler) {
+               struct lttng_event_enabler_session_common *event_session_enabler =
+                       container_of(event_enabler, struct lttng_event_enabler_session_common, parent);
+               fput(event_session_enabler->chan->priv->file);
+       }
        return 0;
 }
 
-static const struct file_operations lttng_event_recorder_event_fops = {
+static const struct file_operations lttng_event_session_fops = {
        .owner = THIS_MODULE,
-       .release = lttng_event_recorder_event_release,
-       .unlocked_ioctl = lttng_event_recorder_event_ioctl,
+       .release = lttng_event_session_release,
+       .unlocked_ioctl = lttng_event_ioctl,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl = lttng_event_recorder_event_ioctl,
+       .compat_ioctl = lttng_event_ioctl,
 #endif
 };
 
-static const struct file_operations lttng_event_recorder_enabler_fops = {
+static const struct file_operations lttng_event_session_enabler_fops = {
        .owner = THIS_MODULE,
-       .release = lttng_event_recorder_enabler_release,
-       .unlocked_ioctl = lttng_event_recorder_enabler_ioctl,
+       .release = lttng_event_session_enabler_release,
+       .unlocked_ioctl = lttng_event_enabler_ioctl,
 #ifdef CONFIG_COMPAT
-       .compat_ioctl = lttng_event_recorder_enabler_ioctl,
+       .compat_ioctl = lttng_event_enabler_ioctl,
 #endif
 };
 
@@ -2741,9 +3889,9 @@ static int put_u32(uint32_t val, unsigned long arg)
 static long lttng_stream_ring_buffer_ioctl(struct file *filp,
                unsigned int cmd, unsigned long arg)
 {
-       struct lib_ring_buffer *buf = filp->private_data;
-       struct channel *chan = buf->backend.chan;
-       const struct lib_ring_buffer_config *config = &chan->backend.config;
+       struct lttng_kernel_ring_buffer *buf = filp->private_data;
+       struct lttng_kernel_ring_buffer_channel *chan = buf->backend.chan;
+       const struct lttng_kernel_ring_buffer_config *config = &chan->backend.config;
        const struct lttng_kernel_channel_buffer_ops *ops = chan->backend.priv_ops;
        int ret;
 
@@ -2845,9 +3993,9 @@ error:
 static long lttng_stream_ring_buffer_compat_ioctl(struct file *filp,
                unsigned int cmd, unsigned long arg)
 {
-       struct lib_ring_buffer *buf = filp->private_data;
-       struct channel *chan = buf->backend.chan;
-       const struct lib_ring_buffer_config *config = &chan->backend.config;
+       struct lttng_kernel_ring_buffer *buf = filp->private_data;
+       struct lttng_kernel_ring_buffer_channel *chan = buf->backend.chan;
+       const struct lttng_kernel_ring_buffer_config *config = &chan->backend.config;
        const struct lttng_kernel_channel_buffer_ops *ops = chan->backend.priv_ops;
        int ret;
 
This page took 0.058507 seconds and 4 git commands to generate.