int lttng_abi_create_event_counter_enabler(struct file *channel_file,
struct lttng_kernel_abi_event *event_param,
const struct lttng_kernel_abi_counter_key *key_param);
+static
+long lttng_abi_session_create_counter(
+ struct lttng_kernel_session *session,
+ const struct lttng_kernel_abi_counter_conf *counter_conf);
static int validate_zeroed_padding(char *p, size_t len)
{
return -EFAULT;
return lttng_abi_session_set_creation_time(session, &time);
}
+ case LTTNG_KERNEL_ABI_COUNTER:
+ {
+ struct lttng_kernel_abi_counter_conf counter_conf;
+
+ if (copy_from_user(&counter_conf,
+ (struct lttng_kernel_abi_counter_conf __user *) arg,
+ sizeof(struct lttng_kernel_abi_counter_conf)))
+ return -EFAULT;
+ return lttng_abi_session_create_counter(session, &counter_conf);
+ }
default:
return -ENOIOCTLCMD;
}
return ret;
}
+static
+long lttng_abi_session_create_counter(
+ struct lttng_kernel_session *session,
+ const struct lttng_kernel_abi_counter_conf *counter_conf)
+{
+ int counter_fd, ret;
+ char *counter_transport_name;
+ struct lttng_kernel_channel_counter *chan_counter = NULL;
+ struct file *counter_file;
+ struct lttng_counter_dimension dimensions[1];
+ size_t counter_len;
+
+ if (counter_conf->arithmetic != LTTNG_KERNEL_ABI_COUNTER_ARITHMETIC_MODULAR) {
+ printk(KERN_ERR "LTTng: Maps: Counter of the wrong arithmetic type.\n");
+ return -EINVAL;
+ }
+
+ if (counter_conf->number_dimensions != 1) {
+ printk(KERN_ERR "LTTng: Maps: Counter has more than one dimension.\n");
+ return -EINVAL;
+ }
+
+ switch (counter_conf->bitness) {
+ case LTTNG_KERNEL_ABI_COUNTER_BITNESS_64:
+ counter_transport_name = "counter-per-cpu-64-modular";
+ break;
+ case LTTNG_KERNEL_ABI_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]",
+ <tng_counter_fops,
+ NULL, O_RDONLY);
+ if (IS_ERR(counter_file)) {
+ ret = PTR_ERR(counter_file);
+ goto file_error;
+ }
+
+ counter_len = counter_conf->dimensions[0].size;
+ dimensions[0].size = counter_len;
+ dimensions[0].underflow_index = 0;
+ dimensions[0].overflow_index = 0;
+ dimensions[0].has_underflow = 0;
+ dimensions[0].has_overflow = 0;
+
+ 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, dimensions, 0,
+ counter_conf->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,
if (channel) {
fput(channel->parent.session->priv->file);
- lttng_metadata_channel_destroy(channel);
+ lttng_metadata_channel_buffer_destroy(channel);
}
return 0;
static void lttng_event_enabler_sync(struct lttng_event_enabler_common *event_enabler);
static void _lttng_event_destroy(struct lttng_kernel_event_common *event);
-static void _lttng_channel_destroy(struct lttng_kernel_channel_buffer *chan);
+static void _lttng_channel_destroy(struct lttng_kernel_channel_common *chan);
static void _lttng_event_unregister(struct lttng_kernel_event_common *event);
static
int _lttng_event_recorder_metadata_statedump(struct lttng_kernel_event_common *event);
void lttng_session_destroy(struct lttng_kernel_session *session)
{
- struct lttng_kernel_channel_buffer_private *chan_priv, *tmpchan_priv;
+ struct lttng_kernel_channel_common_private *chan_priv, *tmpchan_priv;
struct lttng_kernel_event_recorder_private *event_recorder_priv, *tmpevent_recorder_priv;
struct lttng_metadata_stream *metadata_stream;
struct lttng_event_enabler_common *event_enabler, *tmp_event_enabler;
mutex_lock(&sessions_mutex);
WRITE_ONCE(session->active, 0);
list_for_each_entry(chan_priv, &session->priv->chan_head, node) {
- ret = lttng_syscalls_unregister_syscall_table(&chan_priv->parent.syscall_table);
+ ret = lttng_syscalls_unregister_syscall_table(&chan_priv->syscall_table);
WARN_ON(ret);
}
list_for_each_entry(event_recorder_priv, &session->priv->events_head, parent.parent.node)
_lttng_event_unregister(&event_recorder_priv->pub->parent);
synchronize_trace(); /* Wait for in-flight events to complete */
list_for_each_entry(chan_priv, &session->priv->chan_head, node) {
- ret = lttng_syscalls_destroy_syscall_table(&chan_priv->parent.syscall_table);
+ ret = lttng_syscalls_destroy_syscall_table(&chan_priv->syscall_table);
WARN_ON(ret);
}
list_for_each_entry_safe(event_enabler, tmp_event_enabler, &session->priv->enablers_head, node)
list_for_each_entry_safe(event_recorder_priv, tmpevent_recorder_priv, &session->priv->events_head, parent.parent.node)
_lttng_event_destroy(&event_recorder_priv->pub->parent);
list_for_each_entry_safe(chan_priv, tmpchan_priv, &session->priv->chan_head, node) {
- BUG_ON(chan_priv->channel_type == METADATA_CHANNEL);
_lttng_channel_destroy(chan_priv->pub);
}
mutex_lock(&session->priv->metadata_cache->lock);
int lttng_session_enable(struct lttng_kernel_session *session)
{
int ret = 0;
- struct lttng_kernel_channel_buffer_private *chan_priv;
+ struct lttng_kernel_channel_common_private *chan_priv;
mutex_lock(&sessions_mutex);
if (session->active) {
* we need to use.
*/
list_for_each_entry(chan_priv, &session->priv->chan_head, node) {
- if (chan_priv->header_type)
+ struct lttng_kernel_channel_buffer_private *chan_buf_priv;
+
+ if (chan_priv->pub->type != LTTNG_KERNEL_CHANNEL_TYPE_BUFFER)
+ continue;
+ chan_buf_priv = container_of(chan_priv, struct lttng_kernel_channel_buffer_private, parent);
+ if (chan_buf_priv->header_type)
continue; /* don't change it if session stop/restart */
- if (chan_priv->free_event_id < 31)
- chan_priv->header_type = 1; /* compact */
+ if (chan_buf_priv->free_event_id < 31)
+ chan_buf_priv->header_type = 1; /* compact */
else
- chan_priv->header_type = 2; /* large */
+ chan_buf_priv->header_type = 2; /* large */
}
/* Clear each stream's quiescent state. */
list_for_each_entry(chan_priv, &session->priv->chan_head, node) {
- if (chan_priv->channel_type != METADATA_CHANNEL)
- lib_ring_buffer_clear_quiescent_channel(chan_priv->rb_chan);
+ struct lttng_kernel_channel_buffer_private *chan_buf_priv;
+
+ if (chan_priv->pub->type != LTTNG_KERNEL_CHANNEL_TYPE_BUFFER)
+ continue;
+ chan_buf_priv = container_of(chan_priv, struct lttng_kernel_channel_buffer_private, parent);
+ if (chan_buf_priv->channel_type != METADATA_CHANNEL)
+ lib_ring_buffer_clear_quiescent_channel(chan_buf_priv->rb_chan);
}
WRITE_ONCE(session->active, 1);
int lttng_session_disable(struct lttng_kernel_session *session)
{
int ret = 0;
- struct lttng_kernel_channel_buffer_private *chan_priv;
+ struct lttng_kernel_channel_common_private *chan_priv;
mutex_lock(&sessions_mutex);
if (!session->active) {
/* Set each stream's quiescent state. */
list_for_each_entry(chan_priv, &session->priv->chan_head, node) {
- if (chan_priv->channel_type != METADATA_CHANNEL)
- lib_ring_buffer_set_quiescent_channel(chan_priv->rb_chan);
+ struct lttng_kernel_channel_buffer_private *chan_buf_priv;
+
+ if (chan_priv->pub->type != LTTNG_KERNEL_CHANNEL_TYPE_BUFFER)
+ continue;
+ chan_buf_priv = container_of(chan_priv, struct lttng_kernel_channel_buffer_private, parent);
+ if (chan_buf_priv->channel_type != METADATA_CHANNEL)
+ lib_ring_buffer_set_quiescent_channel(chan_buf_priv->rb_chan);
}
end:
mutex_unlock(&sessions_mutex);
int lttng_session_metadata_regenerate(struct lttng_kernel_session *session)
{
int ret = 0;
- struct lttng_kernel_channel_buffer_private *chan_priv;
+ struct lttng_kernel_channel_common_private *chan_priv;
struct lttng_kernel_event_recorder_private *event_recorder_priv;
struct lttng_metadata_cache *cache = session->priv->metadata_cache;
struct lttng_metadata_stream *stream;
session->priv->metadata_dumped = 0;
list_for_each_entry(chan_priv, &session->priv->chan_head, node) {
- chan_priv->metadata_dumped = 0;
+ struct lttng_kernel_channel_buffer_private *chan_buf_priv;
+
+ if (chan_priv->pub->type != LTTNG_KERNEL_CHANNEL_TYPE_BUFFER)
+ continue;
+ chan_buf_priv = container_of(chan_priv, struct lttng_kernel_channel_buffer_private, parent);
+ chan_buf_priv->metadata_dumped = 0;
}
list_for_each_entry(event_recorder_priv, &session->priv->events_head, parent.parent.node) {
chan->parent.enabled = 1;
chan->priv->transport = transport;
chan->priv->channel_type = channel_type;
- list_add(&chan->priv->node, &session->priv->chan_head);
+ list_add(&chan->priv->parent.node, &session->priv->chan_head);
mutex_unlock(&sessions_mutex);
return chan;
* Needs to be called with sessions mutex held.
*/
static
-void _lttng_channel_destroy(struct lttng_kernel_channel_buffer *chan)
+void lttng_kernel_buffer_destroy(struct lttng_kernel_channel_buffer *chan)
{
chan->ops->priv->channel_destroy(chan->priv->rb_chan);
module_put(chan->priv->transport->owner);
- list_del(&chan->priv->node);
lttng_kernel_destroy_context(chan->priv->ctx);
kfree(chan->priv);
kfree(chan);
}
-void lttng_metadata_channel_destroy(struct lttng_kernel_channel_buffer *chan)
+static
+void _lttng_channel_destroy(struct lttng_kernel_channel_common *chan)
+{
+ list_del(&chan->priv->node);
+
+ switch (chan->type) {
+ case LTTNG_KERNEL_CHANNEL_TYPE_BUFFER:
+ {
+ struct lttng_kernel_channel_buffer *chan_buf =
+ container_of(chan, struct lttng_kernel_channel_buffer, parent);
+ lttng_kernel_buffer_destroy(chan_buf);
+ break;
+ }
+ case LTTNG_KERNEL_CHANNEL_TYPE_COUNTER:
+ {
+ struct lttng_kernel_channel_counter *chan_counter =
+ container_of(chan, struct lttng_kernel_channel_counter, parent);
+ lttng_kernel_counter_destroy(chan_counter);
+ break;
+ }
+ default:
+ WARN_ON_ONCE(1);
+ }
+}
+
+void lttng_metadata_channel_buffer_destroy(struct lttng_kernel_channel_buffer *chan)
{
BUG_ON(chan->priv->channel_type != METADATA_CHANNEL);
/* Protect the metadata cache with the sessions_mutex. */
mutex_lock(&sessions_mutex);
- _lttng_channel_destroy(chan);
+ _lttng_channel_destroy(&chan->parent);
mutex_unlock(&sessions_mutex);
}
-EXPORT_SYMBOL_GPL(lttng_metadata_channel_destroy);
+EXPORT_SYMBOL_GPL(lttng_metadata_channel_buffer_destroy);
static
void _lttng_metadata_channel_hangup(struct lttng_metadata_stream *stream)
}
ret = lttng_kernel_event_notifier_clear_error_counter(event);
- if (ret)
+ if (ret) {
goto register_error;
+ }
hlist_add_head(&event->priv->hlist_node, head);
list_add(&event->priv->node, event_list_head);
unsigned char *uuid_c = session->priv->uuid.b;
unsigned char uuid_s[37], clock_uuid_s[BOOT_ID_LEN];
const char *product_uuid;
- struct lttng_kernel_channel_buffer_private *chan_priv;
+ struct lttng_kernel_channel_common_private *chan_priv;
struct lttng_kernel_event_recorder_private *event_recorder_priv;
int ret = 0;
skip_session:
list_for_each_entry(chan_priv, &session->priv->chan_head, node) {
- ret = _lttng_channel_metadata_statedump(session, chan_priv->pub);
+ struct lttng_kernel_channel_buffer_private *chan_buf_priv;
+
+ if (chan_priv->pub->type != LTTNG_KERNEL_CHANNEL_TYPE_BUFFER)
+ continue;
+ chan_buf_priv = container_of(chan_priv, struct lttng_kernel_channel_buffer_private, parent);
+ ret = _lttng_channel_metadata_statedump(session, chan_buf_priv->pub);
if (ret)
goto end;
}