X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-relayd%2Fmain.c;h=25a32a70b7b8488435474461e7a92ea9b161bf73;hp=4e30ac49882e5c392097b51dfedf95b0d7207686;hb=7ceefac4c8474606312e25ab822e510c41a3d644;hpb=f77a6ec2ae90f5d58e9389e47228c18b081cf97a diff --git a/src/bin/lttng-relayd/main.c b/src/bin/lttng-relayd/main.c index 4e30ac498..25a32a70b 100644 --- a/src/bin/lttng-relayd/main.c +++ b/src/bin/lttng-relayd/main.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ #include #include #include +#include #include #include @@ -61,6 +63,8 @@ #include #include #include +#include +#include #include "backward-compatibility-group-by.h" #include "cmd.h" @@ -160,6 +164,9 @@ static uint64_t last_relay_stream_id; */ static struct relay_conn_queue relay_conn_queue; +/* Cap of file desriptors to be in simultaneous use by the relay daemon. */ +static unsigned int lttng_opt_fd_pool_size = -1; + /* Global relay stream hash table. */ struct lttng_ht *relay_streams_ht; @@ -174,6 +181,9 @@ struct health_app *health_relayd; struct sessiond_trace_chunk_registry *sessiond_trace_chunk_registry; +/* Global fd tracker. */ +struct fd_tracker *the_fd_tracker; + static struct option long_options[] = { { "control-port", 1, 0, 'C', }, { "data-port", 1, 0, 'D', }, @@ -181,6 +191,7 @@ static struct option long_options[] = { { "daemonize", 0, 0, 'd', }, { "background", 0, 0, 'b', }, { "group", 1, 0, 'g', }, + { "fd-pool-size", 1, 0, '\0', }, { "help", 0, 0, 'h', }, { "output", 1, 0, 'o', }, { "verbose", 0, 0, 'v', }, @@ -224,9 +235,27 @@ static int set_option(int opt, const char *arg, const char *optname) switch (opt) { case 0: - fprintf(stderr, "option %s", optname); - if (arg) { - fprintf(stderr, " with arg %s\n", arg); + if (!strcmp(optname, "fd-pool-size")) { + unsigned long v; + + errno = 0; + v = strtoul(arg, NULL, 0); + if (errno != 0 || !isdigit(arg[0])) { + ERR("Wrong value in --fd-pool-size parameter: %s", arg); + ret = -1; + goto end; + } + if (v >= UINT_MAX) { + ERR("File descriptor cap overflow in --fd-pool-size parameter: %s", arg); + ret = -1; + goto end; + } + lttng_opt_fd_pool_size = (unsigned int) v; + } else { + fprintf(stderr, "unknown option %s", optname); + if (arg) { + fprintf(stderr, " with arg %s\n", arg); + } } break; case 'C': @@ -446,6 +475,56 @@ static int parse_env_options(void) return ret; } +static int set_fd_pool_size(void) +{ + int ret = 0; + struct rlimit rlimit; + + ret = getrlimit(RLIMIT_NOFILE, &rlimit); + if (ret) { + PERROR("Failed to get file descriptor limit"); + ret = -1; + goto end; + } + + DBG("File descriptor count limits are %" PRIu64 " (soft) and %" PRIu64 " (hard)", + (uint64_t) rlimit.rlim_cur, + (uint64_t) rlimit.rlim_max); + if (lttng_opt_fd_pool_size == -1) { + /* Use default value (soft limit - reserve). */ + if (rlimit.rlim_cur < DEFAULT_RELAYD_MIN_FD_POOL_SIZE) { + ERR("The process' file number limit is too low (%" PRIu64 "). The process' file number limit must be set to at least %i.", + (uint64_t) rlimit.rlim_cur, DEFAULT_RELAYD_MIN_FD_POOL_SIZE); + ret = -1; + goto end; + } + lttng_opt_fd_pool_size = rlimit.rlim_cur - + DEFAULT_RELAYD_FD_POOL_SIZE_RESERVE; + goto end; + } + + if (lttng_opt_fd_pool_size < DEFAULT_RELAYD_MIN_FD_POOL_SIZE) { + ERR("File descriptor pool size must be set to at least %d", + DEFAULT_RELAYD_MIN_FD_POOL_SIZE); + ret = -1; + goto end; + } + + if (lttng_opt_fd_pool_size > rlimit.rlim_cur) { + ERR("File descriptor pool size argument (%u) exceeds the process' soft limit (%" PRIu64 ").", + lttng_opt_fd_pool_size, (uint64_t) rlimit.rlim_cur); + ret = -1; + goto end; + } + + DBG("File descriptor pool size argument (%u) adjusted to %u to accomodate transient fd uses", + lttng_opt_fd_pool_size, + lttng_opt_fd_pool_size - DEFAULT_RELAYD_FD_POOL_SIZE_RESERVE); + lttng_opt_fd_pool_size -= DEFAULT_RELAYD_FD_POOL_SIZE_RESERVE; +end: + return ret; +} + static int set_options(int argc, char **argv) { int c, ret = 0, option_index = 0, retval = 0; @@ -563,6 +642,11 @@ static int set_options(int argc, char **argv) goto exit; } } + ret = set_fd_pool_size(); + if (ret) { + retval = -1; + goto exit; + } if (opt_group_output_by == RELAYD_GROUP_OUTPUT_BY_UNKNOWN) { opt_group_output_by = RELAYD_GROUP_OUTPUT_BY_HOST; @@ -588,13 +672,26 @@ exit: static void print_global_objects(void) { - rcu_register_thread(); - print_viewer_streams(); print_relay_streams(); print_sessions(); +} - rcu_unregister_thread(); +static int noop_close(void *data, int *fds) +{ + return 0; +} + +static void untrack_stdio(void) +{ + int fds[] = { fileno(stdout), fileno(stderr) }; + + /* + * noop_close is used since we don't really want to close + * the stdio output fds; we merely want to stop tracking them. + */ + (void) fd_tracker_close_unsuspendable_fd(the_fd_tracker, + fds, 2, noop_close, NULL); } /* @@ -616,8 +713,30 @@ static void relayd_cleanup(void) free(opt_output_path); free(opt_working_directory); + if (health_relayd) { + health_app_destroy(health_relayd); + } /* Close thread quit pipes */ - utils_close_pipe(thread_quit_pipe); + if (health_quit_pipe[0] != -1) { + (void) fd_tracker_util_pipe_close( + the_fd_tracker, health_quit_pipe); + } + if (thread_quit_pipe[0] != -1) { + (void) fd_tracker_util_pipe_close( + the_fd_tracker, thread_quit_pipe); + } + if (sessiond_trace_chunk_registry) { + sessiond_trace_chunk_registry_destroy( + sessiond_trace_chunk_registry); + } + if (the_fd_tracker) { + untrack_stdio(); + /* + * fd_tracker_destroy() will log the contents of the fd-tracker + * if a leak is detected. + */ + fd_tracker_destroy(the_fd_tracker); + } uri_free(control_uri); uri_free(data_uri); @@ -779,17 +898,26 @@ void lttng_relay_notify_ready(void) */ static int init_thread_quit_pipe(void) { - int ret; - - ret = utils_create_pipe_cloexec(thread_quit_pipe); + return fd_tracker_util_pipe_open_cloexec( + the_fd_tracker, "Quit pipe", thread_quit_pipe); +} - return ret; +/* + * Init health quit pipe. + * + * Return -1 on error or 0 if all pipes are created. + */ +static int init_health_quit_pipe(void) +{ + return fd_tracker_util_pipe_open_cloexec(the_fd_tracker, + "Health quit pipe", health_quit_pipe); } /* * Create a poll set with O_CLOEXEC and add the thread quit pipe to the set. */ -static int create_thread_poll_set(struct lttng_poll_event *events, int size) +static int create_named_thread_poll_set(struct lttng_poll_event *events, + int size, const char *name) { int ret; @@ -798,10 +926,8 @@ static int create_thread_poll_set(struct lttng_poll_event *events, int size) goto error; } - ret = lttng_poll_create(events, size, LTTNG_CLOEXEC); - if (ret < 0) { - goto error; - } + ret = fd_tracker_util_poll_create(the_fd_tracker, + name, events, 1, LTTNG_CLOEXEC); /* Add quit pipe */ ret = lttng_poll_add(events, thread_quit_pipe[0], LPOLLIN | LPOLLERR); @@ -829,13 +955,38 @@ static int check_thread_quit_pipe(int fd, uint32_t events) return 0; } +static int create_sock(void *data, int *out_fd) +{ + int ret; + struct lttcomm_sock *sock = data; + + ret = lttcomm_create_sock(sock); + if (ret < 0) { + goto end; + } + + *out_fd = sock->fd; +end: + return ret; +} + +static int close_sock(void *data, int *in_fd) +{ + struct lttcomm_sock *sock = data; + + return sock->ops->close(sock); +} + /* * Create and init socket from uri. */ -static struct lttcomm_sock *relay_socket_create(struct lttng_uri *uri) +static struct lttcomm_sock *relay_socket_create(struct lttng_uri *uri, + const char *name) { - int ret; + int ret, sock_fd; struct lttcomm_sock *sock = NULL; + char uri_str[PATH_MAX]; + char *formated_name = NULL; sock = lttcomm_alloc_sock_from_uri(uri); if (sock == NULL) { @@ -843,11 +994,25 @@ static struct lttcomm_sock *relay_socket_create(struct lttng_uri *uri) goto error; } - ret = lttcomm_create_sock(sock); - if (ret < 0) { - goto error; + /* + * Don't fail to create the socket if the name can't be built as it is + * only used for debugging purposes. + */ + ret = uri_to_str_url(uri, uri_str, sizeof(uri_str)); + uri_str[sizeof(uri_str) - 1] = '\0'; + if (ret >= 0) { + ret = asprintf(&formated_name, "%s socket @ %s", name, + uri_str); + if (ret < 0) { + formated_name = NULL; + } } - DBG("Listening on sock %d", sock->fd); + + ret = fd_tracker_open_unsuspendable_fd(the_fd_tracker, &sock_fd, + (const char **) (formated_name ? &formated_name : NULL), + 1, create_sock, sock); + free(formated_name); + DBG("Listening on %s socket %d", name, sock->fd); ret = sock->ops->bind(sock); if (ret < 0) { @@ -886,12 +1051,12 @@ static void *relay_thread_listener(void *data) health_code_update(); - control_sock = relay_socket_create(control_uri); + control_sock = relay_socket_create(control_uri, "Control listener"); if (!control_sock) { goto error_sock_control; } - data_sock = relay_socket_create(data_uri); + data_sock = relay_socket_create(data_uri, "Data listener"); if (!data_sock) { goto error_sock_relay; } @@ -900,7 +1065,7 @@ static void *relay_thread_listener(void *data) * Pass 3 as size here for the thread quit pipe, control and * data socket. */ - ret = create_thread_poll_set(&events, 3); + ret = create_named_thread_poll_set(&events, 3, "Listener thread epoll"); if (ret < 0) { goto error_create_poll; } @@ -1034,21 +1199,31 @@ exit: error: error_poll_add: error_testpoint: - lttng_poll_clean(&events); + (void) fd_tracker_util_poll_clean(the_fd_tracker, &events); error_create_poll: if (data_sock->fd >= 0) { - ret = data_sock->ops->close(data_sock); + int data_sock_fd = data_sock->fd; + + ret = fd_tracker_close_unsuspendable_fd(the_fd_tracker, + &data_sock_fd, 1, close_sock, + data_sock); if (ret) { - PERROR("close"); + PERROR("Failed to close the data listener socket file descriptor"); } + data_sock->fd = -1; } lttcomm_destroy_sock(data_sock); error_sock_relay: if (control_sock->fd >= 0) { - ret = control_sock->ops->close(control_sock); + int control_sock_fd = control_sock->fd; + + ret = fd_tracker_close_unsuspendable_fd(the_fd_tracker, + &control_sock_fd, 1, close_sock, + control_sock); if (ret) { - PERROR("close"); + PERROR("Failed to close the control listener socket file descriptor"); } + control_sock->fd = -1; } lttcomm_destroy_sock(control_sock); error_sock_control: @@ -2457,7 +2632,6 @@ static int relay_create_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr, struct lttng_trace_chunk *chunk = NULL, *published_chunk = NULL; enum lttng_error_code reply_code = LTTNG_OK; enum lttng_trace_chunk_status chunk_status; - struct lttng_directory_handle *session_output = NULL; const char *new_path; if (!session || !conn->version_check_done) { @@ -2554,15 +2728,9 @@ static int relay_create_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr, goto end; } - session_output = session_create_output_directory_handle( - conn->session); - if (!session_output) { - reply_code = LTTNG_ERR_CREATE_DIR_FAIL; - goto end; - } - chunk_status = lttng_trace_chunk_set_as_owner(chunk, session_output); - lttng_directory_handle_put(session_output); - session_output = NULL; + assert(conn->session->output_directory); + chunk_status = lttng_trace_chunk_set_as_owner(chunk, + conn->session->output_directory); if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) { reply_code = LTTNG_ERR_UNK; ret = -1; @@ -2621,7 +2789,6 @@ end: end_no_reply: lttng_trace_chunk_put(chunk); lttng_trace_chunk_put(published_chunk); - lttng_directory_handle_put(session_output); return ret; } @@ -3617,7 +3784,7 @@ static void *relay_thread_worker(void *data) goto relay_connections_ht_error; } - ret = create_thread_poll_set(&events, 2); + ret = create_named_thread_poll_set(&events, 2, "Worker thread epoll"); if (ret < 0) { goto error_poll_create; } @@ -3886,12 +4053,13 @@ error: } rcu_read_unlock(); - lttng_poll_clean(&events); + (void) fd_tracker_util_poll_clean(the_fd_tracker, &events); error_poll_create: lttng_ht_destroy(relay_connections_ht); relay_connections_ht_error: /* Close relay conn pipes */ - utils_close_pipe(relay_conn_pipe); + (void) fd_tracker_util_pipe_close(the_fd_tracker, + relay_conn_pipe); if (err) { DBG("Thread exited with error"); } @@ -3913,11 +4081,24 @@ error_testpoint: */ static int create_relay_conn_pipe(void) { - int ret; + return fd_tracker_util_pipe_open_cloexec(the_fd_tracker, + "Relayd connection pipe", relay_conn_pipe); +} - ret = utils_create_pipe_cloexec(relay_conn_pipe); +static int stdio_open(void *data, int *fds) +{ + fds[0] = fileno(stdout); + fds[1] = fileno(stderr); + return 0; +} - return ret; +static int track_stdio(void) +{ + int fds[2]; + const char *names[] = { "stdout", "stderr" }; + + return fd_tracker_open_unsuspendable_fd(the_fd_tracker, fds, + names, 2, stdio_open, NULL); } /* @@ -3925,6 +4106,7 @@ static int create_relay_conn_pipe(void) */ int main(int argc, char **argv) { + bool thread_is_rcu_registered = false; int ret = 0, retval = 0; void *status; @@ -3985,23 +4167,12 @@ int main(int argc, char **argv) /* Daemonize */ if (opt_daemon || opt_background) { - int i; - ret = lttng_daemonize(&child_ppid, &recv_child_signal, !opt_background); if (ret < 0) { retval = -1; goto exit_options; } - - /* - * We are in the child. Make sure all other file - * descriptors are closed, in case we are called with - * more opened file descriptors than the standard ones. - */ - for (i = 3; i < sysconf(_SC_OPEN_MAX); i++) { - (void) close(i); - } } if (opt_working_directory) { @@ -4016,7 +4187,28 @@ int main(int argc, char **argv) if (!sessiond_trace_chunk_registry) { ERR("Failed to initialize session daemon trace chunk registry"); retval = -1; - goto exit_sessiond_trace_chunk_registry; + goto exit_options; + } + + /* + * The RCU thread registration (and use, through the fd-tracker's + * creation) is done after the daemonization to allow us to not + * deal with liburcu's fork() management as the call RCU needs to + * be restored. + */ + rcu_register_thread(); + thread_is_rcu_registered = true; + + the_fd_tracker = fd_tracker_create(lttng_opt_fd_pool_size); + if (!the_fd_tracker) { + retval = -1; + goto exit_options; + } + + ret = track_stdio(); + if (ret) { + retval = -1; + goto exit_options; } /* Initialize thread health monitoring */ @@ -4024,19 +4216,19 @@ int main(int argc, char **argv) if (!health_relayd) { PERROR("health_app_create error"); retval = -1; - goto exit_health_app_create; + goto exit_options; } /* Create thread quit pipe */ if (init_thread_quit_pipe()) { retval = -1; - goto exit_init_data; + goto exit_options; } /* Setup the thread apps communication pipe. */ if (create_relay_conn_pipe()) { retval = -1; - goto exit_init_data; + goto exit_options; } /* Init relay command queue. */ @@ -4050,27 +4242,27 @@ int main(int argc, char **argv) sessions_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64); if (!sessions_ht) { retval = -1; - goto exit_init_data; + goto exit_options; } /* tables of streams indexed by stream ID */ relay_streams_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64); if (!relay_streams_ht) { retval = -1; - goto exit_init_data; + goto exit_options; } /* tables of streams indexed by stream ID */ viewer_streams_ht = lttng_ht_new(0, LTTNG_HT_TYPE_U64); if (!viewer_streams_ht) { retval = -1; - goto exit_init_data; + goto exit_options; } - ret = utils_create_pipe(health_quit_pipe); + ret = init_health_quit_pipe(); if (ret) { retval = -1; - goto exit_health_quit_pipe; + goto exit_options; } /* Create thread to manage the client socket */ @@ -4080,7 +4272,7 @@ int main(int argc, char **argv) errno = ret; PERROR("pthread_create health"); retval = -1; - goto exit_health_thread; + goto exit_options; } /* Setup the dispatcher thread */ @@ -4161,16 +4353,6 @@ exit_dispatcher_thread: PERROR("pthread_join health_thread"); retval = -1; } -exit_health_thread: - - utils_close_pipe(health_quit_pipe); -exit_health_quit_pipe: - -exit_init_data: - health_app_destroy(health_relayd); - sessiond_trace_chunk_registry_destroy(sessiond_trace_chunk_registry); -exit_health_app_create: -exit_sessiond_trace_chunk_registry: exit_options: /* * Wait for all pending call_rcu work to complete before tearing @@ -4183,6 +4365,10 @@ exit_options: /* Ensure all prior call_rcu are done. */ rcu_barrier(); + if (thread_is_rcu_registered) { + rcu_unregister_thread(); + } + if (!retval) { exit(EXIT_SUCCESS); } else {