X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-comm.c;h=61dbb41b4553c9a9eee21829ba269e4d5c93c1cb;hb=060577e34998f721439135e8fc533a0e52d98ff1;hp=a84316a9358caeda6be0138a439c3828dd979b8e;hpb=8478887d1c753e281a584c0e8a3b63f34359ff76;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index a84316a9..61dbb41b 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -46,17 +48,21 @@ #include #include #include +#include #include #include #include "tracepoint-internal.h" #include "lttng-tracer-core.h" #include "compat.h" -#include "../libringbuffer/tlsfixup.h" +#include "../libringbuffer/rb-init.h" #include "lttng-ust-statedump.h" #include "clock.h" #include "../libringbuffer/getcpu.h" #include "getenv.h" +/* Concatenate lttng ust shared library name with its major version number. */ +#define LTTNG_UST_LIB_SO_NAME "liblttng-ust.so." __ust_stringify(CONFIG_LTTNG_UST_LIBRARY_VERSION_MAJOR) + /* * Has lttng ust comm constructor been called ? */ @@ -258,7 +264,7 @@ struct sock_info global_apps = { .global = 1, .root_handle = -1, - .allowed = 1, + .allowed = 0, .thread_active = 0, .sock_path = LTTNG_DEFAULT_RUNDIR "/" LTTNG_UST_SOCK_FILENAME, @@ -337,6 +343,8 @@ extern void lttng_ring_buffer_client_discard_exit(void); extern void lttng_ring_buffer_client_discard_rt_exit(void); extern void lttng_ring_buffer_metadata_client_exit(void); +static char *get_map_shm(struct sock_info *sock_info); + ssize_t lttng_ust_read(int fd, void *buf, size_t len) { ssize_t ret; @@ -364,11 +372,11 @@ const char *get_lttng_home_dir(void) { const char *val; - val = (const char *) lttng_secure_getenv("LTTNG_HOME"); + val = (const char *) lttng_getenv("LTTNG_HOME"); if (val != NULL) { return val; } - return (const char *) lttng_secure_getenv("HOME"); + return (const char *) lttng_getenv("HOME"); } /* @@ -396,6 +404,17 @@ void lttng_fixup_urcu_bp_tls(void) rcu_read_unlock(); } +void lttng_ust_fixup_tls(void) +{ + lttng_fixup_urcu_bp_tls(); + lttng_fixup_ringbuffer_tls(); + lttng_fixup_vtid_tls(); + lttng_fixup_nest_count_tls(); + lttng_fixup_procname_tls(); + lttng_fixup_ust_mutex_nest_tls(); + lttng_ust_fixup_fd_tracker_tls(); +} + int lttng_get_notify_socket(void *owner) { struct sock_info *info = owner; @@ -417,25 +436,48 @@ void print_cmd(int cmd, int handle) lttng_ust_obj_get_name(handle), handle); } +static +int setup_global_apps(void) +{ + int ret = 0; + assert(!global_apps.wait_shm_mmap); + + global_apps.wait_shm_mmap = get_map_shm(&global_apps); + if (!global_apps.wait_shm_mmap) { + WARN("Unable to get map shm for global apps. Disabling LTTng-UST global tracing."); + global_apps.allowed = 0; + ret = -EIO; + goto error; + } + + global_apps.allowed = 1; +error: + return ret; +} static int setup_local_apps(void) { + int ret = 0; const char *home_dir; uid_t uid; + assert(!local_apps.wait_shm_mmap); + uid = getuid(); /* * Disallow per-user tracing for setuid binaries. */ if (uid != geteuid()) { assert(local_apps.allowed == 0); - return 0; + ret = 0; + goto end; } home_dir = get_lttng_home_dir(); if (!home_dir) { WARN("HOME environment variable not set. Disabling LTTng-UST per-user tracing."); assert(local_apps.allowed == 0); - return -ENOENT; + ret = -ENOENT; + goto end; } local_apps.allowed = 1; snprintf(local_apps.sock_path, PATH_MAX, "%s/%s/%s", @@ -445,11 +487,20 @@ int setup_local_apps(void) snprintf(local_apps.wait_shm_path, PATH_MAX, "/%s-%u", LTTNG_UST_WAIT_FILENAME, uid); - return 0; + + local_apps.wait_shm_mmap = get_map_shm(&local_apps); + if (!local_apps.wait_shm_mmap) { + WARN("Unable to get map shm for local apps. Disabling LTTng-UST per-user tracing."); + local_apps.allowed = 0; + ret = -EIO; + goto end; + } +end: + return ret; } /* - * Get notify_sock timeout, in ms. + * Get socket timeout, in ms. * -1: wait forever. 0: don't wait. >0: timeout, in ms. */ static @@ -458,7 +509,7 @@ long get_timeout(void) long constructor_delay_ms = LTTNG_UST_DEFAULT_CONSTRUCTOR_TIMEOUT_MS; if (!got_timeout_env) { - str_timeout = getenv("LTTNG_UST_REGISTER_TIMEOUT"); + str_timeout = lttng_getenv("LTTNG_UST_REGISTER_TIMEOUT"); got_timeout_env = 1; } if (str_timeout) @@ -469,12 +520,20 @@ long get_timeout(void) return constructor_delay_ms; } +/* Timeout for notify socket send and recv. */ static long get_notify_sock_timeout(void) { return get_timeout(); } +/* Timeout for connecting to cmd and notify sockets. */ +static +long get_connect_sock_timeout(void) +{ + return get_timeout(); +} + /* * Return values: -1: wait forever. 0: don't wait. 1: timeout wait. */ @@ -513,6 +572,19 @@ int get_constructor_timeout(struct timespec *constructor_timeout) return 1; } +static +void get_allow_blocking(void) +{ + const char *str_allow_blocking = + lttng_getenv("LTTNG_UST_ALLOW_BLOCKING"); + + if (str_allow_blocking) { + DBG("%s environment variable is set", + "LTTNG_UST_ALLOW_BLOCKING"); + lttng_ust_ringbuffer_set_allow_blocking(); + } +} + static int register_to_sessiond(int socket, enum ustctl_socket_type type) { @@ -936,6 +1008,21 @@ int handle_message(struct sock_info *sock_info, } } DBG("Return value: %d", lur.ret_val); + + ust_unlock(); + + /* + * Performed delayed statedump operations outside of the UST + * lock. We need to take the dynamic loader lock before we take + * the UST lock internally within handle_pending_statedump(). + */ + handle_pending_statedump(sock_info); + + if (ust_lock()) { + ret = -LTTNG_UST_ERR_EXITING; + goto error; + } + ret = send_reply(sock, &lur); if (ret < 0) { DBG("error sending reply"); @@ -966,13 +1053,6 @@ int handle_message(struct sock_info *sock_info, error: ust_unlock(); - /* - * Performed delayed statedump operations outside of the UST - * lock. We need to take the dynamic loader lock before we take - * the UST lock internally within handle_pending_statedump(). - */ - handle_pending_statedump(sock_info); - return ret; } @@ -1213,17 +1293,39 @@ char *get_map_shm(struct sock_info *sock_info) goto error; } + lttng_ust_lock_fd_tracker(); wait_shm_fd = get_wait_shm(sock_info, page_size); if (wait_shm_fd < 0) { + lttng_ust_unlock_fd_tracker(); goto error; } + + ret = lttng_ust_add_fd_to_tracker(wait_shm_fd); + if (ret < 0) { + ret = close(wait_shm_fd); + if (!ret) { + PERROR("Error closing fd"); + } + lttng_ust_unlock_fd_tracker(); + goto error; + } + + wait_shm_fd = ret; + lttng_ust_unlock_fd_tracker(); + wait_shm_mmap = mmap(NULL, page_size, PROT_READ, MAP_SHARED, wait_shm_fd, 0); + /* close shm fd immediately after taking the mmap reference */ + lttng_ust_lock_fd_tracker(); ret = close(wait_shm_fd); - if (ret) { + if (!ret) { + lttng_ust_delete_fd_from_tracker(wait_shm_fd); + } else { PERROR("Error closing fd"); } + lttng_ust_unlock_fd_tracker(); + if (wait_shm_mmap == MAP_FAILED) { DBG("mmap error (can be caused by race with sessiond). Fallback to poll mode."); goto error; @@ -1237,19 +1339,17 @@ error: static void wait_for_sessiond(struct sock_info *sock_info) { + /* Use ust_lock to check if we should quit. */ if (ust_lock()) { goto quit; } if (wait_poll_fallback) { goto error; } - if (!sock_info->wait_shm_mmap) { - sock_info->wait_shm_mmap = get_map_shm(sock_info); - if (!sock_info->wait_shm_mmap) - goto error; - } ust_unlock(); + assert(sock_info->wait_shm_mmap); + DBG("Waiting for %s apps sessiond", sock_info->name); /* Wait for futex wakeup */ if (uatomic_read((int32_t *) sock_info->wait_shm_mmap)) @@ -1300,9 +1400,10 @@ static void *ust_listener_thread(void *arg) { struct sock_info *sock_info = arg; - int sock, ret, prev_connect_failed = 0, has_waited = 0; + int sock, ret, prev_connect_failed = 0, has_waited = 0, fd; long timeout; + lttng_ust_fixup_tls(); /* * If available, add '-ust' to the end of this thread's * process name @@ -1331,7 +1432,12 @@ restart: prev_connect_failed = 0; } + if (ust_lock()) { + goto quit; + } + if (sock_info->socket != -1) { + /* FD tracker is updated by ustcomm_close_unix_sock() */ ret = ustcomm_close_unix_sock(sock_info->socket); if (ret) { ERR("Error closing %s ust cmd socket", @@ -1340,6 +1446,7 @@ restart: sock_info->socket = -1; } if (sock_info->notify_socket != -1) { + /* FD tracker is updated by ustcomm_close_unix_sock() */ ret = ustcomm_close_unix_sock(sock_info->notify_socket); if (ret) { ERR("Error closing %s ust notify socket", @@ -1348,6 +1455,7 @@ restart: sock_info->notify_socket = -1; } + /* * Register. We need to perform both connect and sending * registration message before doing the next connect otherwise @@ -1356,15 +1464,14 @@ restart: * first connect registration message. */ /* Connect cmd socket */ - ret = ustcomm_connect_unix_sock(sock_info->sock_path); + lttng_ust_lock_fd_tracker(); + ret = ustcomm_connect_unix_sock(sock_info->sock_path, + get_connect_sock_timeout()); if (ret < 0) { + lttng_ust_unlock_fd_tracker(); DBG("Info: sessiond not accepting connections to %s apps socket", sock_info->name); prev_connect_failed = 1; - if (ust_lock()) { - goto quit; - } - /* * If we cannot find the sessiond daemon, don't delay * constructor execution. @@ -1374,8 +1481,28 @@ restart: ust_unlock(); goto restart; } + fd = ret; + ret = lttng_ust_add_fd_to_tracker(fd); + if (ret < 0) { + ret = close(fd); + if (ret) { + PERROR("close on sock_info->socket"); + } + ret = -1; + lttng_ust_unlock_fd_tracker(); + ust_unlock(); + goto quit; + } + sock_info->socket = ret; + lttng_ust_unlock_fd_tracker(); + ust_unlock(); + /* + * Unlock/relock ust lock because connect is blocking (with + * timeout). Don't delay constructors on the ust lock for too + * long. + */ if (ust_lock()) { goto quit; } @@ -1410,17 +1537,24 @@ restart: } ust_unlock(); + /* + * Unlock/relock ust lock because connect is blocking (with + * timeout). Don't delay constructors on the ust lock for too + * long. + */ + if (ust_lock()) { + goto quit; + } /* Connect notify socket */ - ret = ustcomm_connect_unix_sock(sock_info->sock_path); + lttng_ust_lock_fd_tracker(); + ret = ustcomm_connect_unix_sock(sock_info->sock_path, + get_connect_sock_timeout()); if (ret < 0) { + lttng_ust_unlock_fd_tracker(); DBG("Info: sessiond not accepting connections to %s apps socket", sock_info->name); prev_connect_failed = 1; - if (ust_lock()) { - goto quit; - } - /* * If we cannot find the sessiond daemon, don't delay * constructor execution. @@ -1430,7 +1564,32 @@ restart: ust_unlock(); goto restart; } + + fd = ret; + ret = lttng_ust_add_fd_to_tracker(fd); + if (ret < 0) { + ret = close(fd); + if (ret) { + PERROR("close on sock_info->notify_socket"); + } + ret = -1; + lttng_ust_unlock_fd_tracker(); + ust_unlock(); + goto quit; + } + sock_info->notify_socket = ret; + lttng_ust_unlock_fd_tracker(); + + ust_unlock(); + /* + * Unlock/relock ust lock because connect is blocking (with + * timeout). Don't delay constructors on the ust lock for too + * long. + */ + if (ust_lock()) { + goto quit; + } timeout = get_notify_sock_timeout(); if (timeout >= 0) { @@ -1454,10 +1613,6 @@ restart: WARN("Unsupported timeout value %ld", timeout); } - if (ust_lock()) { - goto quit; - } - ret = register_to_sessiond(sock_info->notify_socket, USTCTL_SOCKET_NOTIFY); if (ret < 0) { @@ -1566,6 +1721,7 @@ void __attribute__((constructor)) lttng_ust_init(void) pthread_attr_t thread_attr; int timeout_mode; int ret; + void *handle; if (uatomic_xchg(&initialized, 1) == 1) return; @@ -1575,15 +1731,30 @@ void __attribute__((constructor)) lttng_ust_init(void) * to be the dynamic linker mutex) and ust_lock, taken within * the ust lock. */ - lttng_fixup_urcu_bp_tls(); - lttng_fixup_ringbuffer_tls(); - lttng_fixup_vtid_tls(); - lttng_fixup_nest_count_tls(); - lttng_fixup_procname_tls(); - lttng_fixup_ust_mutex_nest_tls(); + lttng_ust_fixup_tls(); lttng_ust_loaded = 1; + /* + * We need to ensure that the liblttng-ust library is not unloaded to avoid + * the unloading of code used by the ust_listener_threads as we can not + * reliably know when they exited. To do that, manually load + * liblttng-ust.so to increment the dynamic loader's internal refcount for + * this library so it never becomes zero, thus never gets unloaded from the + * address space of the process. Since we are already running in the + * constructor of the LTTNG_UST_LIB_SO_NAME library, calling dlopen will + * simply increment the refcount and no additionnal work is needed by the + * dynamic loader as the shared library is already loaded in the address + * space. As a safe guard, we use the RTLD_NODELETE flag to prevent + * unloading of the UST library if its refcount becomes zero (which should + * never happen). Do the return value check but discard the handle at the + * end of the function as it's not needed. + */ + handle = dlopen(LTTNG_UST_LIB_SO_NAME, RTLD_LAZY | RTLD_NODELETE); + if (!handle) { + ERR("dlopen of liblttng-ust shared library (%s).", LTTNG_UST_LIB_SO_NAME); + } + /* * We want precise control over the order in which we construct * our sub-libraries vs starting to receive commands from @@ -1591,7 +1762,9 @@ void __attribute__((constructor)) lttng_ust_init(void) * sessiond before the init functions are completed). */ init_usterr(); + lttng_ust_getenv_init(); /* Needs init_usterr() to be completed. */ init_tracepoint(); + lttng_ust_init_fd_tracker(); lttng_ust_clock_init(); lttng_ust_getcpu_init(); lttng_ust_statedump_init(); @@ -1608,13 +1781,22 @@ void __attribute__((constructor)) lttng_ust_init(void) timeout_mode = get_constructor_timeout(&constructor_timeout); + get_allow_blocking(); + ret = sem_init(&constructor_wait, 0, 0); if (ret) { PERROR("sem_init"); } + ret = setup_global_apps(); + if (ret) { + assert(global_apps.allowed == 0); + DBG("global apps setup returned %d", ret); + } + ret = setup_local_apps(); if (ret) { + assert(local_apps.allowed == 0); DBG("local apps setup returned %d", ret); } @@ -1638,14 +1820,18 @@ void __attribute__((constructor)) lttng_ust_init(void) ERR("pthread_attr_setdetachstate: %s", strerror(ret)); } - pthread_mutex_lock(&ust_exit_mutex); - ret = pthread_create(&global_apps.ust_listener, &thread_attr, - ust_listener_thread, &global_apps); - if (ret) { - ERR("pthread_create global: %s", strerror(ret)); + if (global_apps.allowed) { + pthread_mutex_lock(&ust_exit_mutex); + ret = pthread_create(&global_apps.ust_listener, &thread_attr, + ust_listener_thread, &global_apps); + if (ret) { + ERR("pthread_create global: %s", strerror(ret)); + } + global_apps.thread_active = 1; + pthread_mutex_unlock(&ust_exit_mutex); + } else { + handle_register_done(&global_apps); } - global_apps.thread_active = 1; - pthread_mutex_unlock(&ust_exit_mutex); if (local_apps.allowed) { pthread_mutex_lock(&ust_exit_mutex); @@ -1716,6 +1902,7 @@ void lttng_ust_cleanup(int exiting) cleanup_sock_info(&global_apps, exiting); cleanup_sock_info(&local_apps, exiting); local_apps.allowed = 0; + global_apps.allowed = 0; /* * The teardown in this function all affect data structures * accessed under the UST lock by the listener thread. This @@ -1811,6 +1998,9 @@ void ust_before_fork(sigset_t *save_sigset) sigset_t all_sigs; int ret; + /* Fixup lttng-ust TLS. */ + lttng_ust_fixup_tls(); + if (URCU_TLS(lttng_ust_nest_count)) return; /* Disable signals */ @@ -1823,7 +2013,7 @@ void ust_before_fork(sigset_t *save_sigset) pthread_mutex_lock(&ust_fork_mutex); ust_lock_nocheck(); - rcu_bp_before_fork(); + urcu_bp_before_fork(); } static void ust_after_fork_common(sigset_t *restore_sigset) @@ -1847,7 +2037,7 @@ void ust_after_fork_parent(sigset_t *restore_sigset) if (URCU_TLS(lttng_ust_nest_count)) return; DBG("process %d", getpid()); - rcu_bp_after_fork_parent(); + urcu_bp_after_fork_parent(); /* Release mutexes and reenable signals */ ust_after_fork_common(restore_sigset); } @@ -1865,10 +2055,12 @@ void ust_after_fork_child(sigset_t *restore_sigset) { if (URCU_TLS(lttng_ust_nest_count)) return; + lttng_context_vpid_reset(); lttng_context_vtid_reset(); + lttng_context_procname_reset(); DBG("process %d", getpid()); /* Release urcu mutexes */ - rcu_bp_after_fork_child(); + urcu_bp_after_fork_child(); lttng_ust_cleanup(0); /* Release mutexes and reenable signals */ ust_after_fork_common(restore_sigset);