size_t *max_nr_elem); /* array of size nr_dimensions */
};
+struct lttng_counter_map_descriptor {
+ uint64_t user_token;
+ size_t array_index;
+ char key[LTTNG_KERNEL_ABI_COUNTER_KEY_LEN];
+};
+
+struct lttng_counter_map {
+ struct lttng_counter_map_descriptor *descriptors;
+ size_t nr_descriptors;
+ size_t alloc_len;
+ struct mutex lock; /* counter map lock */
+};
+
struct lttng_kernel_channel_counter_private {
struct lttng_kernel_channel_common_private parent;
struct lib_counter *counter;
struct lttng_kernel_channel_counter_ops *ops;
+ struct lttng_counter_map map;
+
/* Owned either by session or event notifier group. */
/* Session or event notifier group file owner. */
uint64_t *id);
};
-struct lttng_counter_map_descriptor {
- uint64_t user_token;
- size_t array_index;
- char key[LTTNG_KERNEL_ABI_COUNTER_KEY_LEN];
-};
-
-struct lttng_counter_map {
- struct lttng_counter_map_descriptor *descriptors;
- size_t nr_descriptors;
- size_t alloc_len;
- struct mutex lock; /* counter map lock */
-};
-
#define LTTNG_EVENT_HT_BITS 12
#define LTTNG_EVENT_HT_SIZE (1U << LTTNG_EVENT_HT_BITS)
return lttng_channel_enable(&counter->parent);
case LTTNG_KERNEL_ABI_DISABLE:
return lttng_channel_disable(&counter->parent);
+ case LTTNG_KERNEL_ABI_SYSCALL_MASK:
+ return lttng_syscall_table_get_active_mask(&counter->priv->parent.syscall_table,
+ (struct lttng_kernel_abi_syscall_mask __user *) arg);
+ case LTTNG_KERNEL_ABI_COUNTER_MAP_NR_DESCRIPTORS:
+ {
+ uint64_t __user *user_nr_descriptors = (uint64_t __user *) arg;
+ uint64_t nr_descriptors;
+
+ mutex_lock(&counter->priv->map.lock);
+ nr_descriptors = counter->priv->map.nr_descriptors;
+ mutex_unlock(&counter->priv->map.lock);
+ return put_user(nr_descriptors, user_nr_descriptors);
+ }
+ case LTTNG_KERNEL_ABI_COUNTER_MAP_DESCRIPTOR:
+ {
+ struct lttng_kernel_abi_counter_map_descriptor __user *user_descriptor =
+ (struct lttng_kernel_abi_counter_map_descriptor __user *) arg;
+ struct lttng_kernel_abi_counter_map_descriptor local_descriptor;
+ struct lttng_counter_map_descriptor *kernel_descriptor;
+ int ret;
+
+ if (copy_from_user(&local_descriptor, user_descriptor,
+ sizeof(local_descriptor)))
+ return -EFAULT;
+ if (validate_zeroed_padding(local_descriptor.padding,
+ sizeof(local_descriptor.padding)))
+ return -EINVAL;
+
+ mutex_lock(&counter->priv->map.lock);
+ if (local_descriptor.descriptor_index >= counter->priv->map.nr_descriptors) {
+ ret = -EOVERFLOW;
+ goto map_descriptor_error_unlock;
+ }
+ kernel_descriptor = &counter->priv->map.descriptors[local_descriptor.descriptor_index];
+ local_descriptor.user_token = kernel_descriptor->user_token;
+ local_descriptor.array_index = kernel_descriptor->array_index;
+ memcpy(local_descriptor.key, kernel_descriptor->key, LTTNG_KERNEL_ABI_COUNTER_KEY_LEN);
+ mutex_unlock(&counter->priv->map.lock);
+
+ if (copy_to_user(user_descriptor, &local_descriptor,
+ sizeof(local_descriptor)))
+ return -EFAULT;
+
+ return 0;
+
+ map_descriptor_error_unlock:
+ mutex_unlock(&counter->priv->map.lock);
+ return ret;
+ }
default:
return -ENOSYS;
}
counter->ops = &counter_transport->ops;
counter->priv->parent.coalesce_hits = coalesce_hits;
counter->priv->transport = counter_transport;
+ mutex_init(&counter->priv->map.lock);
return counter;
struct lttng_counter_transport *counter_transport = counter->priv->transport;
counter->ops->priv->counter_destroy(counter);
+ lttng_kvfree(counter->priv->map.descriptors);
module_put(counter_transport->owner);
}
}
}
+static
+int lttng_counter_append_descriptor(struct lttng_kernel_channel_counter *counter,
+ uint64_t user_token,
+ size_t index,
+ const char *key)
+{
+ struct lttng_counter_map *map = &counter->priv->map;
+ struct lttng_counter_map_descriptor *last;
+ int ret = 0;
+
+ if (strlen(key) >= LTTNG_KERNEL_ABI_COUNTER_KEY_LEN) {
+ WARN_ON_ONCE(1);
+ return -EOVERFLOW;
+ }
+ mutex_lock(&map->lock);
+ if (map->nr_descriptors == map->alloc_len) {
+ struct lttng_counter_map_descriptor *new_table, *old_table;
+ size_t old_len = map->nr_descriptors;
+ size_t new_len = max_t(size_t, old_len + 1, map->alloc_len * 2);
+
+ old_table = map->descriptors;
+ new_table = lttng_kvzalloc(sizeof(struct lttng_counter_map_descriptor) * new_len,
+ GFP_KERNEL);
+ if (!new_table) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ if (old_table)
+ memcpy(new_table, old_table, old_len * sizeof(struct lttng_counter_map_descriptor));
+
+ map->descriptors = new_table;
+ map->alloc_len = new_len;
+ lttng_kvfree(old_table);
+ }
+ last = &map->descriptors[map->nr_descriptors++];
+ last->user_token = user_token;
+ last->array_index = index;
+ strcpy(last->key, key);
+unlock:
+ mutex_unlock(&map->lock);
+ return ret;
+}
+
+static
+int lttng_append_event_to_channel_map(struct lttng_event_enabler_common *event_enabler,
+ struct lttng_kernel_event_common *event,
+ const char *event_name)
+{
+ struct lttng_event_counter_enabler *event_counter_enabler;
+ struct lttng_kernel_channel_counter *chan_counter;
+ struct lttng_kernel_event_counter *event_counter;
+ const char *name = "<UNKNOWN>";
+
+ if (event_enabler->enabler_type != LTTNG_EVENT_ENABLER_TYPE_COUNTER)
+ return 0;
+ event_counter_enabler = container_of(event_enabler, struct lttng_event_counter_enabler, parent.parent);
+ event_counter = container_of(event, struct lttng_kernel_event_counter, parent);
+ chan_counter = event_counter_enabler->chan;
+ if (event_counter->priv->key[0])
+ name = event_counter->priv->key;
+ else
+ name = event_name;
+ return lttng_counter_append_descriptor(chan_counter, event_enabler->user_token,
+ event_counter->priv->parent.id, name);
+}
+
/*
* Supports event creation while tracing session is active.
* Needs to be called with sessions mutex held.
}
ret = try_module_get(event->priv->desc->owner);
WARN_ON_ONCE(!ret);
+ ret = lttng_append_event_to_channel_map(event_enabler, event, event_name);
+ WARN_ON_ONCE(ret);
break;
case LTTNG_KERNEL_ABI_KRETPROBE:
goto statedump_error;
}
list_add(&event_return->priv->node, event_list_head);
+ ret = lttng_append_event_to_channel_map(event_enabler, event, event_name);
+ WARN_ON_ONCE(ret);
+ ret = lttng_append_event_to_channel_map(event_enabler, event_return, event_name);
+ WARN_ON_ONCE(ret);
break;
}
goto register_error;
ret = try_module_get(event->priv->desc->owner);
WARN_ON_ONCE(!ret);
+ ret = lttng_append_event_to_channel_map(event_enabler, event, event_name);
+ WARN_ON_ONCE(ret);
break;
default:
enabler_ref = lttng_enabler_ref(&event_priv->enablers_ref_head, event_enabler);
if (!enabler_ref) {
+ int ret;
+
/*
* If no backward ref, create it.
* Add backward ref from event_notifier to enabler.
enabler_ref->ref = event_enabler;
list_add(&enabler_ref->node, &event_priv->enablers_ref_head);
+
+ ret = lttng_append_event_to_channel_map(event_enabler, event,
+ event->priv->desc->event_name);
+ WARN_ON_ONCE(ret);
}
lttng_event_enabler_init_event_filter(event_enabler, event);