X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fkernel.c;h=a72fe7f5c977ac76cd351555ec170b5781977191;hb=de04bbc88637bb336255f6cc7c7e4f4ea179f40d;hp=6b404c0ed97f260d3517d91044315ff8877ec9d7;hpb=d069d57732e9a19624078b6e8ca424dbd5827fc0;p=lttng-tools.git diff --git a/src/bin/lttng-sessiond/kernel.c b/src/bin/lttng-sessiond/kernel.c index 6b404c0ed..a72fe7f5c 100644 --- a/src/bin/lttng-sessiond/kernel.c +++ b/src/bin/lttng-sessiond/kernel.c @@ -15,9 +15,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE #define _LGPL_SOURCE -#include #include #include #include @@ -38,6 +36,8 @@ /* * Add context on a kernel channel. + * + * Assumes the ownership of ctx. */ int kernel_add_channel_context(struct ltt_kernel_channel *chan, struct ltt_kernel_context *ctx) @@ -50,20 +50,30 @@ int kernel_add_channel_context(struct ltt_kernel_channel *chan, DBG("Adding context to channel %s", chan->channel->name); ret = kernctl_add_context(chan->fd, &ctx->ctx); if (ret < 0) { - if (errno != EEXIST) { - PERROR("add context ioctl"); - } else { + switch (-ret) { + case ENOSYS: + /* Exists but not available for this kernel */ + ret = LTTNG_ERR_KERN_CONTEXT_UNAVAILABLE; + goto error; + case EEXIST: /* If EEXIST, we just ignore the error */ ret = 0; + goto end; + default: + PERROR("add context ioctl"); + ret = LTTNG_ERR_KERN_CONTEXT_FAIL; + goto error; } - goto error; } +end: cds_list_add_tail(&ctx->list, &chan->ctx_list); - - return 0; - + ctx->in_list = true; + ctx = NULL; error: + if (ctx) { + trace_kernel_destroy_context(ctx); + } return ret; } @@ -177,7 +187,9 @@ error: * We own filter_expression and filter. */ int kernel_create_event(struct lttng_event *ev, - struct ltt_kernel_channel *channel) + struct ltt_kernel_channel *channel, + char *filter_expression, + struct lttng_filter_bytecode *filter) { int ret; struct ltt_kernel_event *event; @@ -185,7 +197,9 @@ int kernel_create_event(struct lttng_event *ev, assert(ev); assert(channel); - event = trace_kernel_create_event(ev); + /* We pass ownership of filter_expression and filter */ + event = trace_kernel_create_event(ev, filter_expression, + filter); if (event == NULL) { ret = -1; goto error; @@ -193,7 +207,7 @@ int kernel_create_event(struct lttng_event *ev, ret = kernctl_create_event(channel->fd, event->event); if (ret < 0) { - switch (errno) { + switch (-ret) { case EEXIST: break; case ENOSYS: @@ -205,23 +219,10 @@ int kernel_create_event(struct lttng_event *ev, default: PERROR("create event ioctl"); } - ret = -errno; goto free_event; } - /* - * LTTNG_KERNEL_SYSCALL event creation will return 0 on success. - */ - if (ret == 0 && event->event->instrumentation == LTTNG_KERNEL_SYSCALL) { - DBG2("Kernel event syscall creation success"); - /* - * We use fd == -1 to ensure that we never trigger a close of fd - * 0. - */ - event->fd = -1; - goto add_list; - } - + event->type = ev->type; event->fd = ret; /* Prevent fd duplication after execlp() */ ret = fcntl(event->fd, F_SETFD, FD_CLOEXEC); @@ -229,7 +230,26 @@ int kernel_create_event(struct lttng_event *ev, PERROR("fcntl session fd"); } -add_list: + if (filter) { + ret = kernctl_filter(event->fd, filter); + if (ret) { + goto filter_error; + } + } + + ret = kernctl_enable(event->fd); + if (ret < 0) { + switch (-ret) { + case EEXIST: + ret = LTTNG_ERR_KERN_EVENT_EXIST; + break; + default: + PERROR("enable kernel event"); + break; + } + goto enable_error; + } + /* Add event to event list */ cds_list_add(&event->list, &channel->events_list.head); channel->event_count++; @@ -238,6 +258,16 @@ add_list: return 0; +enable_error: +filter_error: + { + int closeret; + + closeret = close(event->fd); + if (closeret) { + PERROR("close event fd"); + } + } free_event: free(event); error: @@ -256,7 +286,6 @@ int kernel_disable_channel(struct ltt_kernel_channel *chan) ret = kernctl_disable(chan->fd); if (ret < 0) { PERROR("disable chan ioctl"); - ret = errno; goto error; } @@ -279,7 +308,7 @@ int kernel_enable_channel(struct ltt_kernel_channel *chan) assert(chan); ret = kernctl_enable(chan->fd); - if (ret < 0 && errno != EEXIST) { + if (ret < 0 && ret != -EEXIST) { PERROR("Enable kernel chan"); goto error; } @@ -304,7 +333,7 @@ int kernel_enable_event(struct ltt_kernel_event *event) ret = kernctl_enable(event->fd); if (ret < 0) { - switch (errno) { + switch (-ret) { case EEXIST: ret = LTTNG_ERR_KERN_EVENT_EXIST; break; @@ -335,7 +364,7 @@ int kernel_disable_event(struct ltt_kernel_event *event) ret = kernctl_disable(event->fd); if (ret < 0) { - switch (errno) { + switch (-ret) { case EEXIST: ret = LTTNG_ERR_KERN_EVENT_EXIST; break; @@ -355,16 +384,274 @@ error: return ret; } -int kernel_enable_syscall(const char *syscall_name, - struct ltt_kernel_channel *channel) +static +struct lttng_tracker_list *get_id_tracker_list(struct ltt_kernel_session *session, + enum lttng_tracker_type tracker_type) { - return kernctl_enable_syscall(channel->fd, syscall_name); + switch (tracker_type) { + case LTTNG_TRACKER_PID: + return session->tracker_list_pid; + case LTTNG_TRACKER_VPID: + return session->tracker_list_vpid; + case LTTNG_TRACKER_UID: + return session->tracker_list_uid; + case LTTNG_TRACKER_VUID: + return session->tracker_list_vuid; + case LTTNG_TRACKER_GID: + return session->tracker_list_gid; + case LTTNG_TRACKER_VGID: + return session->tracker_list_vgid; + default: + return NULL; + } } -int kernel_disable_syscall(const char *syscall_name, - struct ltt_kernel_channel *channel) +int kernel_track_id(enum lttng_tracker_type tracker_type, + struct ltt_kernel_session *session, + struct lttng_tracker_id *id) { - return kernctl_disable_syscall(channel->fd, syscall_name); + int ret, value; + struct lttng_tracker_list *tracker_list; + struct lttng_tracker_id *saved_ids; + ssize_t saved_ids_count, i; + + ret = lttng_tracker_id_lookup_string(tracker_type, + id, &value); + if (ret != LTTNG_OK) { + return ret; + } + + tracker_list = get_id_tracker_list(session, tracker_type); + if (!tracker_list) { + return LTTNG_ERR_INVALID; + } + /* Save list for restore on error. */ + saved_ids_count = lttng_tracker_id_get_list(tracker_list, &saved_ids); + if (saved_ids_count < 0) { + return LTTNG_ERR_INVALID; + } + /* Add to list. */ + ret = lttng_tracker_list_add(tracker_list, id); + if (ret != LTTNG_OK) { + goto end; + } + + switch (tracker_type) { + case LTTNG_TRACKER_PID: + DBG("Kernel track PID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_track_pid(session->fd, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_VPID: + DBG("Kernel track VPID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_track_id(session->fd, LTTNG_TRACKER_VPID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_UID: + DBG("Kernel track UID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_track_id(session->fd, LTTNG_TRACKER_UID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_GID: + DBG("Kernel track GID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_track_id(session->fd, LTTNG_TRACKER_GID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_VUID: + DBG("Kernel track VUID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_track_id(session->fd, LTTNG_TRACKER_VUID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_VGID: + DBG("Kernel track VGID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_track_id(session->fd, LTTNG_TRACKER_VGID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + default: + ret = -EINVAL; + break; + } + /* Error handling. */ + switch (-ret) { + case EINVAL: + ret = LTTNG_ERR_INVALID; + break; + case ENOMEM: + ret = LTTNG_ERR_NOMEM; + break; + case EEXIST: + ret = LTTNG_ERR_ID_TRACKED; + break; + default: + ret = LTTNG_ERR_UNK; + break; + } + if (lttng_tracker_id_set_list(tracker_list, saved_ids, saved_ids_count) != LTTNG_OK) { + ERR("Error on tracker add error handling.\n"); + } +end: + for (i = 0; i < saved_ids_count; i++) { + free(saved_ids[i].string); + } + free(saved_ids); + return ret; +} + +int kernel_untrack_id(enum lttng_tracker_type tracker_type, + struct ltt_kernel_session *session, + struct lttng_tracker_id *id) +{ + int ret, value; + struct lttng_tracker_list *tracker_list; + struct lttng_tracker_id *saved_ids; + ssize_t saved_ids_count, i; + + ret = lttng_tracker_id_lookup_string(tracker_type, + id, &value); + if (ret != LTTNG_OK) { + return ret; + } + + tracker_list = get_id_tracker_list(session, tracker_type); + if (!tracker_list) { + return LTTNG_ERR_INVALID; + } + /* Save list for restore on error. */ + saved_ids_count = lttng_tracker_id_get_list(tracker_list, &saved_ids); + if (saved_ids_count < 0) { + return LTTNG_ERR_INVALID; + } + /* Remove from list. */ + ret = lttng_tracker_list_remove(tracker_list, id); + if (ret != LTTNG_OK) { + goto end; + } + + switch (tracker_type) { + case LTTNG_TRACKER_PID: + DBG("Kernel untrack PID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_untrack_pid(session->fd, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_VPID: + DBG("Kernel untrack VPID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_untrack_id(session->fd, LTTNG_TRACKER_VPID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_UID: + DBG("Kernel untrack UID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_untrack_id(session->fd, LTTNG_TRACKER_UID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_GID: + DBG("Kernel untrack GID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_untrack_id(session->fd, LTTNG_TRACKER_GID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_VUID: + DBG("Kernel untrack VUID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_untrack_id(session->fd, LTTNG_TRACKER_VUID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + case LTTNG_TRACKER_VGID: + DBG("Kernel untrack VGID %d for session id %" PRIu64 ".", + value, session->id); + ret = kernctl_untrack_id(session->fd, LTTNG_TRACKER_VGID, value); + if (!ret) { + ret = LTTNG_OK; + goto end; + } + break; + default: + ret = -EINVAL; + break; + } + + /* Error handling. */ + switch (-ret) { + case EINVAL: + ret = LTTNG_ERR_INVALID; + break; + case ENOMEM: + ret = LTTNG_ERR_NOMEM; + break; + case EEXIST: + ret = LTTNG_ERR_ID_TRACKED; + break; + default: + ret = LTTNG_ERR_UNK; + break; + } + + if (lttng_tracker_id_set_list(tracker_list, saved_ids, saved_ids_count) != LTTNG_OK) { + ERR("Error on tracker remove error handling.\n"); + } +end: + for (i = 0; i < saved_ids_count; i++) { + free(saved_ids[i].string); + } + free(saved_ids); + return ret; +} + +/* + * Called with session lock held. + */ +ssize_t kernel_list_tracker_ids(enum lttng_tracker_type tracker_type, + struct ltt_kernel_session *session, + struct lttng_tracker_id **_ids) +{ + struct lttng_tracker_list *tracker_list; + + tracker_list = get_id_tracker_list(session, tracker_type); + if (!tracker_list) { + return -LTTNG_ERR_INVALID; + } + return lttng_tracker_id_get_list(tracker_list, _ids); } /* @@ -448,25 +735,6 @@ void kernel_wait_quiescent(int fd) } } -/* - * Kernel calibrate - */ -int kernel_calibrate(int fd, struct lttng_kernel_calibrate *calibrate) -{ - int ret; - - assert(calibrate); - - ret = kernctl_calibrate(fd, calibrate); - if (ret < 0) { - PERROR("calibrate ioctl"); - return -1; - } - - return 0; -} - - /* * Force flush buffer of metadata. */ @@ -535,17 +803,22 @@ error: * Open stream of channel, register it to the kernel tracer and add it * to the stream list of the channel. * + * Note: given that the streams may appear in random order wrt CPU + * number (e.g. cpu hotplug), the index value of the stream number in + * the stream name is not necessarily linked to the CPU number. + * * Return the number of created stream. Else, a negative value. */ int kernel_open_channel_stream(struct ltt_kernel_channel *channel) { - int ret, count = 0; + int ret; struct ltt_kernel_stream *lks; assert(channel); while ((ret = kernctl_create_stream(channel->fd)) >= 0) { - lks = trace_kernel_create_stream(channel->channel->name, count); + lks = trace_kernel_create_stream(channel->channel->name, + channel->stream_count); if (lks == NULL) { ret = close(ret); if (ret) { @@ -564,13 +837,10 @@ int kernel_open_channel_stream(struct ltt_kernel_channel *channel) lks->tracefile_size = channel->channel->attr.tracefile_size; lks->tracefile_count = channel->channel->attr.tracefile_count; - /* Add stream to channe stream list */ + /* Add stream to channel stream list */ cds_list_add(&lks->list, &channel->stream_list.head); channel->stream_count++; - /* Increment counter which represent CPU number. */ - count++; - DBG("Kernel stream %s created (fd: %d, state: %d)", lks->name, lks->fd, lks->state); } @@ -705,7 +975,7 @@ int kernel_validate_version(int tracer_fd) ret = kernctl_tracer_version(tracer_fd, &version); if (ret < 0) { - ERR("Failed at getting the lttng-modules version"); + ERR("Failed to retrieve the lttng-modules version"); goto error; } @@ -717,11 +987,11 @@ int kernel_validate_version(int tracer_fd) } ret = kernctl_tracer_abi_version(tracer_fd, &abi_version); if (ret < 0) { - ERR("Failed at getting lttng-modules ABI version"); + ERR("Failed to retrieve lttng-modules ABI version"); goto error; } if (abi_version.major != LTTNG_MODULES_ABI_MAJOR_VERSION) { - ERR("Kernel tracer ABI version (%d.%d) is not compatible with expected ABI major version (%d.*)", + ERR("Kernel tracer ABI version (%d.%d) does not match the expected ABI major version (%d.*)", abi_version.major, abi_version.minor, LTTNG_MODULES_ABI_MAJOR_VERSION); goto error; @@ -735,6 +1005,7 @@ error_version: ret = -1; error: + ERR("Kernel tracer version check failed; kernel tracing will not be available"); return ret; } @@ -853,7 +1124,8 @@ void kernel_destroy_channel(struct ltt_kernel_channel *kchan) * Return 0 on success or else return a LTTNG_ERR code. */ int kernel_snapshot_record(struct ltt_kernel_session *ksess, - struct snapshot_output *output, int wait, uint64_t max_size_per_stream) + struct snapshot_output *output, int wait, + uint64_t nb_packets_per_stream) { int err, ret, saved_metadata_fd; struct consumer_socket *socket; @@ -910,12 +1182,10 @@ int kernel_snapshot_record(struct ltt_kernel_session *ksess, /* For each channel, ask the consumer to snapshot it. */ cds_list_for_each_entry(chan, &ksess->channel_list.head, list) { - pthread_mutex_lock(socket->lock); ret = consumer_snapshot_channel(socket, chan->fd, output, 0, ksess->uid, ksess->gid, DEFAULT_KERNEL_TRACE_DIR, wait, - max_size_per_stream); - pthread_mutex_unlock(socket->lock); + nb_packets_per_stream); if (ret < 0) { ret = LTTNG_ERR_KERN_CONSUMER_FAIL; (void) kernel_consumer_destroy_metadata(socket, @@ -925,11 +1195,9 @@ int kernel_snapshot_record(struct ltt_kernel_session *ksess, } /* Snapshot metadata, */ - pthread_mutex_lock(socket->lock); ret = consumer_snapshot_channel(socket, ksess->metadata->fd, output, 1, ksess->uid, ksess->gid, - DEFAULT_KERNEL_TRACE_DIR, wait, max_size_per_stream); - pthread_mutex_unlock(socket->lock); + DEFAULT_KERNEL_TRACE_DIR, wait, 0); if (ret < 0) { ret = LTTNG_ERR_KERN_CONSUMER_FAIL; goto error_consumer;