X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=lttng-abi.c;h=61119837f718da9e9c1114c6b913948c267dd748;hb=refs%2Fheads%2Fstable-2.11;hp=e193f4377734d1a47a8d881125de8d93befe0cc3;hpb=601252cfa07fa29f15c769fe3f4cf4419311d6f9;p=lttng-modules.git diff --git a/lttng-abi.c b/lttng-abi.c index e193f437..61119837 100644 --- a/lttng-abi.c +++ b/lttng-abi.c @@ -1,25 +1,11 @@ -/* +/* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1) + * * lttng-abi.c * * LTTng ABI * * Copyright (C) 2010-2012 Mathieu Desnoyers * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; only - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * * Mimic system calls for: * - session creation, returns a file descriptor or failure. * - channel creation, returns a file descriptor or failure. @@ -44,17 +30,19 @@ #include #include #include -#include /* for wrapper_vmalloc_sync_all() */ +#include /* for wrapper_vmalloc_sync_mappings() */ #include #include #include #include #include #include +#include #include #include #include #include +#include #include /* @@ -63,7 +51,13 @@ */ static struct proc_dir_entry *lttng_proc_dentry; -static const struct file_operations lttng_fops; + +#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,6,0)) +static const struct proc_ops lttng_proc_ops; +#else +static const struct file_operations lttng_proc_ops; +#endif + static const struct file_operations lttng_session_fops; static const struct file_operations lttng_channel_fops; static const struct file_operations lttng_metadata_fops; @@ -71,6 +65,7 @@ static const struct file_operations lttng_event_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); /* * Teardown management: opened file descriptors keep a refcount on the module, @@ -245,6 +240,9 @@ long lttng_abi_add_context(struct file *file, return lttng_add_preemptible_to_ctx(ctx); case LTTNG_KERNEL_CONTEXT_MIGRATABLE: return lttng_add_migratable_to_ctx(ctx); + case LTTNG_KERNEL_CONTEXT_CALLSTACK_KERNEL: + case LTTNG_KERNEL_CONTEXT_CALLSTACK_USER: + return lttng_add_callstack_to_ctx(ctx, context_param->ctx); default: return -EINVAL; } @@ -362,13 +360,22 @@ long lttng_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } } -static const struct file_operations lttng_fops = { +#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,6,0)) +static const struct proc_ops lttng_proc_ops = { + .proc_ioctl = lttng_ioctl, +#ifdef CONFIG_COMPAT + .proc_compat_ioctl = lttng_ioctl, +#endif /* CONFIG_COMPAT */ +}; +#else +static const struct file_operations lttng_proc_ops = { .owner = THIS_MODULE, .unlocked_ioctl = lttng_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = lttng_ioctl, -#endif +#endif /* CONFIG_COMPAT */ }; +#endif static int lttng_abi_create_channel(struct file *session_file, @@ -396,7 +403,7 @@ int lttng_abi_create_channel(struct file *session_file, fops = <tng_metadata_fops; break; } - + chan_file = anon_inode_getfile("[lttng_channel]", fops, NULL, O_RDWR); @@ -428,8 +435,8 @@ int lttng_abi_create_channel(struct file *session_file, transport_name = ""; break; } - if (atomic_long_add_unless(&session_file->f_count, - 1, INT_MAX) == INT_MAX) { + if (!atomic_long_add_unless(&session_file->f_count, 1, LONG_MAX)) { + ret = -EOVERFLOW; goto refcount_error; } /* @@ -462,6 +469,40 @@ fd_error: return ret; } +static +int lttng_abi_session_set_name(struct lttng_session *session, + struct lttng_kernel_session_name *name) +{ + size_t len; + + len = strnlen(name->name, LTTNG_KERNEL_SESSION_NAME_LEN); + + if (len == LTTNG_KERNEL_SESSION_NAME_LEN) { + /* Name is too long/malformed */ + return -EINVAL; + } + + strcpy(session->name, name->name); + return 0; +} + +static +int lttng_abi_session_set_creation_time(struct lttng_session *session, + struct lttng_kernel_session_creation_time *time) +{ + size_t len; + + len = strnlen(time->iso8601, LTTNG_KERNEL_SESSION_CREATION_TIME_ISO8601_LEN); + + if (len == LTTNG_KERNEL_SESSION_CREATION_TIME_ISO8601_LEN) { + /* Time is too long/malformed */ + return -EINVAL; + } + + strcpy(session->creation_time, time->iso8601); + return 0; +} + /** * lttng_session_ioctl - lttng session fd ioctl * @@ -489,13 +530,12 @@ static long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct lttng_session *session = file->private_data; + struct lttng_kernel_channel chan_param; + struct lttng_kernel_old_channel old_chan_param; switch (cmd) { case LTTNG_KERNEL_OLD_CHANNEL: { - struct lttng_kernel_channel chan_param; - struct lttng_kernel_old_channel old_chan_param; - if (copy_from_user(&old_chan_param, (struct lttng_kernel_old_channel __user *) arg, sizeof(struct lttng_kernel_old_channel))) @@ -512,8 +552,6 @@ long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } case LTTNG_KERNEL_CHANNEL: { - struct lttng_kernel_channel chan_param; - if (copy_from_user(&chan_param, (struct lttng_kernel_channel __user *) arg, sizeof(struct lttng_kernel_channel))) @@ -533,9 +571,6 @@ long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return lttng_session_disable(session); case LTTNG_KERNEL_OLD_METADATA: { - struct lttng_kernel_channel chan_param; - struct lttng_kernel_old_channel old_chan_param; - if (copy_from_user(&old_chan_param, (struct lttng_kernel_old_channel __user *) arg, sizeof(struct lttng_kernel_old_channel))) @@ -552,8 +587,6 @@ long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } case LTTNG_KERNEL_METADATA: { - struct lttng_kernel_channel chan_param; - if (copy_from_user(&chan_param, (struct lttng_kernel_channel __user *) arg, sizeof(struct lttng_kernel_channel))) @@ -571,6 +604,26 @@ long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return lttng_session_metadata_regenerate(session); case LTTNG_KERNEL_SESSION_STATEDUMP: return lttng_session_statedump(session); + case LTTNG_KERNEL_SESSION_SET_NAME: + { + struct lttng_kernel_session_name name; + + if (copy_from_user(&name, + (struct lttng_kernel_session_name __user *) arg, + sizeof(struct lttng_kernel_session_name))) + return -EFAULT; + return lttng_abi_session_set_name(session, &name); + } + case LTTNG_KERNEL_SESSION_SET_CREATION_TIME: + { + struct lttng_kernel_session_creation_time time; + + if (copy_from_user(&time, + (struct lttng_kernel_session_creation_time __user *) arg, + sizeof(struct lttng_kernel_session_creation_time))) + return -EFAULT; + return lttng_abi_session_set_creation_time(session, &time); + } default: return -ENOIOCTLCMD; } @@ -653,6 +706,38 @@ void lttng_metadata_ring_buffer_ioctl_put_next_subbuf(struct file *filp, stream->metadata_out = stream->metadata_in; } +/* + * Reset the counter of how much metadata has been consumed to 0. That way, + * the consumer receives the content of the metadata cache unchanged. This is + * different from the metadata_regenerate where the offset from epoch is + * resampled, here we want the exact same content as the last time the metadata + * was generated. This command is only possible if all the metadata written + * in the cache has been output to the metadata stream to avoid corrupting the + * metadata file. + * + * Return 0 on success, a negative value on error. + */ +static +int lttng_metadata_cache_dump(struct lttng_metadata_stream *stream) +{ + int ret; + struct lttng_metadata_cache *cache = stream->metadata_cache; + + mutex_lock(&cache->lock); + if (stream->metadata_out != cache->metadata_written) { + ret = -EBUSY; + goto end; + } + stream->metadata_out = 0; + stream->metadata_in = 0; + wake_up_interruptible(&stream->read_wait); + ret = 0; + +end: + mutex_unlock(&cache->lock); + return ret; +} + static long lttng_metadata_ring_buffer_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) @@ -660,6 +745,13 @@ 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; + unsigned int rb_cmd; + bool coherent; + + if (cmd == RING_BUFFER_GET_NEXT_SUBBUF_METADATA_CHECK) + rb_cmd = RING_BUFFER_GET_NEXT_SUBBUF; + else + rb_cmd = cmd; switch (cmd) { case RING_BUFFER_GET_NEXT_SUBBUF: @@ -668,7 +760,7 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp, struct lib_ring_buffer *buf = stream->priv; struct channel *chan = buf->backend.chan; - ret = lttng_metadata_output_channel(stream, chan); + ret = lttng_metadata_output_channel(stream, chan, NULL); if (ret > 0) { lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE); ret = 0; @@ -683,6 +775,7 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp, */ return -ENOSYS; } + case RING_BUFFER_FLUSH_EMPTY: /* Fall-through. */ case RING_BUFFER_FLUSH: { struct lttng_metadata_stream *stream = filp->private_data; @@ -693,7 +786,7 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp, * Before doing the actual ring buffer flush, write up to one * packet of metadata in the ring buffer. */ - ret = lttng_metadata_output_channel(stream, chan); + ret = lttng_metadata_output_channel(stream, chan, NULL); if (ret < 0) goto err; break; @@ -704,16 +797,25 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp, return put_u64(stream->version, arg); } - case RING_BUFFER_SNAPSHOT: + case RING_BUFFER_METADATA_CACHE_DUMP: { - /* - * Force the buffer to quiescent so the ring buffer - * don't attempt to perform a SWITCH_FLUSH, which would - * desynchronize the client accounting of the amount of - * data available in the buffer from the ring buffer - * view. - */ - buf->quiescent = true; + struct lttng_metadata_stream *stream = filp->private_data; + + return lttng_metadata_cache_dump(stream); + } + case 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; + + ret = lttng_metadata_output_channel(stream, chan, &coherent); + if (ret > 0) { + lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE); + ret = 0; + } else if (ret < 0) { + goto err; + } break; } default: @@ -722,7 +824,7 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp, /* PUT_SUBBUF is the one from lib ring buffer, unmodified. */ /* Performing lib ring buffer ioctl after our own. */ - ret = lib_ring_buffer_ioctl(filp, cmd, arg, buf); + ret = lib_ring_buffer_ioctl(filp, rb_cmd, arg, buf); if (ret < 0) goto err; @@ -733,6 +835,10 @@ long lttng_metadata_ring_buffer_ioctl(struct file *filp, cmd, arg); break; } + case RING_BUFFER_GET_NEXT_SUBBUF_METADATA_CHECK: + { + return put_u32(coherent, arg); + } default: break; } @@ -748,6 +854,13 @@ 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; + unsigned int rb_cmd; + bool coherent; + + if (cmd == RING_BUFFER_GET_NEXT_SUBBUF_METADATA_CHECK) + rb_cmd = RING_BUFFER_GET_NEXT_SUBBUF; + else + rb_cmd = cmd; switch (cmd) { case RING_BUFFER_GET_NEXT_SUBBUF: @@ -756,7 +869,7 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp, struct lib_ring_buffer *buf = stream->priv; struct channel *chan = buf->backend.chan; - ret = lttng_metadata_output_channel(stream, chan); + ret = lttng_metadata_output_channel(stream, chan, NULL); if (ret > 0) { lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE); ret = 0; @@ -771,6 +884,7 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp, */ return -ENOSYS; } + case RING_BUFFER_FLUSH_EMPTY: /* Fall-through. */ case RING_BUFFER_FLUSH: { struct lttng_metadata_stream *stream = filp->private_data; @@ -781,7 +895,7 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp, * Before doing the actual ring buffer flush, write up to one * packet of metadata in the ring buffer. */ - ret = lttng_metadata_output_channel(stream, chan); + ret = lttng_metadata_output_channel(stream, chan, NULL); if (ret < 0) goto err; break; @@ -792,16 +906,25 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp, return put_u64(stream->version, arg); } - case RING_BUFFER_SNAPSHOT: + case RING_BUFFER_METADATA_CACHE_DUMP: { - /* - * Force the buffer to quiescent so the ring buffer - * don't attempt to perform a SWITCH_FLUSH, which would - * desynchronize the client accounting of the amount of - * data available in the buffer from the ring buffer - * view. - */ - buf->quiescent = true; + struct lttng_metadata_stream *stream = filp->private_data; + + return lttng_metadata_cache_dump(stream); + } + case 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; + + ret = lttng_metadata_output_channel(stream, chan, &coherent); + if (ret > 0) { + lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE); + ret = 0; + } else if (ret < 0) { + goto err; + } break; } default: @@ -810,7 +933,7 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp, /* PUT_SUBBUF is the one from lib ring buffer, unmodified. */ /* Performing lib ring buffer ioctl after our own. */ - ret = lib_ring_buffer_compat_ioctl(filp, cmd, arg, buf); + ret = lib_ring_buffer_compat_ioctl(filp, rb_cmd, arg, buf); if (ret < 0) goto err; @@ -821,6 +944,10 @@ long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp, cmd, arg); break; } + case RING_BUFFER_GET_NEXT_SUBBUF_METADATA_CHECK: + { + return put_u32(coherent, arg); + } default: break; } @@ -857,8 +984,12 @@ 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; + mutex_lock(&stream->metadata_cache->lock); + list_del(&stream->list); + mutex_unlock(&stream->metadata_cache->lock); kref_put(&stream->metadata_cache->refcount, metadata_cache_destroy); module_put(stream->transport->owner); + kfree(stream); return lib_ring_buffer_release(inode, file, buf); } @@ -987,6 +1118,8 @@ int lttng_abi_open_metadata_stream(struct file *channel_file) metadata_stream->priv = buf; stream_priv = metadata_stream; metadata_stream->transport = channel->transport; + /* Initial state is an empty metadata, considered as incoherent. */ + metadata_stream->coherent = false; /* * Since life-time of metadata cache differs from that of @@ -998,15 +1131,20 @@ int lttng_abi_open_metadata_stream(struct file *channel_file) goto notransport; } - if (!lttng_kref_get(&session->metadata_cache->refcount)) + if (!lttng_kref_get(&session->metadata_cache->refcount)) { + ret = -EOVERFLOW; goto kref_error; + } + ret = lttng_abi_create_stream_fd(channel_file, stream_priv, <tng_metadata_ring_buffer_file_operations); if (ret < 0) goto fd_error; + mutex_lock(&session->metadata_cache->lock); list_add(&metadata_stream->list, &session->metadata_cache->metadata_stream); + mutex_unlock(&session->metadata_cache->lock); return ret; fd_error: @@ -1020,6 +1158,46 @@ nomem: return ret; } +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_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_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 *channel_file, struct lttng_kernel_event *event_param) @@ -1038,7 +1216,8 @@ int lttng_abi_create_event(struct file *channel_file, event_param->u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; break; case LTTNG_KERNEL_FUNCTION: - event_param->u.ftrace.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; + WARN_ON_ONCE(1); + /* Not implemented. */ break; default: break; @@ -1056,17 +1235,23 @@ int lttng_abi_create_event(struct file *channel_file, goto file_error; } /* The event holds a reference on the channel */ - if (atomic_long_add_unless(&channel_file->f_count, - 1, INT_MAX) == INT_MAX) { + if (!atomic_long_add_unless(&channel_file->f_count, 1, LONG_MAX)) { ret = -EOVERFLOW; goto refcount_error; } + ret = lttng_abi_validate_event_param(event_param); + if (ret) + goto event_error; if (event_param->instrumentation == LTTNG_KERNEL_TRACEPOINT || event_param->instrumentation == LTTNG_KERNEL_SYSCALL) { struct lttng_enabler *enabler; - if (event_param->name[strlen(event_param->name) - 1] == '*') { - enabler = lttng_enabler_create(LTTNG_ENABLER_WILDCARD, + 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_param, channel); } else { enabler = lttng_enabler_create(LTTNG_ENABLER_NAME, @@ -1186,9 +1371,8 @@ long lttng_channel_ioctl(struct file *file, unsigned int cmd, unsigned long arg) sizeof(uevent_param->u.kretprobe.symbol_name)); break; case LTTNG_KERNEL_FUNCTION: - memcpy(uevent_param->u.ftrace.symbol_name, - old_uevent_param->u.ftrace.symbol_name, - sizeof(uevent_param->u.ftrace.symbol_name)); + WARN_ON_ONCE(1); + /* Not implemented. */ break; default: break; @@ -1286,7 +1470,6 @@ old_ctx_end: default: return -ENOIOCTLCMD; } - } /** @@ -1453,7 +1636,21 @@ long lttng_event_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return lttng_enabler_attach_bytecode(enabler, (struct lttng_kernel_filter_bytecode __user *) arg); } - + default: + WARN_ON_ONCE(1); + return -ENOSYS; + } + case LTTNG_KERNEL_ADD_CALLSITE: + switch (*evtype) { + case LTTNG_TYPE_EVENT: + event = file->private_data; + return lttng_event_add_callsite(event, + (struct lttng_kernel_event_callsite __user *) arg); + case LTTNG_TYPE_ENABLER: + return -EINVAL; + default: + WARN_ON_ONCE(1); + return -ENOSYS; } default: return -ENOIOCTLCMD; @@ -1504,6 +1701,11 @@ static int put_u64(uint64_t val, unsigned long arg) return put_user(val, (uint64_t __user *) arg); } +static int put_u32(uint32_t val, unsigned long arg) +{ + return put_user(val, (uint32_t __user *) arg); +} + static long lttng_stream_ring_buffer_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -1739,11 +1941,17 @@ int __init lttng_abi_init(void) { int ret = 0; - wrapper_vmalloc_sync_all(); + wrapper_vmalloc_sync_mappings(); lttng_clock_ref(); + + ret = lttng_tp_mempool_init(); + if (ret) { + goto error; + } + lttng_proc_dentry = proc_create_data("lttng", S_IRUSR | S_IWUSR, NULL, - <tng_fops, NULL); - + <tng_proc_ops, NULL); + if (!lttng_proc_dentry) { printk(KERN_ERR "Error creating LTTng control file\n"); ret = -ENOMEM; @@ -1753,6 +1961,7 @@ int __init lttng_abi_init(void) return 0; error: + lttng_tp_mempool_destroy(); lttng_clock_unref(); return ret; } @@ -1760,6 +1969,7 @@ error: /* No __exit annotation because used by init error path too. */ void lttng_abi_exit(void) { + lttng_tp_mempool_destroy(); lttng_clock_unref(); if (lttng_proc_dentry) remove_proc_entry("lttng", NULL);