Fix: add missing rcu_barrier at end of sessiond main
[lttng-tools.git] / src / bin / lttng-sessiond / main.c
index 22dd28e1e9df1538baa242e595284580db67dc60..eb96b6a16ae2db772cc733c75a68a5045ffde2f4 100644 (file)
@@ -70,6 +70,7 @@
 #include "agent-thread.h"
 #include "save.h"
 #include "load-session-thread.h"
+#include "syscall.h"
 
 #define CONSUMERD_FILE "lttng-consumerd"
 
@@ -628,6 +629,9 @@ static void cleanup(void)
                }
        }
 
+       DBG("Cleaning up all agent apps");
+       agent_app_ht_clean();
+
        DBG("Closing all UST sockets");
        ust_app_clean_list();
        buffer_reg_destroy_registries();
@@ -642,6 +646,7 @@ static void cleanup(void)
                }
                DBG("Unloading kernel modules");
                modprobe_remove_lttng_all();
+               free(syscall_table);
        }
 
        close_consumer_sockets();
@@ -1000,12 +1005,14 @@ static void *thread_manage_kernel(void *data)
                        update_poll_flag = 0;
                }
 
-               DBG("Thread kernel polling on %d fds", LTTNG_POLL_GETNB(&events));
+               DBG("Thread kernel polling");
 
                /* Poll infinite value of time */
        restart:
                health_poll_entry();
                ret = lttng_poll_wait(&events, -1);
