X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=src%2Flttng-abi.c;h=07c520f00a0c8d2604e0d170186621b35f46e2ae;hb=dffef45d53ab388fd08c19e8865b245b40ca9dff;hp=219d20a044e284c63f1688a9a06df514b28bceb6;hpb=badfe9f5c396efb1b00e5f2abcded2e4ac4a5bac;p=lttng-modules.git diff --git a/src/lttng-abi.c b/src/lttng-abi.c index 219d20a0..07c520f0 100644 --- a/src/lttng-abi.c +++ b/src/lttng-abi.c @@ -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]", + <tng_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, - <tng_stream_ring_buffer_file_operations); + <tng_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, - <tng_metadata_ring_buffer_file_operations); + <tng_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]", + <tng_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);