From: Mathieu Desnoyers Date: Thu, 24 Mar 2022 16:21:10 +0000 (-0400) Subject: Implement counter configuration/dimensions extensible ABI X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=81ab5b77778a1a584c75bef76da7b046ca6f28f6;p=lttng-modules.git Implement counter configuration/dimensions extensible ABI Signed-off-by: Mathieu Desnoyers Change-Id: I0660738c60a128b57a6975e65db5bf2a1562a323 --- diff --git a/include/lttng/events-internal.h b/include/lttng/events-internal.h index 2274de7d..b4d2277b 100644 --- a/include/lttng/events-internal.h +++ b/include/lttng/events-internal.h @@ -18,6 +18,7 @@ struct lttng_metadata_cache; struct perf_event; struct perf_event_attr; struct lttng_kernel_ring_buffer_config; +struct lttng_kernel_counter_dimension; enum lttng_enabler_format_type { LTTNG_ENABLER_FORMAT_STAR_GLOB, @@ -50,14 +51,6 @@ struct lttng_counter_key { struct lttng_counter_key_dimension key_dimensions[LTTNG_COUNTER_DIMENSION_MAX]; }; -struct lttng_counter_dimension { - uint64_t size; - uint64_t underflow_index; - uint64_t overflow_index; - uint8_t has_underflow; - uint8_t has_overflow; -}; - enum lttng_kernel_event_enabler_type { LTTNG_EVENT_ENABLER_TYPE_RECORDER, LTTNG_EVENT_ENABLER_TYPE_NOTIFIER, @@ -241,7 +234,7 @@ struct lttng_kernel_channel_counter_ops_private { struct lttng_kernel_channel_counter_ops *pub; /* Public channel counter ops interface */ struct lttng_kernel_channel_counter *(*counter_create)(size_t nr_dimensions, - const struct lttng_counter_dimension *dimensions, + const struct lttng_kernel_counter_dimension *dimensions, int64_t global_sum_step); void (*counter_destroy)(struct lttng_kernel_channel_counter *counter); int (*counter_add)(struct lttng_kernel_channel_counter *counter, @@ -613,6 +606,42 @@ struct lttng_kernel_id_tracker_private { enum tracker_type tracker_type; }; +enum lttng_kernel_counter_dimension_flags { + LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_UNDERFLOW = (1 << 0), + LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_OVERFLOW = (1 << 1), +}; + +enum lttng_kernel_counter_conf_flags { + LTTNG_KERNEL_COUNTER_CONF_FLAG_COALESCE_HITS = (1 << 0), +}; + +enum lttng_kernel_counter_arithmetic { + LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR = 0, +}; + +enum lttng_kernel_counter_bitness { + LTTNG_KERNEL_COUNTER_BITNESS_32 = 0, + LTTNG_KERNEL_COUNTER_BITNESS_64 = 1, +}; + +/* Internally, only 1 dimension is supported fow now. */ +#define LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS 1 + +struct lttng_kernel_counter_dimension { + uint32_t flags; /* enum lttng_kernel_counter_dimension_flags */ + uint64_t size; /* dimension size */ + uint64_t underflow_index; + uint64_t overflow_index; +}; + +struct lttng_kernel_counter_conf { + uint32_t flags; /* enum lttng_kernel_counter_conf_flags */ + uint32_t arithmetic; /* enum lttng_kernel_counter_arithmetic */ + uint32_t bitness; /* enum lttng_kernel_counter_bitness */ + int64_t global_sum_step; + struct lttng_kernel_counter_dimension dimension_array[LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS]; +}; + extern struct lttng_kernel_ctx *lttng_static_ctx; static inline @@ -1195,7 +1224,7 @@ void metadata_cache_destroy(struct kref *kref); struct lttng_kernel_channel_counter *lttng_kernel_counter_create( const char *counter_transport_name, size_t number_dimensions, - const struct lttng_counter_dimension *dimensions, + const struct lttng_kernel_counter_dimension *dimensions, int64_t global_sum_step, bool coalesce_hits); int lttng_kernel_counter_read(struct lttng_kernel_channel_counter *counter, diff --git a/src/lttng-abi.c b/src/lttng-abi.c index cfa1307a..2a8d79ed 100644 --- a/src/lttng-abi.c +++ b/src/lttng-abi.c @@ -81,7 +81,7 @@ int lttng_abi_create_event_counter_enabler(struct file *channel_file, static long lttng_abi_session_create_counter( struct lttng_kernel_session *session, - const struct lttng_kernel_abi_old_counter_conf *counter_conf); + const struct lttng_kernel_counter_conf *counter_conf); static int validate_zeroed_padding(char *p, size_t len) { @@ -905,6 +905,128 @@ enum tracker_type get_tracker_type(struct lttng_kernel_abi_tracker_args *tracker } } +static +int lttng_abi_copy_user_old_counter_conf(struct lttng_kernel_counter_conf *counter_conf, + struct lttng_kernel_abi_old_counter_conf __user *old_ucounter_conf) +{ + struct lttng_kernel_abi_old_counter_conf old_kcounter_conf; + struct lttng_kernel_counter_dimension *dimension; + int ret; + + ret = copy_from_user(&old_kcounter_conf, old_ucounter_conf, + sizeof(old_kcounter_conf)); + if (ret) + return ret; + if (!old_kcounter_conf.number_dimensions || + old_kcounter_conf.number_dimensions > LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS) + return -EINVAL; + switch (old_kcounter_conf.arithmetic) { + case LTTNG_KERNEL_ABI_COUNTER_ARITHMETIC_MODULAR: + counter_conf->arithmetic = LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR; + break; + default: + return -EINVAL; + } + switch (old_kcounter_conf.bitness) { + case LTTNG_KERNEL_ABI_COUNTER_BITNESS_32: + counter_conf->bitness = LTTNG_KERNEL_COUNTER_BITNESS_32; + break; + case LTTNG_KERNEL_ABI_COUNTER_BITNESS_64: + counter_conf->bitness = LTTNG_KERNEL_COUNTER_BITNESS_64; + break; + default: + return -EINVAL; + } + counter_conf->global_sum_step = old_kcounter_conf.global_sum_step; + counter_conf->flags |= old_kcounter_conf.coalesce_hits ? + LTTNG_KERNEL_COUNTER_CONF_FLAG_COALESCE_HITS : 0; + dimension = &counter_conf->dimension_array[0]; + dimension->flags |= old_kcounter_conf.dimensions[0].has_underflow ? + LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_UNDERFLOW : 0; + dimension->flags |= old_kcounter_conf.dimensions[0].has_overflow ? + LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_OVERFLOW : 0; + dimension->size = old_kcounter_conf.dimensions[0].size; + dimension->underflow_index = old_kcounter_conf.dimensions[0].underflow_index; + dimension->overflow_index = old_kcounter_conf.dimensions[0].overflow_index; + return 0; +} + +static +int lttng_abi_copy_user_counter_conf(struct lttng_kernel_counter_conf *counter_conf, + struct lttng_kernel_abi_counter_conf __user *ucounter_conf) +{ + uint32_t len, number_dimensions; + struct lttng_kernel_abi_counter_conf kcounter_conf = {}; + struct lttng_kernel_counter_dimension *dimension; + struct lttng_kernel_abi_counter_dimension kdimension = {}; + struct lttng_kernel_abi_counter_dimension __user *udimension; + int ret; + + ret = get_user(len, &ucounter_conf->len); + if (ret) + return ret; + if (len < offsetofend(struct lttng_kernel_abi_counter_conf, dimension_array)) + return -EINVAL; + if (len > PAGE_SIZE) + return -EINVAL; + + ret = lttng_copy_struct_from_user(&kcounter_conf, sizeof(kcounter_conf), ucounter_conf, len); + if (ret) + return ret; + + /* Validate flags and enumerations */ + switch (kcounter_conf.arithmetic) { + case LTTNG_KERNEL_ABI_COUNTER_ARITHMETIC_MODULAR: + counter_conf->arithmetic = LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR; + break; + default: + return -EINVAL; + } + switch (kcounter_conf.bitness) { + case LTTNG_KERNEL_ABI_COUNTER_BITNESS_32: + counter_conf->bitness = LTTNG_KERNEL_COUNTER_BITNESS_32; + break; + case LTTNG_KERNEL_ABI_COUNTER_BITNESS_64: + counter_conf->bitness = LTTNG_KERNEL_COUNTER_BITNESS_64; + break; + default: + return -EINVAL; + } + if (kcounter_conf.flags & ~LTTNG_KERNEL_ABI_COUNTER_CONF_FLAG_COALESCE_HITS) + return -EINVAL; + counter_conf->global_sum_step = kcounter_conf.global_sum_step; + counter_conf->flags |= (kcounter_conf.flags & LTTNG_KERNEL_ABI_COUNTER_CONF_FLAG_COALESCE_HITS) ? + LTTNG_KERNEL_COUNTER_CONF_FLAG_COALESCE_HITS : 0; + + number_dimensions = kcounter_conf.dimension_array.number_dimensions; + if (!number_dimensions || number_dimensions > LTTNG_KERNEL_COUNTER_MAX_DIMENSIONS) + return -EINVAL; + dimension = &counter_conf->dimension_array[0]; + len = kcounter_conf.dimension_array.elem_len; + if (len > PAGE_SIZE) + return -E2BIG; + if (len < offsetofend(struct lttng_kernel_abi_counter_dimension, overflow_index)) + return -EINVAL; + udimension = (struct lttng_kernel_abi_counter_dimension __user *)(unsigned long)kcounter_conf.dimension_array.ptr; + ret = lttng_copy_struct_from_user(&kdimension, sizeof(kdimension), udimension, len); + if (ret) + return ret; + + /* Validate flags */ + if (kdimension.flags & ~(LTTNG_KERNEL_ABI_COUNTER_DIMENSION_FLAG_UNDERFLOW | + LTTNG_KERNEL_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW)) + return -EINVAL; + + dimension->flags |= (kdimension.flags & LTTNG_KERNEL_ABI_COUNTER_DIMENSION_FLAG_UNDERFLOW) ? + LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_UNDERFLOW : 0; + dimension->flags |= (kdimension.flags & LTTNG_KERNEL_ABI_COUNTER_DIMENSION_FLAG_OVERFLOW) ? + LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_OVERFLOW : 0; + dimension->size = kdimension.size; + dimension->underflow_index = kdimension.underflow_index; + dimension->overflow_index = kdimension.overflow_index; + return 0; +} + /** * lttng_session_ioctl - lttng session fd ioctl * @@ -938,6 +1060,7 @@ long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct lttng_kernel_session *session = file->private_data; struct lttng_kernel_abi_channel chan_param; struct lttng_kernel_abi_old_channel old_chan_param; + int ret; /* * Handle backward compatibility. OLD commands have wrong @@ -1104,18 +1227,16 @@ long lttng_session_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -EFAULT; return lttng_abi_session_set_creation_time(session, &time); } - //TODO: remove implementation of LTTNG_KERNEL_ABI_OLD_COUNTER which has never been exposed. - case LTTNG_KERNEL_ABI_OLD_COUNTER: + case LTTNG_KERNEL_ABI_COUNTER: { - struct lttng_kernel_abi_old_counter_conf counter_conf; + struct lttng_kernel_counter_conf counter_conf; - if (copy_from_user(&counter_conf, - (struct lttng_kernel_abi_old_counter_conf __user *) arg, - sizeof(struct lttng_kernel_abi_old_counter_conf))) - return -EFAULT; + ret = lttng_abi_copy_user_counter_conf(&counter_conf, + (struct lttng_kernel_abi_counter_conf __user *) arg); + if (ret) + return ret; return lttng_abi_session_create_counter(session, &counter_conf); } - //TODO: implement LTTNG_KERNEL_ABI_COUNTER default: return -ENOIOCTLCMD; } @@ -2655,34 +2776,26 @@ inval_instr: return ret; } -//TODO: update to 2.14 struct lttng_kernel_abi_counter_conf static long lttng_abi_session_create_counter( struct lttng_kernel_session *session, - const struct lttng_kernel_abi_old_counter_conf *counter_conf) + const struct lttng_kernel_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) { + if (counter_conf->arithmetic != LTTNG_KERNEL_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: + case LTTNG_KERNEL_COUNTER_BITNESS_64: counter_transport_name = "counter-per-cpu-64-modular"; break; - case LTTNG_KERNEL_ABI_COUNTER_BITNESS_32: + case LTTNG_KERNEL_COUNTER_BITNESS_32: counter_transport_name = "counter-per-cpu-32-modular"; break; default: @@ -2705,20 +2818,13 @@ long lttng_abi_session_create_counter( 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); + chan_counter = lttng_kernel_counter_create(counter_transport_name, 1, counter_conf->dimension_array, 0, + counter_conf->flags & LTTNG_KERNEL_COUNTER_CONF_FLAG_COALESCE_HITS); if (!chan_counter) { ret = -EINVAL; goto create_error; @@ -2746,11 +2852,10 @@ fd_error: return ret; } -//TODO: update to expect struct struct lttng_kernel_abi_counter_conf static long lttng_abi_event_notifier_group_create_error_counter( struct file *event_notifier_group_file, - const struct lttng_kernel_abi_old_counter_conf *error_counter_conf) + const struct lttng_kernel_counter_conf *counter_conf) { int counter_fd, ret; char *counter_transport_name; @@ -2758,24 +2863,18 @@ long lttng_abi_event_notifier_group_create_error_counter( struct file *counter_file; struct lttng_event_notifier_group *event_notifier_group = (struct lttng_event_notifier_group *) event_notifier_group_file->private_data; - struct lttng_counter_dimension dimensions[1]; size_t counter_len; - if (error_counter_conf->arithmetic != LTTNG_KERNEL_ABI_COUNTER_ARITHMETIC_MODULAR) { + if (counter_conf->arithmetic != LTTNG_KERNEL_COUNTER_ARITHMETIC_MODULAR) { printk(KERN_ERR "LTTng: event_notifier: Error counter of the wrong arithmetic type.\n"); return -EINVAL; } - if (error_counter_conf->number_dimensions != 1) { - printk(KERN_ERR "LTTng: event_notifier: Error counter has more than one dimension.\n"); - return -EINVAL; - } - - switch (error_counter_conf->bitness) { - case LTTNG_KERNEL_ABI_COUNTER_BITNESS_64: + switch (counter_conf->bitness) { + case LTTNG_KERNEL_COUNTER_BITNESS_64: counter_transport_name = "counter-per-cpu-64-modular"; break; - case LTTNG_KERNEL_ABI_COUNTER_BITNESS_32: + case LTTNG_KERNEL_COUNTER_BITNESS_32: counter_transport_name = "counter-per-cpu-32-modular"; break; default: @@ -2809,19 +2908,13 @@ long lttng_abi_event_notifier_group_create_error_counter( goto file_error; } - counter_len = error_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(&event_notifier_group_file->f_count, 1, LONG_MAX)) { ret = -EOVERFLOW; goto refcount_error; } - chan_counter = lttng_kernel_counter_create(counter_transport_name, 1, dimensions, 0, false); + counter_len = counter_conf->dimension_array[0].size; + chan_counter = lttng_kernel_counter_create(counter_transport_name, 1, counter_conf->dimension_array, 0, false); if (!chan_counter) { ret = -EINVAL; goto create_error; @@ -2859,6 +2952,8 @@ static long lttng_event_notifier_group_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + int ret; + switch (cmd) { case LTTNG_KERNEL_ABI_EVENT_NOTIFIER_GROUP_NOTIFICATION_FD: { @@ -2881,16 +2976,24 @@ long lttng_event_notifier_group_ioctl(struct file *file, unsigned int cmd, } case LTTNG_KERNEL_ABI_OLD_COUNTER: { - struct lttng_kernel_abi_old_counter_conf uerror_counter_conf; + struct lttng_kernel_counter_conf counter_conf = {}; - if (copy_from_user(&uerror_counter_conf, - (struct lttng_kernel_abi_counter_conf __user *) arg, - sizeof(uerror_counter_conf))) - return -EFAULT; - return lttng_abi_event_notifier_group_create_error_counter(file, - &uerror_counter_conf); + ret = lttng_abi_copy_user_old_counter_conf(&counter_conf, + (struct lttng_kernel_abi_old_counter_conf __user *) arg); + if (ret) + return ret; + return lttng_abi_event_notifier_group_create_error_counter(file, &counter_conf); + } + case LTTNG_KERNEL_ABI_COUNTER: + { + struct lttng_kernel_counter_conf counter_conf = {}; + + ret = lttng_abi_copy_user_counter_conf(&counter_conf, + (struct lttng_kernel_abi_counter_conf __user *) arg); + if (ret) + return ret; + return lttng_abi_event_notifier_group_create_error_counter(file, &counter_conf); } - //TODO: implement LTTNG_KERNEL_ABI_COUNTER default: return -ENOIOCTLCMD; } diff --git a/src/lttng-counter-client-percpu-32-modular.c b/src/lttng-counter-client-percpu-32-modular.c index 55deadb9..277e8fc4 100644 --- a/src/lttng-counter-client-percpu-32-modular.c +++ b/src/lttng-counter-client-percpu-32-modular.c @@ -23,7 +23,7 @@ static const struct lib_counter_config client_config = { }; static struct lttng_kernel_channel_counter *counter_create(size_t nr_dimensions, - const struct lttng_counter_dimension *dimensions, + const struct lttng_kernel_counter_dimension *dimensions, int64_t global_sum_step) { size_t max_nr_elem[LTTNG_COUNTER_DIMENSION_MAX], i; @@ -33,7 +33,8 @@ static struct lttng_kernel_channel_counter *counter_create(size_t nr_dimensions, if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX) return NULL; for (i = 0; i < nr_dimensions; i++) { - if (dimensions[i].has_underflow || dimensions[i].has_overflow) + if ((dimensions[i].flags & LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_UNDERFLOW) + || (dimensions[i].flags & LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_OVERFLOW)) return NULL; max_nr_elem[i] = dimensions[i].size; } diff --git a/src/lttng-counter-client-percpu-64-modular.c b/src/lttng-counter-client-percpu-64-modular.c index 973d6426..2d5b6ac0 100644 --- a/src/lttng-counter-client-percpu-64-modular.c +++ b/src/lttng-counter-client-percpu-64-modular.c @@ -23,7 +23,7 @@ static const struct lib_counter_config client_config = { }; static struct lttng_kernel_channel_counter *counter_create(size_t nr_dimensions, - const struct lttng_counter_dimension *dimensions, + const struct lttng_kernel_counter_dimension *dimensions, int64_t global_sum_step) { size_t max_nr_elem[LTTNG_COUNTER_DIMENSION_MAX], i; @@ -33,7 +33,8 @@ static struct lttng_kernel_channel_counter *counter_create(size_t nr_dimensions, if (nr_dimensions > LTTNG_COUNTER_DIMENSION_MAX) return NULL; for (i = 0; i < nr_dimensions; i++) { - if (dimensions[i].has_underflow || dimensions[i].has_overflow) + if ((dimensions[i].flags & LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_UNDERFLOW) + || (dimensions[i].flags & LTTNG_KERNEL_COUNTER_DIMENSION_FLAG_OVERFLOW)) return NULL; max_nr_elem[i] = dimensions[i].size; } diff --git a/src/lttng-events.c b/src/lttng-events.c index 164ab196..007fe80e 100644 --- a/src/lttng-events.c +++ b/src/lttng-events.c @@ -237,7 +237,7 @@ struct lttng_counter_transport *lttng_counter_transport_find(const char *name) struct lttng_kernel_channel_counter *lttng_kernel_counter_create( const char *counter_transport_name, size_t number_dimensions, - const struct lttng_counter_dimension *dimensions, + const struct lttng_kernel_counter_dimension *dimensions, int64_t global_sum_step, bool coalesce_hits) {