Fix: ensure kernel context is in a list before trying to delete it
[lttng-tools.git] / src / bin / lttng-sessiond / kernel.c
index bf9f8b623288eb2e7eb58652bb5f26493ecf399e..2cbed381870a096350a4e8ac77ec39845850d0f1 100644 (file)
@@ -15,9 +15,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#define _GNU_SOURCE
 #define _LGPL_SOURCE
-#include <errno.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -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,31 @@ 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;
        }
+       ret = 0;
 
+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 +188,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 +198,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 +208,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,7 +220,6 @@ int kernel_create_event(struct lttng_event *ev,
                default:
                        PERROR("create event ioctl");
                }
-               ret = -errno;
                goto free_event;
        }
 
@@ -217,6 +231,26 @@ int kernel_create_event(struct lttng_event *ev,
                PERROR("fcntl session fd");
        }
 
+       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++;
@@ -225,6 +259,16 @@ int kernel_create_event(struct lttng_event *ev,
 
        return 0;
 
+enable_error:
+filter_error:
+       {
+               int closeret;
+
+               closeret = close(event->fd);
+               if (closeret) {
+                       PERROR("close event fd");
+               }
+       }
 free_event:
        free(event);
 error:
@@ -243,7 +287,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;
        }
 
@@ -266,7 +309,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;
        }
@@ -291,7 +334,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;
@@ -322,7 +365,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;
@@ -345,16 +388,46 @@ error:
 
 int kernel_track_pid(struct ltt_kernel_session *session, int pid)
 {
+       int ret;
+
        DBG("Kernel track PID %d for session id %" PRIu64 ".",
                        pid, session->id);
-       return kernctl_track_pid(session->fd, pid);
+       ret = kernctl_track_pid(session->fd, pid);
+       if (!ret) {
+               return LTTNG_OK;
+       }
+       switch (-ret) {
+       case EINVAL:
+               return LTTNG_ERR_INVALID;
+       case ENOMEM:
+               return LTTNG_ERR_NOMEM;
+       case EEXIST:
+               return LTTNG_ERR_PID_TRACKED;
+       default:
+               return LTTNG_ERR_UNK;
+       }
 }
 
 int kernel_untrack_pid(struct ltt_kernel_session *session, int pid)
 {
+       int ret;
+
        DBG("Kernel untrack PID %d for session id %" PRIu64 ".",
                        pid, session->id);
-       return kernctl_untrack_pid(session->fd, pid);
+       ret = kernctl_untrack_pid(session->fd, pid);
+       if (!ret) {
+               return LTTNG_OK;
+       }
+       switch (-ret) {
+       case EINVAL:
+               return LTTNG_ERR_INVALID;
+       case ENOMEM:
+               return LTTNG_ERR_NOMEM;
+       case ENOENT:
+               return LTTNG_ERR_PID_NOT_TRACKED;
+       default:
+               return LTTNG_ERR_UNK;
+       }
 }
 
 ssize_t kernel_list_tracker_pids(struct ltt_kernel_session *session,
@@ -509,25 +582,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.
  */
@@ -596,17 +650,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) {
@@ -625,13 +684,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);
        }
@@ -766,7 +822,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;
        }
 
@@ -778,11 +834,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;
@@ -796,6 +852,7 @@ error_version:
        ret = -1;
 
 error:
+       ERR("Kernel tracer version check failed; kernel tracing will not be available");
        return ret;
 }
 
@@ -1037,3 +1094,35 @@ int kernel_syscall_mask(int chan_fd, char **syscall_mask, uint32_t *nr_bits)
 
        return kernctl_syscall_mask(chan_fd, syscall_mask, nr_bits);
 }
+
+/*
+ * Check for the support of the RING_BUFFER_SNAPSHOT_SAMPLE_POSITIONS via abi
+ * version number.
+ *
+ * Return 1 on success, 0 when feature is not supported, negative value in case
+ * of errors.
+ */
+int kernel_supports_ring_buffer_snapshot_sample_positions(int tracer_fd)
+{
+       int ret = 0; // Not supported by default
+       struct lttng_kernel_tracer_abi_version abi;
+
+       ret = kernctl_tracer_abi_version(tracer_fd, &abi);
+       if (ret < 0) {
+               ERR("Failed to retrieve lttng-modules ABI version");
+               goto error;
+       }
+
+       /*
+        * RING_BUFFER_SNAPSHOT_SAMPLE_POSITIONS was introduced in 2.3
+        */
+       if (abi.major >= 2 && abi.minor >= 3) {
+               /* Supported */
+               ret = 1;
+       } else {
+               /* Not supported */
+               ret = 0;
+       }
+error:
+       return ret;
+}
This page took 0.027191 seconds and 4 git commands to generate.