X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-ust-comm.c;h=ead0d7fecbc6d15f03ab120ff9f3524b063bf454;hb=867942fdcdf016a65df7165b4b8135801e2832c2;hp=7cd6a227d66c3bede0f7e244a02038c2c8de668b;hpb=4c62d8d195fb07d3bc64b6a81836d2a5be4abcf3;p=lttng-ust.git diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 7cd6a227..ead0d7fe 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -20,13 +20,15 @@ */ #define _LGPL_SOURCE -#define _GNU_SOURCE +#include +#include #include #include #include #include #include #include +#include #include #include #include @@ -35,10 +37,13 @@ #include #include #include +#include #include -#include +#include "futex.h" #include +#include +#include #include #include #include @@ -52,11 +57,15 @@ #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" +#include "ust-events-internal.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 ? @@ -81,6 +90,8 @@ static int initialized; * * ust_lock nests within the dynamic loader lock (within glibc) because * it is taken within the library constructor. + * + * The ust fd tracker lock nests within the ust_mutex. */ static pthread_mutex_t ust_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -223,7 +234,11 @@ static sem_t constructor_wait; /* * Doing this for both the global and local sessiond. */ -static int sem_count = { 2 }; +enum { + sem_count_initial_value = 4, +}; + +static int sem_count = sem_count_initial_value; /* * Counting nesting within lttng-ust. Used to ensure that calling fork() @@ -238,7 +253,7 @@ struct sock_info { const char *name; pthread_t ust_listener; /* listener thread */ int root_handle; - int constructor_sem_posted; + int registration_done; int allowed; int global; int thread_active; @@ -251,6 +266,9 @@ struct sock_info { char *wait_shm_mmap; /* Keep track of lazy state dump not performed yet. */ int statedump_pending; + int initial_statedump_done; + /* Keep procname for statedump */ + char procname[LTTNG_UST_ABI_PROCNAME_LEN]; }; /* Socket from app (connect) to session daemon (listen) for communication */ @@ -259,7 +277,8 @@ struct sock_info global_apps = { .global = 1, .root_handle = -1, - .allowed = 1, + .registration_done = 0, + .allowed = 0, .thread_active = 0, .sock_path = LTTNG_DEFAULT_RUNDIR "/" LTTNG_UST_SOCK_FILENAME, @@ -269,6 +288,8 @@ struct sock_info global_apps = { .wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME, .statedump_pending = 0, + .initial_statedump_done = 0, + .procname[0] = '\0' }; /* TODO: allow global_apps_sock_path override */ @@ -277,6 +298,7 @@ struct sock_info local_apps = { .name = "local", .global = 0, .root_handle = -1, + .registration_done = 0, .allowed = 0, /* Check setuid bit first */ .thread_active = 0, @@ -284,6 +306,8 @@ struct sock_info local_apps = { .notify_socket = -1, .statedump_pending = 0, + .initial_statedump_done = 0, + .procname[0] = '\0' }; static int wait_poll_fallback; @@ -298,6 +322,8 @@ static const char *cmd_name_mapping[] = { [ LTTNG_UST_REGISTER_DONE ] = "Registration Done", [ LTTNG_UST_TRACEPOINT_FIELD_LIST ] = "Create Tracepoint Field List", + [ LTTNG_UST_EVENT_NOTIFIER_GROUP_CREATE ] = "Create event notifier group", + /* Session FD commands */ [ LTTNG_UST_CHANNEL ] = "Create Channel", [ LTTNG_UST_SESSION_START ] = "Start Session", @@ -322,6 +348,16 @@ static const char *cmd_name_mapping[] = { /* Event FD commands */ [ LTTNG_UST_FILTER ] = "Create Filter", [ LTTNG_UST_EXCLUSION ] = "Add exclusions to event", + + /* Event notifier group commands */ + [ LTTNG_UST_EVENT_NOTIFIER_CREATE ] = "Create event notifier", + + /* Session and event notifier group commands */ + [ LTTNG_UST_COUNTER ] = "Create Counter", + + /* Counter commands */ + [ LTTNG_UST_COUNTER_GLOBAL ] = "Create Counter Global", + [ LTTNG_UST_COUNTER_CPU ] = "Create Counter CPU", }; static const char *str_timeout; @@ -337,6 +373,12 @@ extern void lttng_ring_buffer_client_overwrite_rt_exit(void); 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); +extern void lttng_counter_client_percpu_32_modular_init(void); +extern void lttng_counter_client_percpu_32_modular_exit(void); +extern void lttng_counter_client_percpu_64_modular_init(void); +extern void lttng_counter_client_percpu_64_modular_exit(void); + +static char *get_map_shm(struct sock_info *sock_info); ssize_t lttng_ust_read(int fd, void *buf, size_t len) { @@ -365,11 +407,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"); } /* @@ -393,8 +435,7 @@ void lttng_fixup_ust_mutex_nest_tls(void) static void lttng_fixup_urcu_bp_tls(void) { - rcu_read_lock(); - rcu_read_unlock(); + (void) lttng_ust_urcu_read_ongoing(); } void lttng_ust_fixup_tls(void) @@ -405,7 +446,13 @@ void lttng_ust_fixup_tls(void) lttng_fixup_nest_count_tls(); lttng_fixup_procname_tls(); lttng_fixup_ust_mutex_nest_tls(); + lttng_ust_fixup_perf_counter_tls(); lttng_ust_fixup_fd_tracker_tls(); + lttng_fixup_cgroup_ns_tls(); + lttng_fixup_ipc_ns_tls(); + lttng_fixup_net_ns_tls(); + lttng_fixup_time_ns_tls(); + lttng_fixup_uts_ns_tls(); } int lttng_get_notify_socket(void *owner) @@ -415,6 +462,15 @@ int lttng_get_notify_socket(void *owner) return info->notify_socket; } + +LTTNG_HIDDEN +char* lttng_ust_sockinfo_get_procname(void *owner) +{ + struct sock_info *info = owner; + + return info->procname; +} + static void print_cmd(int cmd, int handle) { @@ -429,25 +485,49 @@ 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; + lttng_pthread_getname_np(global_apps.procname, LTTNG_UST_ABI_PROCNAME_LEN); +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", @@ -457,7 +537,18 @@ 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; + } + + lttng_pthread_getname_np(local_apps.procname, LTTNG_UST_ABI_PROCNAME_LEN); +end: + return ret; } /* @@ -470,7 +561,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) @@ -533,6 +624,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) { @@ -569,48 +673,213 @@ int send_reply(int sock, struct ustcomm_ust_reply *lur) } static -int handle_register_done(struct sock_info *sock_info) +void decrement_sem_count(unsigned int count) { int ret; - if (sock_info->constructor_sem_posted) - return 0; - sock_info->constructor_sem_posted = 1; + assert(uatomic_read(&sem_count) >= count); + if (uatomic_read(&sem_count) <= 0) { - return 0; + return; } - ret = uatomic_add_return(&sem_count, -1); + + ret = uatomic_add_return(&sem_count, -count); if (ret == 0) { ret = sem_post(&constructor_wait); assert(!ret); } +} + +static +int handle_register_done(struct sock_info *sock_info) +{ + if (sock_info->registration_done) + return 0; + sock_info->registration_done = 1; + + decrement_sem_count(1); + if (!sock_info->statedump_pending) { + sock_info->initial_statedump_done = 1; + decrement_sem_count(1); + } + + return 0; +} + +static +int handle_register_failed(struct sock_info *sock_info) +{ + if (sock_info->registration_done) + return 0; + sock_info->registration_done = 1; + sock_info->initial_statedump_done = 1; + + decrement_sem_count(2); + return 0; } /* * Only execute pending statedump after the constructor semaphore has - * been posted by each listener thread. This means statedump will only - * be performed after the "registration done" command is received from - * each session daemon the application is connected to. + * been posted by the current listener thread. This means statedump will + * only be performed after the "registration done" command is received + * from this thread's session daemon. * * This ensures we don't run into deadlock issues with the dynamic * loader mutex, which is held while the constructor is called and * waiting on the constructor semaphore. All operations requiring this * dynamic loader lock need to be postponed using this mechanism. + * + * In a scenario with two session daemons connected to the application, + * it is possible that the first listener thread which receives the + * registration done command issues its statedump while the dynamic + * loader lock is still held by the application constructor waiting on + * the semaphore. It will however be allowed to proceed when the + * second session daemon sends the registration done command to the + * second listener thread. This situation therefore does not produce + * a deadlock. */ static void handle_pending_statedump(struct sock_info *sock_info) { - int ctor_passed = sock_info->constructor_sem_posted; - - if (ctor_passed && sock_info->statedump_pending) { + if (sock_info->registration_done && sock_info->statedump_pending) { sock_info->statedump_pending = 0; pthread_mutex_lock(&ust_fork_mutex); lttng_handle_pending_statedump(sock_info); pthread_mutex_unlock(&ust_fork_mutex); + + if (!sock_info->initial_statedump_done) { + sock_info->initial_statedump_done = 1; + decrement_sem_count(1); + } + } +} + +static inline +const char *bytecode_type_str(uint32_t cmd) +{ + switch (cmd) { + case LTTNG_UST_CAPTURE: + return "capture"; + case LTTNG_UST_FILTER: + return "filter"; + default: + abort(); } } +static +int handle_bytecode_recv(struct sock_info *sock_info, + int sock, struct ustcomm_ust_msg *lum) +{ + struct lttng_ust_bytecode_node *bytecode; + enum lttng_ust_bytecode_node_type type; + const struct lttng_ust_objd_ops *ops; + uint32_t data_size, data_size_max, reloc_offset; + uint64_t seqnum; + ssize_t len; + int ret = 0; + + switch (lum->cmd) { + case LTTNG_UST_FILTER: + type = LTTNG_UST_BYTECODE_NODE_TYPE_FILTER; + data_size = lum->u.filter.data_size; + data_size_max = FILTER_BYTECODE_MAX_LEN; + reloc_offset = lum->u.filter.reloc_offset; + seqnum = lum->u.filter.seqnum; + break; + case LTTNG_UST_CAPTURE: + type = LTTNG_UST_BYTECODE_NODE_TYPE_CAPTURE; + data_size = lum->u.capture.data_size; + data_size_max = CAPTURE_BYTECODE_MAX_LEN; + reloc_offset = lum->u.capture.reloc_offset; + seqnum = lum->u.capture.seqnum; + break; + default: + abort(); + } + + if (data_size > data_size_max) { + ERR("Bytecode %s data size is too large: %u bytes", + bytecode_type_str(lum->cmd), data_size); + ret = -EINVAL; + goto end; + } + + if (reloc_offset > data_size) { + ERR("Bytecode %s reloc offset %u is not within data", + bytecode_type_str(lum->cmd), reloc_offset); + ret = -EINVAL; + goto end; + } + + /* Allocate the structure AND the `data[]` field. */ + bytecode = zmalloc(sizeof(*bytecode) + data_size); + if (!bytecode) { + ret = -ENOMEM; + goto end; + } + + bytecode->bc.len = data_size; + bytecode->bc.reloc_offset = reloc_offset; + bytecode->bc.seqnum = seqnum; + bytecode->type = type; + + len = ustcomm_recv_unix_sock(sock, bytecode->bc.data, bytecode->bc.len); + switch (len) { + case 0: /* orderly shutdown */ + ret = 0; + goto error_free_bytecode; + default: + if (len == bytecode->bc.len) { + DBG("Bytecode %s data received", + bytecode_type_str(lum->cmd)); + break; + } else if (len < 0) { + DBG("Receive failed from lttng-sessiond with errno %d", + (int) -len); + if (len == -ECONNRESET) { + ERR("%s remote end closed connection", + sock_info->name); + ret = len; + goto error_free_bytecode; + } + ret = len; + goto error_free_bytecode; + } else { + DBG("Incorrect %s bytecode data message size: %zd", + bytecode_type_str(lum->cmd), len); + ret = -EINVAL; + goto error_free_bytecode; + } + } + + ops = objd_ops(lum->handle); + if (!ops) { + ret = -ENOENT; + goto error_free_bytecode; + } + + if (ops->cmd) { + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) bytecode, + NULL, sock_info); + if (ret) + goto error_free_bytecode; + /* don't free bytecode if everything went fine. */ + } else { + ret = -ENOSYS; + goto error_free_bytecode; + } + + goto end; + +error_free_bytecode: + free(bytecode); +end: + return ret; +} + static int handle_message(struct sock_info *sock_info, int sock, struct ustcomm_ust_msg *lum) @@ -648,76 +917,12 @@ int handle_message(struct sock_info *sock_info, else ret = lttng_ust_objd_unref(lum->handle, 1); break; + case LTTNG_UST_CAPTURE: case LTTNG_UST_FILTER: - { - /* Receive filter data */ - struct lttng_ust_filter_bytecode_node *bytecode; - - if (lum->u.filter.data_size > FILTER_BYTECODE_MAX_LEN) { - ERR("Filter data size is too large: %u bytes", - lum->u.filter.data_size); - ret = -EINVAL; - goto error; - } - - if (lum->u.filter.reloc_offset > lum->u.filter.data_size) { - ERR("Filter reloc offset %u is not within data", - lum->u.filter.reloc_offset); - ret = -EINVAL; - goto error; - } - - bytecode = zmalloc(sizeof(*bytecode) + lum->u.filter.data_size); - if (!bytecode) { - ret = -ENOMEM; - goto error; - } - len = ustcomm_recv_unix_sock(sock, bytecode->bc.data, - lum->u.filter.data_size); - switch (len) { - case 0: /* orderly shutdown */ - ret = 0; - free(bytecode); + ret = handle_bytecode_recv(sock_info, sock, lum); + if (ret) goto error; - default: - if (len == lum->u.filter.data_size) { - DBG("filter data received"); - break; - } else if (len < 0) { - DBG("Receive failed from lttng-sessiond with errno %d", (int) -len); - if (len == -ECONNRESET) { - ERR("%s remote end closed connection", sock_info->name); - ret = len; - free(bytecode); - goto error; - } - ret = len; - free(bytecode); - goto error; - } else { - DBG("incorrect filter data message size: %zd", len); - ret = -EINVAL; - free(bytecode); - goto error; - } - } - bytecode->bc.len = lum->u.filter.data_size; - bytecode->bc.reloc_offset = lum->u.filter.reloc_offset; - bytecode->bc.seqnum = lum->u.filter.seqnum; - if (ops->cmd) { - ret = ops->cmd(lum->handle, lum->cmd, - (unsigned long) bytecode, - &args, sock_info); - if (ret) { - free(bytecode); - } - /* don't free bytecode if everything went fine. */ - } else { - ret = -ENOSYS; - free(bytecode); - } break; - } case LTTNG_UST_EXCLUSION: { /* Receive exclusion names */ @@ -780,6 +985,47 @@ int handle_message(struct sock_info *sock_info, } break; } + case LTTNG_UST_EVENT_NOTIFIER_GROUP_CREATE: + { + int event_notifier_notif_fd; + + len = ustcomm_recv_event_notifier_notif_fd_from_sessiond(sock, + &event_notifier_notif_fd); + switch (len) { + case 0: /* orderly shutdown */ + ret = 0; + goto error; + case 1: + break; + default: + if (len < 0) { + DBG("Receive failed from lttng-sessiond with errno %d", + (int) -len); + if (len == -ECONNRESET) { + ERR("%s remote end closed connection", + sock_info->name); + ret = len; + goto error; + } + ret = len; + goto error; + } else { + DBG("Incorrect event notifier fd message size: %zd", + len); + ret = -EINVAL; + goto error; + } + } + args.event_notifier_handle.event_notifier_notif_fd = + event_notifier_notif_fd; + if (ops->cmd) + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &lum->u, + &args, sock_info); + else + ret = -ENOSYS; + break; + } case LTTNG_UST_CHANNEL: { void *chan_data; @@ -819,18 +1065,30 @@ int handle_message(struct sock_info *sock_info, &args, sock_info); else ret = -ENOSYS; + if (args.channel.wakeup_fd >= 0) { + int close_ret; + + lttng_ust_lock_fd_tracker(); + close_ret = close(args.channel.wakeup_fd); + lttng_ust_unlock_fd_tracker(); + args.channel.wakeup_fd = -1; + if (close_ret) + PERROR("close"); + } + free(args.channel.chan_data); break; } case LTTNG_UST_STREAM: { /* Receive shm_fd, wakeup_fd */ ret = ustcomm_recv_stream_from_sessiond(sock, - &lum->u.stream.len, + NULL, &args.stream.shm_fd, &args.stream.wakeup_fd); if (ret) { goto error; } + if (ops->cmd) ret = ops->cmd(lum->handle, lum->cmd, (unsigned long) &lum->u, @@ -897,6 +1155,121 @@ int handle_message(struct sock_info *sock_info, ret = -ENOSYS; } break; + case LTTNG_UST_COUNTER: + { + void *counter_data; + + len = ustcomm_recv_counter_from_sessiond(sock, + &counter_data, lum->u.counter.len); + switch (len) { + case 0: /* orderly shutdown */ + ret = 0; + goto error; + default: + if (len == lum->u.counter.len) { + DBG("counter data received"); + break; + } else if (len < 0) { + DBG("Receive failed from lttng-sessiond with errno %d", (int) -len); + if (len == -ECONNRESET) { + ERR("%s remote end closed connection", sock_info->name); + ret = len; + goto error; + } + ret = len; + goto error; + } else { + DBG("incorrect counter data message size: %zd", len); + ret = -EINVAL; + goto error; + } + } + args.counter.counter_data = counter_data; + if (ops->cmd) + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &lum->u, + &args, sock_info); + else + ret = -ENOSYS; + break; + } + case LTTNG_UST_COUNTER_GLOBAL: + { + /* Receive shm_fd */ + ret = ustcomm_recv_counter_shm_from_sessiond(sock, + &args.counter_shm.shm_fd); + if (ret) { + goto error; + } + + if (ops->cmd) + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &lum->u, + &args, sock_info); + else + ret = -ENOSYS; + break; + } + case LTTNG_UST_COUNTER_CPU: + { + /* Receive shm_fd */ + ret = ustcomm_recv_counter_shm_from_sessiond(sock, + &args.counter_shm.shm_fd); + if (ret) { + goto error; + } + + if (ops->cmd) + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &lum->u, + &args, sock_info); + else + ret = -ENOSYS; + break; + } + case LTTNG_UST_EVENT_NOTIFIER_CREATE: + { + /* Receive struct lttng_ust_event_notifier */ + struct lttng_ust_event_notifier event_notifier; + + if (sizeof(event_notifier) != lum->u.event_notifier.len) { + DBG("incorrect event notifier data message size: %u", lum->u.event_notifier.len); + ret = -EINVAL; + goto error; + } + len = ustcomm_recv_unix_sock(sock, &event_notifier, sizeof(event_notifier)); + switch (len) { + case 0: /* orderly shutdown */ + ret = 0; + goto error; + default: + if (len == sizeof(event_notifier)) { + DBG("event notifier data received"); + break; + } else if (len < 0) { + DBG("Receive failed from lttng-sessiond with errno %d", (int) -len); + if (len == -ECONNRESET) { + ERR("%s remote end closed connection", sock_info->name); + ret = len; + goto error; + } + ret = len; + goto error; + } else { + DBG("incorrect event notifier data message size: %zd", len); + ret = -EINVAL; + goto error; + } + } + if (ops->cmd) + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &event_notifier, + &args, sock_info); + else + ret = -ENOSYS; + break; + } + default: if (ops->cmd) ret = ops->cmd(lum->handle, lum->cmd, @@ -1016,7 +1389,8 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting) } sock_info->root_handle = -1; } - sock_info->constructor_sem_posted = 0; + sock_info->registration_done = 0; + sock_info->initial_statedump_done = 0; /* * wait_shm_mmap, socket and notify socket are used by listener @@ -1045,7 +1419,7 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting) if (sock_info->wait_shm_mmap) { long page_size; - page_size = sysconf(_SC_PAGE_SIZE); + page_size = LTTNG_UST_PAGE_SIZE; if (page_size <= 0) { if (!page_size) { errno = EINVAL; @@ -1247,7 +1621,18 @@ char *get_map_shm(struct sock_info *sock_info) lttng_ust_unlock_fd_tracker(); goto error; } - lttng_ust_add_fd_to_tracker(wait_shm_fd); + + 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, @@ -1276,25 +1661,23 @@ 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)) goto end_wait; - while (futex_async((int32_t *) sock_info->wait_shm_mmap, + while (lttng_ust_futex_async((int32_t *) sock_info->wait_shm_mmap, FUTEX_WAIT, 0, NULL, NULL, 0)) { switch (errno) { case EWOULDBLOCK: @@ -1339,7 +1722,7 @@ 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(); @@ -1371,6 +1754,10 @@ 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); @@ -1390,9 +1777,6 @@ restart: sock_info->notify_socket = -1; } - if (ust_lock()) { - goto quit; - } /* * Register. We need to perform both connect and sending @@ -1414,14 +1798,26 @@ restart: * If we cannot find the sessiond daemon, don't delay * constructor execution. */ - ret = handle_register_done(sock_info); + ret = handle_register_failed(sock_info); assert(!ret); ust_unlock(); goto restart; } - lttng_ust_add_fd_to_tracker(ret); - lttng_ust_unlock_fd_tracker(); + 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(); /* @@ -1456,7 +1852,7 @@ restart: * If we cannot register to the sessiond daemon, don't * delay constructor execution. */ - ret = handle_register_done(sock_info); + ret = handle_register_failed(sock_info); assert(!ret); ust_unlock(); goto restart; @@ -1485,14 +1881,27 @@ restart: * If we cannot find the sessiond daemon, don't delay * constructor execution. */ - ret = handle_register_done(sock_info); + ret = handle_register_failed(sock_info); assert(!ret); ust_unlock(); goto restart; } - lttng_ust_add_fd_to_tracker(ret); - lttng_ust_unlock_fd_tracker(); + + 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(); /* @@ -1536,7 +1945,7 @@ restart: * If we cannot register to the sessiond daemon, don't * delay constructor execution. */ - ret = handle_register_done(sock_info); + ret = handle_register_failed(sock_info); assert(!ret); ust_unlock(); goto restart; @@ -1566,7 +1975,7 @@ restart: * If we cannot register to the sessiond daemon, don't * delay constructor execution. */ - ret = handle_register_done(sock_info); + ret = handle_register_failed(sock_info); assert(!ret); ust_unlock(); goto end; @@ -1634,6 +2043,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; @@ -1647,6 +2057,26 @@ void __attribute__((constructor)) lttng_ust_init(void) 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 @@ -1654,6 +2084,7 @@ 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(); @@ -1664,6 +2095,8 @@ void __attribute__((constructor)) lttng_ust_init(void) lttng_ring_buffer_client_overwrite_rt_init(); lttng_ring_buffer_client_discard_init(); lttng_ring_buffer_client_discard_rt_init(); + lttng_counter_client_percpu_32_modular_init(); + lttng_counter_client_percpu_64_modular_init(); lttng_perf_counter_init(); /* * Invoke ust malloc wrapper init before starting other threads. @@ -1672,13 +2105,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); } @@ -1702,14 +2144,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); @@ -1780,6 +2226,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 @@ -1795,11 +2242,13 @@ void lttng_ust_cleanup(int exiting) lttng_ring_buffer_client_overwrite_rt_exit(); lttng_ring_buffer_client_overwrite_exit(); lttng_ring_buffer_metadata_client_exit(); + lttng_counter_client_percpu_32_modular_exit(); + lttng_counter_client_percpu_64_modular_exit(); lttng_ust_statedump_destroy(); exit_tracepoint(); if (!exiting) { /* Reinitialize values for fork */ - sem_count = 2; + sem_count = sem_count_initial_value; lttng_ust_comm_should_quit = 0; initialized = 0; } @@ -1857,6 +2306,35 @@ void __attribute__((destructor)) lttng_ust_exit(void) lttng_ust_cleanup(1); } +static +void ust_context_ns_reset(void) +{ + lttng_context_pid_ns_reset(); + lttng_context_cgroup_ns_reset(); + lttng_context_ipc_ns_reset(); + lttng_context_mnt_ns_reset(); + lttng_context_net_ns_reset(); + lttng_context_user_ns_reset(); + lttng_context_time_ns_reset(); + lttng_context_uts_ns_reset(); +} + +static +void ust_context_vuids_reset(void) +{ + lttng_context_vuid_reset(); + lttng_context_veuid_reset(); + lttng_context_vsuid_reset(); +} + +static +void ust_context_vgids_reset(void) +{ + lttng_context_vgid_reset(); + lttng_context_vegid_reset(); + lttng_context_vsgid_reset(); +} + /* * We exclude the worker threads across fork and clone (except * CLONE_VM), because these system calls only keep the forking thread @@ -1890,7 +2368,11 @@ void ust_before_fork(sigset_t *save_sigset) pthread_mutex_lock(&ust_fork_mutex); ust_lock_nocheck(); - rcu_bp_before_fork(); + lttng_ust_urcu_before_fork(); + if (lttng_ust_liburcu_bp_before_fork) + lttng_ust_liburcu_bp_before_fork(); + lttng_ust_lock_fd_tracker(); + lttng_perf_lock(); } static void ust_after_fork_common(sigset_t *restore_sigset) @@ -1898,6 +2380,8 @@ static void ust_after_fork_common(sigset_t *restore_sigset) int ret; DBG("process %d", getpid()); + lttng_perf_unlock(); + lttng_ust_unlock_fd_tracker(); ust_unlock(); pthread_mutex_unlock(&ust_fork_mutex); @@ -1914,7 +2398,9 @@ 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(); + lttng_ust_urcu_after_fork_parent(); + if (lttng_ust_liburcu_bp_after_fork_parent) + lttng_ust_liburcu_bp_after_fork_parent(); /* Release mutexes and reenable signals */ ust_after_fork_common(restore_sigset); } @@ -1932,16 +2418,77 @@ 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(); + ust_context_ns_reset(); + ust_context_vuids_reset(); + ust_context_vgids_reset(); DBG("process %d", getpid()); /* Release urcu mutexes */ - rcu_bp_after_fork_child(); + lttng_ust_urcu_after_fork_child(); + if (lttng_ust_liburcu_bp_after_fork_child) + lttng_ust_liburcu_bp_after_fork_child(); lttng_ust_cleanup(0); /* Release mutexes and reenable signals */ ust_after_fork_common(restore_sigset); lttng_ust_init(); } +void ust_after_setns(void) +{ + ust_context_ns_reset(); + ust_context_vuids_reset(); + ust_context_vgids_reset(); +} + +void ust_after_unshare(void) +{ + ust_context_ns_reset(); + ust_context_vuids_reset(); + ust_context_vgids_reset(); +} + +void ust_after_setuid(void) +{ + ust_context_vuids_reset(); +} + +void ust_after_seteuid(void) +{ + ust_context_vuids_reset(); +} + +void ust_after_setreuid(void) +{ + ust_context_vuids_reset(); +} + +void ust_after_setresuid(void) +{ + ust_context_vuids_reset(); +} + +void ust_after_setgid(void) +{ + ust_context_vgids_reset(); +} + +void ust_after_setegid(void) +{ + ust_context_vgids_reset(); +} + +void ust_after_setregid(void) +{ + ust_context_vgids_reset(); +} + +void ust_after_setresgid(void) +{ + ust_context_vgids_reset(); +} + void lttng_ust_sockinfo_session_enabled(void *owner) { struct sock_info *sock_info = owner;