Add event notifier and event notifier enabler
[lttng-modules.git] / src / lttng-abi.c
index 219d20a044e284c63f1688a9a06df514b28bceb6..07c520f00a0c8d2604e0d170186621b35f46e2ae 100644 (file)
@@ -59,6 +59,7 @@ static const struct file_operations lttng_proc_ops;
 #endif
 
 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_fops;
@@ -105,6 +106,41 @@ fd_error:
        return ret;
 }
 
+static
+int lttng_abi_create_event_notifier_group(void)
+{
+       struct lttng_event_notifier_group *event_notifier_group;
+       struct file *event_notifier_group_file;
+       int event_notifier_group_fd, ret;
+
+       event_notifier_group = lttng_event_notifier_group_create();
+       if (!event_notifier_group)
+               return -ENOMEM;
+
+       event_notifier_group_fd = lttng_get_unused_fd();
+       if (event_notifier_group_fd < 0) {
+               ret = event_notifier_group_fd;
+               goto fd_error;
+       }
+       event_notifier_group_file = anon_inode_getfile("[lttng_event_notifier_group]",
+                                         &lttng_event_notifier_group_fops,
+                                         event_notifier_group, O_RDWR);
+       if (IS_ERR(event_notifier_group_file)) {
+               ret = PTR_ERR(event_notifier_group_file);
+               goto file_error;
+       }
+
+       event_notifier_group->file = event_notifier_group_file;
+       fd_install(event_notifier_group_fd, event_notifier_group_file);
+       return event_notifier_group_fd;
+
+file_error:
+       put_unused_fd(event_notifier_group_fd);
+fd_error:
+       lttng_event_notifier_group_destroy(event_notifier_group);
+       return ret;
+}
+
 static
 int lttng_abi_tracepoint_list(void)
 {
@@ -306,6 +342,8 @@ long lttng_abi_add_context(struct file *file,
  *             Returns after all previously running probes have completed
  *     LTTNG_KERNEL_TRACER_ABI_VERSION
  *             Returns the LTTng kernel tracer ABI version
+ *     LTTNG_KERNEL_EVENT_NOTIFIER_GROUP_CREATE
+ *             Returns a LTTng event notifier group file descriptor
  *
  * The returned session will be deleted when its file descriptor is closed.
  */
@@ -316,6 +354,8 @@ long lttng_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case LTTNG_KERNEL_OLD_SESSION:
        case LTTNG_KERNEL_SESSION:
                return lttng_abi_create_session();
+       case LTTNG_KERNEL_EVENT_NOTIFIER_GROUP_CREATE:
+               return lttng_abi_create_event_notifier_group();
        case LTTNG_KERNEL_OLD_TRACER_VERSION:
        {
                struct lttng_kernel_tracer_version v;
@@ -1140,7 +1180,7 @@ const struct file_operations lttng_metadata_ring_buffer_file_operations = {
 
 static
 int lttng_abi_create_stream_fd(struct file *channel_file, void *stream_priv,
-               const struct file_operations *fops)
+               const struct file_operations *fops, const char *name)
 {
        int stream_fd, ret;
        struct file *stream_file;
@@ -1150,8 +1190,7 @@ int lttng_abi_create_stream_fd(struct file *channel_file, void *stream_priv,
                ret = stream_fd;
                goto fd_error;
        }
-       stream_file = anon_inode_getfile("[lttng_stream]", fops,
-                       stream_priv, O_RDWR);
+       stream_file = anon_inode_getfile(name, fops, stream_priv, O_RDWR);
        if (IS_ERR(stream_file)) {
                ret = PTR_ERR(stream_file);
                goto file_error;
@@ -1190,7 +1229,8 @@ int lttng_abi_open_stream(struct file *channel_file)
 
        stream_priv = buf;
        ret = lttng_abi_create_stream_fd(channel_file, stream_priv,
-                       &lttng_stream_ring_buffer_file_operations);
+                       &lttng_stream_ring_buffer_file_operations,
+                       "[lttng_stream]");
        if (ret < 0)
                goto fd_error;
 
@@ -1245,7 +1285,8 @@ int lttng_abi_open_metadata_stream(struct file *channel_file)
        }
 
        ret = lttng_abi_create_stream_fd(channel_file, stream_priv,
-                       &lttng_metadata_ring_buffer_file_operations);
+                       &lttng_metadata_ring_buffer_file_operations,
+                       "[lttng_metadata_stream]");
        if (ret < 0)
                goto fd_error;
 
@@ -1352,20 +1393,20 @@ int lttng_abi_create_event(struct file *channel_file,
                goto event_error;
        if (event_param->instrumentation == LTTNG_KERNEL_TRACEPOINT
                        || event_param->instrumentation == LTTNG_KERNEL_SYSCALL) {
-               struct lttng_enabler *enabler;
+               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.
                         */
-                       enabler = lttng_enabler_create(LTTNG_ENABLER_STAR_GLOB,
+                       event_enabler = lttng_event_enabler_create(LTTNG_ENABLER_FORMAT_STAR_GLOB,
                                event_param, channel);
                } else {
-                       enabler = lttng_enabler_create(LTTNG_ENABLER_NAME,
+                       event_enabler = lttng_event_enabler_create(LTTNG_ENABLER_FORMAT_NAME,
                                event_param, channel);
                }
-               priv = enabler;
+               priv = event_enabler;
        } else {
                struct lttng_event *event;
 
@@ -1397,6 +1438,229 @@ fd_error:
        return ret;
 }
 
+static
+long lttng_event_notifier_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct lttng_event_notifier_enabler *event_notifier_enabler;
+       enum lttng_event_type *evtype = file->private_data;
+
+       switch (cmd) {
+       case LTTNG_KERNEL_ENABLE:
+               switch (*evtype) {
+               case LTTNG_TYPE_EVENT:
+                       return -EINVAL;
+               case LTTNG_TYPE_ENABLER:
+                       event_notifier_enabler = file->private_data;
+                       return lttng_event_notifier_enabler_enable(event_notifier_enabler);
+               default:
+                       WARN_ON_ONCE(1);
+                       return -ENOSYS;
+               }
+       case LTTNG_KERNEL_DISABLE:
+               switch (*evtype) {
+               case LTTNG_TYPE_EVENT:
+                       return -EINVAL;
+               case LTTNG_TYPE_ENABLER:
+                       event_notifier_enabler = file->private_data;
+                       return lttng_event_notifier_enabler_disable(event_notifier_enabler);
+               default:
+                       WARN_ON_ONCE(1);
+                       return -ENOSYS;
+               }
+       case LTTNG_KERNEL_FILTER:
+               switch (*evtype) {
+               case LTTNG_TYPE_EVENT:
+                       return -EINVAL;
+               case LTTNG_TYPE_ENABLER:
+                       event_notifier_enabler = file->private_data;
+                       return lttng_event_notifier_enabler_attach_bytecode(event_notifier_enabler,
+                               (struct lttng_kernel_filter_bytecode __user *) arg);
+               default:
+                       WARN_ON_ONCE(1);
+                       return -ENOSYS;
+               }
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static
+int lttng_event_notifier_release(struct inode *inode, struct file *file)
+{
+       struct lttng_event_notifier *event_notifier;
+       struct lttng_event_notifier_enabler *event_notifier_enabler;
+       enum lttng_event_type *evtype = file->private_data;
+
+       if (!evtype)
+               return 0;
+
+       switch (*evtype) {
+       case LTTNG_TYPE_EVENT:
+               event_notifier = file->private_data;
+               if (event_notifier)
+                       fput(event_notifier->group->file);
+               break;
+       case LTTNG_TYPE_ENABLER:
+               event_notifier_enabler = file->private_data;
+               if (event_notifier_enabler)
+                       fput(event_notifier_enabler->group->file);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               break;
+       }
+
+       return 0;
+}
+
+static const struct file_operations lttng_event_notifier_fops = {
+       .owner = THIS_MODULE,
+       .release = lttng_event_notifier_release,
+       .unlocked_ioctl = lttng_event_notifier_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = lttng_event_notifier_ioctl,
+#endif
+};
+
+static
+int lttng_abi_create_event_notifier(struct file *event_notifier_group_file,
+               struct lttng_kernel_event_notifier *event_notifier_param)
+{
+       struct lttng_event_notifier_group *event_notifier_group =
+                       event_notifier_group_file->private_data;
+       int event_notifier_fd, ret;
+       struct file *event_notifier_file;
+       void *priv;
+
+       switch (event_notifier_param->event.instrumentation) {
+       case LTTNG_KERNEL_TRACEPOINT:
+       case LTTNG_KERNEL_KPROBE:
+       case LTTNG_KERNEL_UPROBE:
+       case LTTNG_KERNEL_KRETPROBE:
+       case LTTNG_KERNEL_FUNCTION:
+       case LTTNG_KERNEL_NOOP:
+       case LTTNG_KERNEL_SYSCALL:
+       default:
+               ret = -EINVAL;
+               goto inval_instr;
+       }
+
+       event_notifier_param->event.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
+
+       event_notifier_fd = lttng_get_unused_fd();
+       if (event_notifier_fd < 0) {
+               ret = event_notifier_fd;
+               goto fd_error;
+       }
+
+       event_notifier_file = anon_inode_getfile("[lttng_event_notifier]",
+                                       &lttng_event_notifier_fops,
+                                       NULL, O_RDWR);
+       if (IS_ERR(event_notifier_file)) {
+               ret = PTR_ERR(event_notifier_file);
+               goto file_error;
+       }
+
+       /* The event notifier holds a reference on the event notifier group. */
+       if (!atomic_long_add_unless(&event_notifier_group_file->f_count, 1, LONG_MAX)) {
+               ret = -EOVERFLOW;
+               goto refcount_error;
+       }
+
+       if (event_notifier_param->event.instrumentation == LTTNG_KERNEL_TRACEPOINT
+                       || event_notifier_param->event.instrumentation == LTTNG_KERNEL_SYSCALL) {
+               struct lttng_event_notifier_enabler *enabler;
+
+               if (strutils_is_star_glob_pattern(event_notifier_param->event.name)) {
+                       /*
+                        * If the event name is a star globbing pattern,
+                        * we create the special star globbing enabler.
+                        */
+                       enabler = lttng_event_notifier_enabler_create(
+                                       event_notifier_group,
+                                       LTTNG_ENABLER_FORMAT_STAR_GLOB,
+                                       event_notifier_param);
+               } else {
+                       enabler = lttng_event_notifier_enabler_create(
+                                       event_notifier_group,
+                                       LTTNG_ENABLER_FORMAT_NAME,
+                                       event_notifier_param);
+               }
+               priv = enabler;
+       } else {
+               struct lttng_event_notifier *event_notifier;
+
+               /*
+                * 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_group,
+                               event_notifier_param, NULL,
+                               event_notifier_param->event.instrumentation);
+               WARN_ON_ONCE(!event_notifier);
+               if (IS_ERR(event_notifier)) {
+                       ret = PTR_ERR(event_notifier);
+                       goto event_notifier_error;
+               }
+               priv = event_notifier;
+       }
+       event_notifier_file->private_data = priv;
+       fd_install(event_notifier_fd, event_notifier_file);
+       return event_notifier_fd;
+
+event_notifier_error:
+       atomic_long_dec(&event_notifier_group_file->f_count);
+refcount_error:
+       fput(event_notifier_file);
+file_error:
+       put_unused_fd(event_notifier_fd);
+fd_error:
+inval_instr:
+       return ret;
+}
+
+static
+long lttng_event_notifier_group_ioctl(struct file *file, unsigned int cmd,
+               unsigned long arg)
+{
+       switch (cmd) {
+       case LTTNG_KERNEL_EVENT_NOTIFIER_CREATE:
+       {
+               struct lttng_kernel_event_notifier uevent_notifier_param;
+
+               if (copy_from_user(&uevent_notifier_param,
+                               (struct lttng_kernel_event_notifier __user *) arg,
+                               sizeof(uevent_notifier_param)))
+                       return -EFAULT;
+               return lttng_abi_create_event_notifier(file, &uevent_notifier_param);
+       }
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static
+int lttng_event_notifier_group_release(struct inode *inode, struct file *file)
+{
+       struct lttng_event_notifier_group *event_notifier_group =
+                       file->private_data;
+
+       if (event_notifier_group)
+               lttng_event_notifier_group_destroy(event_notifier_group);
+       return 0;
+}
+
+static const struct file_operations lttng_event_notifier_group_fops = {
+       .owner = THIS_MODULE,
+       .release = lttng_event_notifier_group_release,
+       .unlocked_ioctl = lttng_event_notifier_group_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = lttng_event_notifier_group_ioctl,
+#endif
+};
+
 /**
  *     lttng_channel_ioctl - lttng syscall through ioctl
  *
@@ -1694,7 +1958,7 @@ static
 long lttng_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct lttng_event *event;
-       struct lttng_enabler *enabler;
+       struct lttng_event_enabler *event_enabler;
        enum lttng_event_type *evtype = file->private_data;
 
        switch (cmd) {
@@ -1715,8 +1979,8 @@ long lttng_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        event = file->private_data;
                        return lttng_event_enable(event);
                case LTTNG_TYPE_ENABLER:
-                       enabler = file->private_data;
-                       return lttng_enabler_enable(enabler);
+                       event_enabler = file->private_data;
+                       return lttng_event_enabler_enable(event_enabler);
                default:
                        WARN_ON_ONCE(1);
                        return -ENOSYS;
@@ -1728,8 +1992,8 @@ long lttng_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        event = file->private_data;
                        return lttng_event_disable(event);
                case LTTNG_TYPE_ENABLER:
-                       enabler = file->private_data;
-                       return lttng_enabler_disable(enabler);
+                       event_enabler = file->private_data;
+                       return lttng_event_enabler_disable(event_enabler);
                default:
                        WARN_ON_ONCE(1);
                        return -ENOSYS;
@@ -1740,8 +2004,8 @@ long lttng_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        return -EINVAL;
                case LTTNG_TYPE_ENABLER:
                {
-                       enabler = file->private_data;
-                       return lttng_enabler_attach_bytecode(enabler,
+                       event_enabler = file->private_data;
+                       return lttng_event_enabler_attach_bytecode(event_enabler,
                                (struct lttng_kernel_filter_bytecode __user *) arg);
                }
                default:
@@ -1769,7 +2033,7 @@ static
 int lttng_event_release(struct inode *inode, struct file *file)
 {
        struct lttng_event *event;
-       struct lttng_enabler *enabler;
+       struct lttng_event_enabler *event_enabler;
        enum lttng_event_type *evtype = file->private_data;
 
        if (!evtype)
@@ -1782,9 +2046,9 @@ int lttng_event_release(struct inode *inode, struct file *file)
                        fput(event->chan->file);
                break;
        case LTTNG_TYPE_ENABLER:
-               enabler = file->private_data;
-               if (enabler)
-                       fput(enabler->chan->file);
+               event_enabler = file->private_data;
+               if (event_enabler)
+                       fput(event_enabler->chan->file);
                break;
        default:
                WARN_ON_ONCE(1);
This page took 0.028115 seconds and 4 git commands to generate.