+               DBG("Thread kernel return from poll on %d fds",
+                               LTTNG_POLL_GETNB(&events));
                health_poll_exit();
                if (ret < 0) {
                        /*
@@ -1031,6 +1038,11 @@ static void *thread_manage_kernel(void *data)
 
                        health_code_update();
 
+                       if (!revents) {
+                               /* No activity for this FD (poll implementation). */
+                               continue;
+                       }
+
                        /* Thread quit pipe has been closed. Killing thread. */
                        ret = sessiond_check_thread_quit_pipe(pollfd, revents);
                        if (ret) {
@@ -1114,7 +1126,7 @@ static void signal_consumer_condition(struct consumer_data *data, int state)
  */
 static void *thread_manage_consumer(void *data)
 {
-       int sock = -1, i, ret, pollfd, err = -1;
+       int sock = -1, i, ret, pollfd, err = -1, should_quit = 0;
        uint32_t revents, nb_fd;
        enum lttcomm_return_code code;
        struct lttng_poll_event events;
@@ -1122,6 +1134,9 @@ static void *thread_manage_consumer(void *data)
 
        DBG("[thread] Manage consumer started");
 
+       rcu_register_thread();
+       rcu_thread_online();
+
        health_register(health_sessiond, HEALTH_SESSIOND_TYPE_CONSUMER);
 
        health_code_update();
@@ -1176,6 +1191,11 @@ restart:
 
                health_code_update();
 
+               if (!revents) {
+                       /* No activity for this FD (poll implementation). */
+                       continue;
+               }
+
                /* Thread quit pipe has been closed. Killing thread. */
                ret = sessiond_check_thread_quit_pipe(pollfd, revents);
                if (ret) {
@@ -1272,6 +1292,15 @@ restart:
        /* Infinite blocking call, waiting for transmission */
 restart_poll:
        while (1) {
+               health_code_update();
+
+               /* Exit the thread because the thread quit pipe has been triggered. */
+               if (should_quit) {
+                       /* Not a health error. */
+                       err = 0;
+                       goto exit;
+               }
+
                health_poll_entry();
                ret = lttng_poll_wait(&events, -1);
                health_poll_exit();
@@ -1294,13 +1323,18 @@ restart_poll:
 
                        health_code_update();
 
-                       /* Thread quit pipe has been closed. Killing thread. */
-                       ret = sessiond_check_thread_quit_pipe(pollfd, revents);
-                       if (ret) {
-                               err = 0;
-                               goto exit;
+                       if (!revents) {
+                               /* No activity for this FD (poll implementation). */
+                               continue;
                        }
 
+                       /*
+                        * Thread quit pipe has been triggered, flag that we should stop
+                        * but continue the current loop to handle potential data from
+                        * consumer.
+                        */
+                       should_quit = sessiond_check_thread_quit_pipe(pollfd, revents);
+
                        if (pollfd == sock) {
                                /* Event on the consumerd socket */
                                if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) {
@@ -1328,11 +1362,8 @@ restart_poll:
                                        ERR("Handling metadata request");
                                        goto error;
                                }
-                               break;
-                       } else {
-                               ERR("Unknown pollfd");
-                               goto error;
                        }
+                       /* No need for an else branch all FDs are tested prior. */
                }
                health_code_update();
        }
@@ -1404,6 +1435,9 @@ error_poll:
        health_unregister(health_sessiond);
        DBG("consumer thread cleanup completed");
 
+       rcu_thread_offline();
+       rcu_unregister_thread();
+
        return NULL;
 }
 
@@ -1447,12 +1481,14 @@ static void *thread_manage_apps(void *data)
        health_code_update();
 
        while (1) {
-               DBG("Apps thread polling on %d fds", LTTNG_POLL_GETNB(&events));
+               DBG("Apps thread polling");
 
                /* Inifinite blocking call, waiting for transmission */
        restart:
                health_poll_entry();
                ret = lttng_poll_wait(&events, -1);
+               DBG("Apps thread return from poll on %d fds",
+                               LTTNG_POLL_GETNB(&events));
                health_poll_exit();
                if (ret < 0) {
                        /*
@@ -1473,6 +1509,11 @@ static void *thread_manage_apps(void *data)
 
                        health_code_update();
 
+                       if (!revents) {
+                               /* No activity for this FD (poll implementation). */
+                               continue;
+                       }
+
                        /* Thread quit pipe has been closed. Killing thread. */
                        ret = sessiond_check_thread_quit_pipe(pollfd, revents);
                        if (ret) {
@@ -1651,6 +1692,11 @@ static void sanitize_wait_queue(struct ust_reg_wait_queue *wait_queue)
                uint32_t revents = LTTNG_POLL_GETEV(&events, i);
                int pollfd = LTTNG_POLL_GETFD(&events, i);
 
+               if (!revents) {
+                       /* No activity for this FD (poll implementation). */
+                       continue;
+               }
+
                cds_list_for_each_entry_safe(wait_node, tmp_wait_node,
                                &wait_queue->head, head) {
                        if (pollfd == wait_node->app->sock &&
@@ -1903,6 +1949,22 @@ error:
                free(wait_node);
        }
 
+       /* Empty command queue. */
+       for (;;) {
+               /* Dequeue command for registration */
+               node = cds_wfcq_dequeue_blocking(&ust_cmd_queue.head, &ust_cmd_queue.tail);
+               if (node == NULL) {
+                       break;
+               }
+               ust_cmd = caa_container_of(node, struct ust_command, node);
+               ret = close(ust_cmd->sock);
+               if (ret < 0) {
+                       PERROR("close ust sock exit dispatch %d", ust_cmd->sock);
+               }
+               lttng_fd_put(LTTNG_FD_APPS, 1);
+               free(ust_cmd);
+       }
+
 error_testpoint:
        DBG("Dispatch thread dying");
        if (err) {
@@ -1990,6 +2052,11 @@ static void *thread_registration_apps(void *data)
                        revents = LTTNG_POLL_GETEV(&events, i);
                        pollfd = LTTNG_POLL_GETFD(&events, i);
 
+                       if (!revents) {
+                               /* No activity for this FD (poll implementation). */
+                               continue;
+                       }
+
                        /* Thread quit pipe has been closed. Killing thread. */
                        ret = sessiond_check_thread_quit_pipe(pollfd, revents);
                        if (ret) {
@@ -2030,6 +2097,10 @@ static void *thread_registration_apps(void *data)
                                        ust_cmd = zmalloc(sizeof(struct ust_command));
                                        if (ust_cmd == NULL) {
                                                PERROR("ust command zmalloc");
+                                               ret = close(sock);
+                                               if (ret) {
+                                                       PERROR("close");
+                                               }
                                                goto error;
                                        }
 
@@ -2585,7 +2656,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session)
                 * domain.
                 */
                if (session->kernel_session->consumer) {
-                       consumer_destroy_output(session->kernel_session->consumer);
+                       consumer_output_put(session->kernel_session->consumer);
                }
                session->kernel_session->consumer =
                        consumer_copy_output(session->consumer);
@@ -2598,7 +2669,7 @@ static int copy_session_consumer(int domain, struct ltt_session *session)
        case LTTNG_DOMAIN_UST:
                DBG3("Copying tracing session consumer output in UST session");
                if (session->ust_session->consumer) {
-                       consumer_destroy_output(session->ust_session->consumer);
+                       consumer_output_put(session->ust_session->consumer);
                }
                session->ust_session->consumer =
                        consumer_copy_output(session->consumer);
@@ -2708,7 +2779,7 @@ static int create_kernel_session(struct ltt_session *session)
                                session->kernel_session->consumer->dst.trace_path,
                                S_IRWXU | S_IRWXG, session->uid, session->gid);
                if (ret < 0) {
-                       if (ret != -EEXIST) {
+                       if (errno != EEXIST) {
                                ERR("Trace directory creation error");
                                goto error;
                        }
@@ -2826,6 +2897,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        case LTTNG_LIST_DOMAINS:
        case LTTNG_LIST_CHANNELS:
        case LTTNG_LIST_EVENTS:
+       case LTTNG_LIST_SYSCALLS:
                break;
        default:
                /* Setup lttng message with no payload */
@@ -2844,6 +2916,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        case LTTNG_CALIBRATE:
        case LTTNG_LIST_SESSIONS:
        case LTTNG_LIST_TRACEPOINTS:
+       case LTTNG_LIST_SYSCALLS:
        case LTTNG_LIST_TRACEPOINT_FIELDS:
        case LTTNG_SAVE_SESSION:
                need_tracing_session = 0;
@@ -2876,7 +2949,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock,
        switch (cmd_ctx->lsm->cmd_type) {
        case LTTNG_DISABLE_CHANNEL:
        case LTTNG_DISABLE_EVENT:
-       case LTTNG_DISABLE_ALL_EVENT:
                switch (cmd_ctx->lsm->domain.type) {
                case LTTNG_DOMAIN_KERNEL:
                        if (!cmd_ctx->session->kernel_session) {
@@ -3122,19 +3194,35 @@ skip_domain:
        }
        case LTTNG_DISABLE_EVENT:
        {
-               /* FIXME: passing packed structure to non-packed pointer */
-               /* TODO: handle filter */
-               ret = cmd_disable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type,
-                               cmd_ctx->lsm->u.disable.channel_name,
-                               &cmd_ctx->lsm->u.disable.event);
-               break;
-       }
-       case LTTNG_DISABLE_ALL_EVENT:
-       {
-               DBG("Disabling all events");
 
+               /*
+                * FIXME: handle filter; for now we just receive the filter's
+                * bytecode along with the filter expression which are sent by
+                * liblttng-ctl and discard them.
+                *
+                * This fixes an issue where the client may block while sending
+                * the filter payload and encounter an error because the session
+                * daemon closes the socket without ever handling this data.
+                */
+               size_t count = cmd_ctx->lsm->u.disable.expression_len +
+                       cmd_ctx->lsm->u.disable.bytecode_len;
+
+               if (count) {
+                       char data[LTTNG_FILTER_MAX_LEN];
+
+                       DBG("Discarding disable event command payload of size %zu", count);
+                       while (count) {
+                               ret = lttcomm_recv_unix_sock(sock, data,
+                                       count > sizeof(data) ? sizeof(data) : count);
+                               if (ret < 0) {
+                                       goto error;
+                               }
+
+                               count -= (size_t) ret;
+                       }
+               }
                /* FIXME: passing packed structure to non-packed pointer */
-               ret = cmd_disable_event_all(cmd_ctx->session, cmd_ctx->lsm->domain.type,
+               ret = cmd_disable_event(cmd_ctx->session, cmd_ctx->lsm->domain.type,
                                cmd_ctx->lsm->u.disable.channel_name,
                                &cmd_ctx->lsm->u.disable.event);
                break;
@@ -3213,12 +3301,14 @@ skip_domain:
 
                        if (bytecode_len > LTTNG_FILTER_MAX_LEN) {
                                ret = LTTNG_ERR_FILTER_INVAL;
+                               free(filter_expression);
                                free(exclusion);
                                goto error;
                        }
 
                        bytecode = zmalloc(bytecode_len);
                        if (!bytecode) {
+                               free(filter_expression);
                                free(exclusion);
                                ret = LTTNG_ERR_FILTER_NOMEM;
                                goto error;
@@ -3230,6 +3320,7 @@ skip_domain:
                        if (ret <= 0) {
                                DBG("Nothing recv() from client car len data... continuing");
                                *sock_error = 1;
+                               free(filter_expression);
                                free(bytecode);
                                free(exclusion);
                                ret = LTTNG_ERR_FILTER_INVAL;
@@ -3237,6 +3328,7 @@ skip_domain:
                        }
 
                        if ((bytecode->len + sizeof(*bytecode)) != bytecode_len) {
+                               free(filter_expression);
                                free(bytecode);
                                free(exclusion);
                                ret = LTTNG_ERR_FILTER_INVAL;
@@ -3251,16 +3343,6 @@ skip_domain:
                                kernel_poll_pipe[1]);
                break;
        }
-       case LTTNG_ENABLE_ALL_EVENT:
-       {
-               DBG("Enabling all events");
-
-               ret = cmd_enable_event_all(cmd_ctx->session, &cmd_ctx->lsm->domain,
-                               cmd_ctx->lsm->u.enable.channel_name,
-                               cmd_ctx->lsm->u.enable.event.type, NULL, NULL,
-                               kernel_poll_pipe[1]);
-               break;
-       }
        case LTTNG_LIST_TRACEPOINTS:
        {
                struct lttng_event *events;
@@ -3329,6 +3411,37 @@ skip_domain:
                ret = LTTNG_OK;
                break;
        }
+       case LTTNG_LIST_SYSCALLS:
+       {
+               struct lttng_event *events;
+               ssize_t nb_events;
+
+               nb_events = cmd_list_syscalls(&events);
+               if (nb_events < 0) {
+                       /* Return value is a negative lttng_error_code. */
+                       ret = -nb_events;
+                       goto error;
+               }
+
+               /*
+                * Setup lttng message with payload size set to the event list size in
+                * bytes and then copy list into the llm payload.
+                */
+               ret = setup_lttng_msg(cmd_ctx, sizeof(struct lttng_event) * nb_events);
+               if (ret < 0) {
+                       free(events);
+                       goto setup_error;
+               }
+
+               /* Copy event list into message payload */
+               memcpy(cmd_ctx->llm->payload, events,
+                               sizeof(struct lttng_event) * nb_events);
+
+               free(events);
+
+               ret = LTTNG_OK;
+               break;
+       }
        case LTTNG_SET_CONSUMER_URI:
        {
                size_t nb_uri, len;
@@ -3359,31 +3472,12 @@ skip_domain:
                        goto error;
                }
 
-               ret = cmd_set_consumer_uri(cmd_ctx->lsm->domain.type, cmd_ctx->session,
-                               nb_uri, uris);
+               ret = cmd_set_consumer_uri(cmd_ctx->session, nb_uri, uris);
+               free(uris);
                if (ret != LTTNG_OK) {
-                       free(uris);
                        goto error;
                }
 
-               /*
-                * XXX: 0 means that this URI should be applied on the session. Should
-                * be a DOMAIN enuam.
-                */
-               if (cmd_ctx->lsm->domain.type == 0) {
-                       /* Add the URI for the UST session if a consumer is present. */
-                       if (cmd_ctx->session->ust_session &&
-                                       cmd_ctx->session->ust_session->consumer) {
-                               ret = cmd_set_consumer_uri(LTTNG_DOMAIN_UST, cmd_ctx->session,
-                                               nb_uri, uris);
-                       } else if (cmd_ctx->session->kernel_session &&
-                                       cmd_ctx->session->kernel_session->consumer) {
-                               ret = cmd_set_consumer_uri(LTTNG_DOMAIN_KERNEL,
-                                               cmd_ctx->session, nb_uri, uris);
-                       }
-               }
-
-               free(uris);
 
                break;
        }
@@ -3476,7 +3570,7 @@ skip_domain:
        case LTTNG_LIST_CHANNELS:
        {
                int nb_chan;
-               struct lttng_channel *channels;
+               struct lttng_channel *channels = NULL;
 
                nb_chan = cmd_list_channels(cmd_ctx->lsm->domain.type,
                                cmd_ctx->session, &channels);
@@ -3850,6 +3944,11 @@ restart:
                        revents = LTTNG_POLL_GETEV(&events, i);
                        pollfd = LTTNG_POLL_GETFD(&events, i);
 
+                       if (!revents) {
+                               /* No activity for this FD (poll implementation). */
+                               continue;
+                       }
+
                        /* Thread quit pipe has been closed. Killing thread. */
                        ret = sessiond_check_thread_quit_pipe(pollfd, revents);
                        if (ret) {
@@ -4022,6 +4121,11 @@ static void *thread_manage_clients(void *data)
 
                        health_code_update();
 
+                       if (!revents) {
+                               /* No activity for this FD (poll implementation). */
+                               continue;
+                       }
+
                        /* Thread quit pipe has been closed. Killing thread. */
                        ret = sessiond_check_thread_quit_pipe(pollfd, revents);
                        if (ret) {
@@ -4216,7 +4320,7 @@ static void usage(void)
        fprintf(stderr, "      --verbose-consumer             Verbose mode for consumer. Activate DBG() macro.\n");
        fprintf(stderr, "      --no-kernel                    Disable kernel tracer\n");
        fprintf(stderr, "      --agent-tcp-port               Agent registration TCP port\n");
-       fprintf(stderr, "  -f  --config                       Load daemon configuration file\n");
+       fprintf(stderr, "  -f  --config PATH                  Load daemon configuration file\n");
        fprintf(stderr, "  -l  --load PATH                    Load session configuration\n");
        fprintf(stderr, "      --kmod-probes                  Specify kernel module probes to load\n");
        fprintf(stderr, "      --extra-kmod-probes            Specify extra kernel module probes to load\n");
@@ -4232,6 +4336,17 @@ static int set_option(int opt, const char *arg, const char *optname)
 {
        int ret = 0;
 
+       if (arg && arg[0] == '\0') {
+               /*
+                * This only happens if the value is read from daemon config
+                * file. This means the option requires an argument and the
+                * configuration file contains a line such as:
+                * my_option =
+                */
+               ret = -EINVAL;
+               goto end;
+       }
+
        switch (opt) {
        case 0:
                fprintf(stderr, "option %s", optname);
@@ -4423,6 +4538,23 @@ static int set_option(int opt, const char *arg, const char *optname)
                ret = -1;
        }
 
+end:
+       if (ret == -EINVAL) {
+               const char *opt_name = "unknown";
+               int i;
+
+               for (i = 0; i < sizeof(long_options) / sizeof(struct option);
+                       i++) {
+                       if (opt == long_options[i].val) {
+                               opt_name = long_options[i].name;
+                               break;
+                       }
+               }
+
+               WARN("Invalid argument provided for option \"%s\", using default value.",
+                       opt_name);
+       }
+
        return ret;
 }
 
@@ -5000,6 +5132,9 @@ int main(int argc, char **argv)
        void *status;
        const char *home_path, *env_app_timeout;
 
+       /* Initialize agent apps ht global variable */
+       agent_apps_ht_by_sock = NULL;
+
        init_kernel_workarounds();
 
        rcu_register_thread();
@@ -5053,6 +5188,10 @@ int main(int argc, char **argv)
 
        if (is_root) {
                rundir = strdup(DEFAULT_LTTNG_RUNDIR);
+               if (!rundir) {
+                       ret = -ENOMEM;
+                       goto error;
+               }
 
                /* Create global run dir with root access */
                ret = create_lttng_rundir(rundir);
@@ -5187,20 +5326,24 @@ int main(int argc, char **argv)
                goto error;
        }
 
+       /* After this point, we can safely call cleanup() with "goto exit" */
+
        /*
         * Init UST app hash table. Alloc hash table before this point since
         * cleanup() can get called after that point.
         */
        ust_app_ht_alloc();
 
-       /* Initialize agent domain subsystem. */
-       if ((ret = agent_setup()) < 0) {
-               /* ENOMEM at this point. */
-               goto error;
+       /*
+        * Initialize agent app hash table. We allocate the hash table here
+        * since cleanup() can get called after this point.
+        */
+       if (agent_app_ht_alloc()) {
+               ERR("Failed to allocate Agent app hash table");
+               ret = -1;
+               goto exit;
        }
 
-       /* After this point, we can safely call cleanup() with "goto exit" */
-
        /*
         * These actions must be executed as root. We do that *after* setting up
         * the sockets path because we MUST make the check for another daemon using
@@ -5216,6 +5359,13 @@ int main(int argc, char **argv)
                /* Setup kernel tracer */
                if (!opt_no_kernel) {
                        init_kernel_tracer();
+                       if (kernel_tracer_fd >= 0) {
+                               ret = syscall_init_table();
+                               if (ret < 0) {
+                                       ERR("Unable to populate syscall table. Syscall tracing"
+                                                       " won't work for this session daemon.");
+                               }
+                       }
                }
 
                /* Set ulimit for open files */
@@ -5491,6 +5641,7 @@ exit:
        cleanup();
        rcu_thread_offline();
        rcu_unregister_thread();
+       rcu_barrier();
        if (!ret) {
                exit(EXIT_SUCCESS);
        }
This page took 0.031486 seconds and 4 git commands to generate.