+static
+int lttng_abi_validate_event_param(struct lttng_kernel_event *event_param)
+{
+ /* Limit ABI to implemented features. */
+ switch (event_param->instrumentation) {
+ case LTTNG_KERNEL_SYSCALL:
+ switch (event_param->u.syscall.entryexit) {
+ case LTTNG_KERNEL_SYSCALL_ENTRY:
+ case LTTNG_KERNEL_SYSCALL_EXIT:
+ case LTTNG_KERNEL_SYSCALL_ENTRYEXIT:
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (event_param->u.syscall.abi) {
+ case LTTNG_KERNEL_SYSCALL_ABI_ALL:
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (event_param->u.syscall.match) {
+ case LTTNG_KERNEL_SYSCALL_MATCH_NAME:
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case LTTNG_KERNEL_TRACEPOINT: /* Fallthrough */
+ case LTTNG_KERNEL_KPROBE: /* Fallthrough */
+ case LTTNG_KERNEL_KRETPROBE: /* Fallthrough */
+ case LTTNG_KERNEL_NOOP: /* Fallthrough */
+ case LTTNG_KERNEL_UPROBE:
+ break;
+
+ case LTTNG_KERNEL_FUNCTION: /* Fallthrough */
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static
+int lttng_abi_create_event(struct file *event_container_file,
+ struct lttng_event_container *container,
+ struct lttng_kernel_event *event_param,
+ const struct lttng_counter_key *key)
+{
+ int event_fd, ret;
+ struct file *event_file;
+ void *priv;
+
+ event_param->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
+ switch (event_param->instrumentation) {
+ case LTTNG_KERNEL_KRETPROBE:
+ event_param->u.kretprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
+ break;
+ case LTTNG_KERNEL_KPROBE:
+ event_param->u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
+ break;
+ case LTTNG_KERNEL_FUNCTION:
+ WARN_ON_ONCE(1);
+ /* Not implemented. */
+ break;
+ default:
+ break;
+ }
+ event_fd = lttng_get_unused_fd();
+ if (event_fd < 0) {
+ ret = event_fd;
+ goto fd_error;
+ }
+ event_file = anon_inode_getfile("[lttng_event]",
+ <tng_event_fops,
+ NULL, O_RDWR);
+ if (IS_ERR(event_file)) {
+ ret = PTR_ERR(event_file);
+ goto file_error;
+ }
+ /* The event holds a reference on the container */
+ if (!atomic_long_add_unless(&event_container_file->f_count, 1, LONG_MAX)) {
+ ret = -EOVERFLOW;
+ goto refcount_error;
+ }
+ ret = lttng_abi_validate_event_param(event_param);
+ if (ret)
+ goto event_error;
+ if (event_param->instrumentation == LTTNG_KERNEL_TRACEPOINT
+ || event_param->instrumentation == LTTNG_KERNEL_SYSCALL) {
+ struct lttng_event_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, key, container);
+ } else {
+ event_enabler = lttng_event_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
+ event_param, key, container);
+ }
+ priv = event_enabler;
+ } else {
+ struct lttng_event *event;
+
+ /*
+ * We tolerate no failure path after event creation. It
+ * will stay invariant for the rest of the session.
+ */
+ event = lttng_event_create(container, event_param, key,
+ NULL, NULL,
+ event_param->instrumentation, event_param->token);
+ if (IS_ERR(event)) {
+ ret = PTR_ERR(event);
+ goto event_error;
+ }
+ priv = event;
+ }
+ event_file->private_data = priv;
+ fd_install(event_fd, event_file);
+ return event_fd;
+
+event_error:
+ atomic_long_dec(&event_container_file->f_count);
+refcount_error:
+ fput(event_file);
+file_error:
+ put_unused_fd(event_fd);
+fd_error:
+ return ret;
+}
+