* lock. This means that there CAN NOT be stream(s) being sent to a
* consumer since this action also requires the session lock at any time.
*
- * At this point, we are sure that not streams data will be lost after this
- * command is issued.
+ * At this point, we are sure that no data will be lost after this command
+ * is issued.
*/
if (usess->consumer && usess->consumer->type == CONSUMER_DST_NET) {
cds_lfht_for_each_entry(usess->consumer->socks->ht, &iter.iter, socket,
void *status;
int ret;
- if (consumer_data->pid != 0) {
+ /* Consumer pid must be a real one. */
+ if (consumer_data->pid > 0) {
ret = kill(consumer_data->pid, SIGTERM);
if (ret) {
ERR("Error killing consumer daemon");
DBG3("Creating relayd stream socket from URI");
/* Check relayd version */
- ret = relayd_version_check(sock, LTTNG_UST_COMM_MAJOR, 0);
+ ret = relayd_version_check(sock, RELAYD_VERSION_COMM_MAJOR,
+ RELAYD_VERSION_COMM_MINOR);
if (ret < 0) {
ret = LTTCOMM_RELAYD_VERSION_FAIL;
goto close_sock;
{
int ret;
+ assert(session);
+ assert(consumer);
+
+ /* Don't resend the sockets to the consumer. */
+ if (consumer->dst.net.relayd_socks_sent) {
+ ret = LTTCOMM_OK;
+ goto error;
+ }
+
/* Sending control relayd socket. */
ret = send_socket_relayd_consumer(domain, session,
&consumer->dst.net.control, consumer, fd);
goto error;
}
+ /* Flag that all relayd sockets were sent to the consumer. */
+ consumer->dst.net.relayd_socks_sent = 1;
+
error:
return ret;
}
DBG2("Setting relayd for session %s", session->name);
- if (usess && usess->consumer->type == CONSUMER_DST_NET &&
- usess->consumer->enabled) {
+ if (usess && usess->consumer && usess->consumer->type == CONSUMER_DST_NET
+ && usess->consumer->enabled) {
/* For each consumer socket, send relayd sockets */
cds_lfht_for_each_entry(usess->consumer->socks->ht, &iter.iter,
socket, node.node) {
goto error;
}
}
- } else if (ksess && ksess->consumer->type == CONSUMER_DST_NET &&
- ksess->consumer->enabled) {
+ }
+
+ if (ksess && ksess->consumer && ksess->consumer->type == CONSUMER_DST_NET
+ && ksess->consumer->enabled) {
cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter,
socket, node.node) {
/* Code flow error */
return ret;
}
+/*
+ * Set consumer subdirectory using the session name and a generated datetime if
+ * needed. This is appended to the current subdirectory.
+ */
+static int set_consumer_subdir(struct consumer_output *consumer,
+ const char *session_name)
+{
+ int ret = 0;
+ unsigned int have_default_name = 0;
+ char datetime[16], tmp_path[PATH_MAX];
+ time_t rawtime;
+ struct tm *timeinfo;
+
+ assert(consumer);
+ assert(session_name);
+
+ memset(tmp_path, 0, sizeof(tmp_path));
+
+ /* Flag if we have a default session. */
+ if (strncmp(session_name, DEFAULT_SESSION_NAME "-",
+ strlen(DEFAULT_SESSION_NAME) + 1) == 0) {
+ have_default_name = 1;
+ } else {
+ /* Get date and time for session path */
+ time(&rawtime);
+ timeinfo = localtime(&rawtime);
+ strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
+ }
+
+ if (have_default_name) {
+ ret = snprintf(tmp_path, sizeof(tmp_path),
+ "%s/%s", consumer->subdir, session_name);
+ } else {
+ ret = snprintf(tmp_path, sizeof(tmp_path),
+ "%s/%s-%s/", consumer->subdir, session_name, datetime);
+ }
+ if (ret < 0) {
+ PERROR("snprintf session name date");
+ goto error;
+ }
+
+ strncpy(consumer->subdir, tmp_path, sizeof(consumer->subdir));
+ DBG2("Consumer subdir set to %s", consumer->subdir);
+
+error:
+ return ret;
+}
+
/*
* Copy consumer output from the tracing session to the domain session. The
* function also applies the right modification on a per domain basis for the
const char *dir_name;
struct consumer_output *consumer;
+ assert(session);
+ assert(session->consumer);
+
switch (domain) {
case LTTNG_DOMAIN_KERNEL:
DBG3("Copying tracing session consumer output in kernel session");
goto error;
}
+ ret = set_consumer_subdir(session->consumer, session->name);
+ if (ret < 0) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
/* Append correct directory to subdir */
strncat(consumer->subdir, dir_name, sizeof(consumer->subdir));
DBG3("Copy session consumer subdir %s", consumer->subdir);
- /* Add default trace directory name */
- if (consumer->type == CONSUMER_DST_LOCAL) {
- strncat(consumer->dst.trace_path, dir_name,
- sizeof(consumer->dst.trace_path));
- }
-
ret = LTTCOMM_OK;
error:
struct ltt_ust_session *lus = NULL;
assert(session);
+ assert(domain);
assert(session->consumer);
switch (domain->type) {
goto error;
}
- if (session->consumer->type == CONSUMER_DST_LOCAL) {
- ret = run_as_mkdir_recursive(lus->pathname, S_IRWXU | S_IRWXG,
- session->uid, session->gid);
- if (ret < 0) {
- if (ret != -EEXIST) {
- ERR("Trace directory creation error");
- ret = LTTCOMM_UST_SESS_FAIL;
- goto error;
- }
- }
- }
-
lus->uid = session->uid;
lus->gid = session->gid;
session->ust_session = lus;
goto error;
}
+ /* Code flow safety */
+ assert(session->kernel_session);
+
/* Copy session output to the newly created Kernel session */
ret = copy_session_consumer(LTTNG_DOMAIN_KERNEL, session);
if (ret != LTTCOMM_OK) {
}
/* Create directory(ies) on local filesystem. */
- if (session->consumer->type == CONSUMER_DST_LOCAL) {
+ if (session->kernel_session->consumer->type == CONSUMER_DST_LOCAL &&
+ strlen(session->kernel_session->consumer->dst.trace_path) > 0) {
ret = run_as_mkdir_recursive(
session->kernel_session->consumer->dst.trace_path,
S_IRWXU | S_IRWXG, session->uid, session->gid);
return i;
}
+/*
+ * Create a session path used by list_lttng_sessions for the case that the
+ * session consumer is on the network.
+ */
+static int build_network_session_path(char *dst, size_t size,
+ struct ltt_session *session)
+{
+ int ret, kdata_port, udata_port;
+ struct lttng_uri *kuri = NULL, *uuri = NULL, *uri = NULL;
+ char tmp_uurl[PATH_MAX], tmp_urls[PATH_MAX];
+
+ assert(session);
+ assert(dst);
+
+ memset(tmp_urls, 0, sizeof(tmp_urls));
+ memset(tmp_uurl, 0, sizeof(tmp_uurl));
+
+ kdata_port = udata_port = DEFAULT_NETWORK_DATA_PORT;
+
+ if (session->kernel_session && session->kernel_session->consumer) {
+ kuri = &session->kernel_session->consumer->dst.net.control;
+ kdata_port = session->kernel_session->consumer->dst.net.data.port;
+ }
+
+ if (session->ust_session && session->ust_session->consumer) {
+ uuri = &session->ust_session->consumer->dst.net.control;
+ udata_port = session->ust_session->consumer->dst.net.data.port;
+ }
+
+ if (uuri == NULL && kuri == NULL) {
+ uri = &session->consumer->dst.net.control;
+ kdata_port = session->consumer->dst.net.data.port;
+ } else if (kuri && uuri) {
+ ret = uri_compare(kuri, uuri);
+ if (ret) {
+ /* Not Equal */
+ uri = kuri;
+ /* Build uuri URL string */
+ ret = uri_to_str_url(uuri, tmp_uurl, sizeof(tmp_uurl));
+ if (ret < 0) {
+ goto error;
+ }
+ } else {
+ uri = kuri;
+ }
+ } else if (kuri && uuri == NULL) {
+ uri = kuri;
+ } else if (uuri && kuri == NULL) {
+ uri = uuri;
+ }
+
+ ret = uri_to_str_url(uri, tmp_urls, sizeof(tmp_urls));
+ if (ret < 0) {
+ goto error;
+ }
+
+ if (strlen(tmp_uurl) > 0) {
+ ret = snprintf(dst, size, "[K]: %s [data: %d] -- [U]: %s [data: %d]",
+ tmp_urls, kdata_port, tmp_uurl, udata_port);
+ } else {
+ ret = snprintf(dst, size, "%s [data: %d]", tmp_urls, kdata_port);
+ }
+
+error:
+ return ret;
+}
+
/*
* Using the session list, filled a lttng_session array to send back to the
* client for session listing.
static void list_lttng_sessions(struct lttng_session *sessions, uid_t uid,
gid_t gid)
{
+ int ret;
unsigned int i = 0;
struct ltt_session *session;
if (!session_access_ok(session, uid, gid)) {
continue;
}
- strncpy(sessions[i].path, session->path, PATH_MAX);
- sessions[i].path[PATH_MAX - 1] = '\0';
+
+ struct ltt_kernel_session *ksess = session->kernel_session;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ if (session->consumer->type == CONSUMER_DST_NET ||
+ (ksess && ksess->consumer->type == CONSUMER_DST_NET) ||
+ (usess && usess->consumer->type == CONSUMER_DST_NET)) {
+ ret = build_network_session_path(sessions[i].path,
+ sizeof(session[i].path), session);
+ } else {
+ ret = snprintf(sessions[i].path, sizeof(session[i].path), "%s",
+ session->consumer->dst.trace_path);
+ }
+ if (ret < 0) {
+ PERROR("snprintf session path");
+ continue;
+ }
+
strncpy(sessions[i].name, session->name, NAME_MAX);
sessions[i].name[NAME_MAX - 1] = '\0';
sessions[i].enabled = session->enabled;
return ret;
}
+
+/*
+ * Add URI so the consumer output object. Set the correct path depending on the
+ * domain adding the default trace directory.
+ */
+static int add_uri_to_consumer(struct consumer_output *consumer,
+ struct lttng_uri *uri, int domain, const char *session_name)
+{
+ int ret = LTTCOMM_OK;
+ const char *default_trace_dir;
+
+ assert(uri);
+
+ if (consumer == NULL) {
+ DBG("No consumer detected. Don't add URI. Stopping.");
+ ret = LTTCOMM_NO_CONSUMER;
+ goto error;
+ }
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ default_trace_dir = DEFAULT_KERNEL_TRACE_DIR;
+ break;
+ case LTTNG_DOMAIN_UST:
+ default_trace_dir = DEFAULT_UST_TRACE_DIR;
+ break;
+ default:
+ /*
+ * This case is possible is we try to add the URI to the global tracing
+ * session consumer object which in this case there is no subdir.
+ */
+ default_trace_dir = "";
+ }
+
+ switch (uri->dtype) {
+ case LTTNG_DST_IPV4:
+ case LTTNG_DST_IPV6:
+ DBG2("Setting network URI to consumer");
+
+ /* Set URI into consumer output object */
+ ret = consumer_set_network_uri(consumer, uri);
+ if (ret < 0) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ } else if (ret == 1) {
+ /*
+ * URI was the same in the consumer so we do not append the subdir
+ * again so to not duplicate output dir.
+ */
+ goto error;
+ }
+
+ if (uri->stype == LTTNG_STREAM_CONTROL && strlen(uri->subdir) == 0) {
+ ret = set_consumer_subdir(consumer, session_name);
+ if (ret < 0) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+ }
+
+ if (uri->stype == LTTNG_STREAM_CONTROL) {
+ /* On a new subdir, reappend the default trace dir. */
+ strncat(consumer->subdir, default_trace_dir, sizeof(consumer->subdir));
+ DBG3("Append domain trace name to subdir %s", consumer->subdir);
+ }
+
+ break;
+ case LTTNG_DST_PATH:
+ DBG2("Setting trace directory path from URI to %s", uri->dst.path);
+ memset(consumer->dst.trace_path, 0,
+ sizeof(consumer->dst.trace_path));
+ strncpy(consumer->dst.trace_path, uri->dst.path,
+ sizeof(consumer->dst.trace_path));
+ /* Append default trace dir */
+ strncat(consumer->dst.trace_path, default_trace_dir,
+ sizeof(consumer->dst.trace_path));
+ /* Flag consumer as local. */
+ consumer->type = CONSUMER_DST_LOCAL;
+ break;
+ }
+
+error:
+ return ret;
+}
+
/*
* Command LTTNG_DISABLE_CHANNEL processed by the client thread.
*/
if (ksession != NULL) {
/* Open kernel metadata */
if (ksession->metadata == NULL) {
- ret = kernel_open_metadata(ksession,
- ksession->consumer->dst.trace_path);
+ ret = kernel_open_metadata(ksession);
if (ret < 0) {
ret = LTTCOMM_KERN_META_FAIL;
goto error;
}
/*
- * Command LTTNG_CREATE_SESSION_URI processed by the client thread.
+ * Command LTTNG_SET_CONSUMER_URI processed by the client thread.
*/
-static int cmd_create_session_uri(char *name, struct lttng_uri *ctrl_uri,
- struct lttng_uri *data_uri, unsigned int enable_consumer,
- lttng_sock_cred *creds)
+static int cmd_set_consumer_uri(int domain, struct ltt_session *session,
+ size_t nb_uri, struct lttng_uri *uris)
{
- int ret;
- char *path = NULL;
- struct ltt_session *session;
- struct consumer_output *consumer;
+ int ret, i;
+ struct ltt_kernel_session *ksess = session->kernel_session;
+ struct ltt_ust_session *usess = session->ust_session;
+ struct consumer_output *consumer = NULL;
- /* Verify if the session already exist */
- session = session_find_by_name(name);
- if (session != NULL) {
- ret = LTTCOMM_EXIST_SESS;
+ assert(session);
+ assert(uris);
+ assert(nb_uri > 0);
+
+ /* Can't enable consumer after session started. */
+ if (session->enabled) {
+ ret = LTTCOMM_TRACE_ALREADY_STARTED;
goto error;
}
- /* TODO: validate URIs */
-
- /* Create default consumer output */
- consumer = consumer_create_output(CONSUMER_DST_LOCAL);
- if (consumer == NULL) {
- ret = LTTCOMM_FATAL;
+ if (!session->start_consumer) {
+ ret = LTTCOMM_NO_CONSUMER;
goto error;
}
- strncpy(consumer->subdir, ctrl_uri->subdir, sizeof(consumer->subdir));
- DBG2("Consumer subdir set to %s", consumer->subdir);
- switch (ctrl_uri->dtype) {
- case LTTNG_DST_IPV4:
- case LTTNG_DST_IPV6:
- /* Set control URI into consumer output object */
- ret = consumer_set_network_uri(consumer, ctrl_uri);
- if (ret < 0) {
- ret = LTTCOMM_FATAL;
- goto error;
- }
+ /*
+ * This case switch makes sure the domain session has a temporary consumer
+ * so the URL can be set.
+ */
+ switch (domain) {
+ case 0:
+ /* Code flow error. A session MUST always have a consumer object */
+ assert(session->consumer);
+ /*
+ * The URL will be added to the tracing session consumer instead of a
+ * specific domain consumer.
+ */
+ consumer = session->consumer;
+ break;
+ case LTTNG_DOMAIN_KERNEL:
+ /* Code flow error if we don't have a kernel session here. */
+ assert(ksess);
- /* Set data URI into consumer output object */
- ret = consumer_set_network_uri(consumer, data_uri);
- if (ret < 0) {
- ret = LTTCOMM_FATAL;
- goto error;
+ /* Create consumer output if none exists */
+ consumer = ksess->tmp_consumer;
+ if (consumer == NULL) {
+ consumer = consumer_copy_output(ksess->consumer);
+ if (consumer == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+ /* Trash the consumer subdir, we are about to set a new one. */
+ memset(consumer->subdir, 0, sizeof(consumer->subdir));
+ ksess->tmp_consumer = consumer;
}
- /* Empty path since the session is network */
- path = "";
break;
- case LTTNG_DST_PATH:
- /* Very volatile pointer. Only used for the create session. */
- path = ctrl_uri->dst.path;
- strncpy(consumer->dst.trace_path, path,
- sizeof(consumer->dst.trace_path));
+ case LTTNG_DOMAIN_UST:
+ /* Code flow error if we don't have a kernel session here. */
+ assert(usess);
+
+ /* Create consumer output if none exists */
+ consumer = usess->tmp_consumer;
+ if (consumer == NULL) {
+ consumer = consumer_copy_output(usess->consumer);
+ if (consumer == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+ /* Trash the consumer subdir, we are about to set a new one. */
+ memset(consumer->subdir, 0, sizeof(consumer->subdir));
+ usess->tmp_consumer = consumer;
+ }
+
break;
}
- /* Set if the consumer is enabled or not */
- consumer->enabled = enable_consumer;
+ for (i = 0; i < nb_uri; i++) {
+ struct consumer_socket *socket;
+ struct lttng_ht_iter iter;
- ret = session_create(name, path, LTTNG_SOCK_GET_UID_CRED(creds),
- LTTNG_SOCK_GET_GID_CRED(creds));
- if (ret != LTTCOMM_OK) {
- goto consumer_error;
- }
+ ret = add_uri_to_consumer(consumer, &uris[i], domain, session->name);
+ if (ret < 0) {
+ goto error;
+ }
- /* Get the newly created session pointer back */
- session = session_find_by_name(name);
- assert(session);
+ /*
+ * Don't send relayd socket if URI is NOT remote or if the relayd
+ * sockets for the session are already sent.
+ */
+ if (uris[i].dtype == LTTNG_DST_PATH ||
+ consumer->dst.net.relayd_socks_sent) {
+ continue;
+ }
- /* Assign consumer to session */
- session->consumer = consumer;
+ /* Try to send relayd URI to the consumer if exist. */
+ cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter,
+ socket, node.node) {
- return LTTCOMM_OK;
+ /* A socket in the HT should never have a negative fd */
+ assert(socket->fd >= 0);
+
+ pthread_mutex_lock(socket->lock);
+ ret = send_socket_relayd_consumer(domain, session, &uris[i],
+ consumer, socket->fd);
+ pthread_mutex_unlock(socket->lock);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+ }
+ }
+
+ /* All good! */
+ ret = LTTCOMM_OK;
-consumer_error:
- consumer_destroy_output(consumer);
error:
return ret;
}
+
/*
* Command LTTNG_CREATE_SESSION processed by the client thread.
*/
-static int cmd_create_session(char *name, char *path, lttng_sock_cred *creds)
+static int cmd_create_session_uri(char *name, struct lttng_uri *uris,
+ size_t nb_uri, lttng_sock_cred *creds)
{
int ret;
- struct lttng_uri uri;
+ char *path = NULL;
+ struct ltt_session *session;
- /* Zeroed temporary URI */
- memset(&uri, 0, sizeof(uri));
+ assert(name);
- uri.dtype = LTTNG_DST_PATH;
- uri.utype = LTTNG_URI_DST;
- strncpy(uri.dst.path, path, sizeof(uri.dst.path));
+ /*
+ * Verify if the session already exist
+ *
+ * XXX: There is no need for the session lock list here since the caller
+ * (process_client_msg) is holding it. We might want to change that so a
+ * single command does not lock the entire session list.
+ */
+ session = session_find_by_name(name);
+ if (session != NULL) {
+ ret = LTTCOMM_EXIST_SESS;
+ goto find_error;
+ }
- /* TODO: Strip date-time from path and put it in uri's subdir */
+ /* Create tracing session in the registry */
+ ret = session_create(name, path, LTTNG_SOCK_GET_UID_CRED(creds),
+ LTTNG_SOCK_GET_GID_CRED(creds));
+ if (ret != LTTCOMM_OK) {
+ goto session_error;
+ }
- ret = cmd_create_session_uri(name, &uri, NULL, 1, creds);
+ /*
+ * Get the newly created session pointer back
+ *
+ * XXX: There is no need for the session lock list here since the caller
+ * (process_client_msg) is holding it. We might want to change that so a
+ * single command does not lock the entire session list.
+ */
+ session = session_find_by_name(name);
+ assert(session);
+
+ /* Create default consumer output for the session not yet created. */
+ session->consumer = consumer_create_output(CONSUMER_DST_LOCAL);
+ if (session->consumer == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto consumer_error;
+ }
+
+ /*
+ * This means that the lttng_create_session call was called with the _path_
+ * argument set to NULL.
+ */
+ if (uris == NULL) {
+ /*
+ * At this point, we'll skip the consumer URI setup and create a
+ * session with a NULL path which will flag the session to NOT spawn a
+ * consumer.
+ */
+ DBG("Create session %s with NO uri, skipping consumer setup", name);
+ goto end;
+ }
+
+ session->start_consumer = 1;
+
+ ret = cmd_set_consumer_uri(0, session, nb_uri, uris);
if (ret != LTTCOMM_OK) {
- goto error;
+ goto consumer_error;
}
-error:
+ session->consumer->enabled = 1;
+
+end:
+ return LTTCOMM_OK;
+
+consumer_error:
+ session_destroy(session);
+session_error:
+find_error:
return ret;
}
goto error;
}
+ socket->lock = zmalloc(sizeof(pthread_mutex_t));
+ if (socket->lock == NULL) {
+ PERROR("zmalloc pthread mutex");
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+ pthread_mutex_init(socket->lock, NULL);
+
rcu_read_lock();
consumer_add_socket(socket, session->kernel_session->consumer);
rcu_read_unlock();
+ pthread_mutex_lock(&kconsumer_data.pid_mutex);
+ kconsumer_data.pid = -1;
+ pthread_mutex_unlock(&kconsumer_data.pid_mutex);
+
break;
default:
/* TODO: Userspace tracing */
return ret;
}
-/*
- * Command LTTNG_SET_CONSUMER_URI processed by the client thread.
- */
-static int cmd_set_consumer_uri(int domain, struct ltt_session *session,
- struct lttng_uri *uri)
-{
- int ret;
- struct ltt_kernel_session *ksess = session->kernel_session;
- struct ltt_ust_session *usess = session->ust_session;
- struct consumer_output *consumer;
-
- /* Can't enable consumer after session started. */
- if (session->enabled) {
- ret = LTTCOMM_TRACE_ALREADY_STARTED;
- goto error;
- }
-
- switch (domain) {
- case LTTNG_DOMAIN_KERNEL:
- {
- struct lttng_ht_iter iter;
- struct consumer_socket *socket;
-
- /* Code flow error if we don't have a kernel session here. */
- assert(ksess);
-
- /* Create consumer output if none exists */
- consumer = ksess->tmp_consumer;
- if (consumer == NULL) {
- consumer = consumer_copy_output(ksess->consumer);
- if (consumer == NULL) {
- ret = LTTCOMM_FATAL;
- goto error;
- }
- /* Reassign new pointer */
- ksess->tmp_consumer = consumer;
- }
-
- switch (uri->dtype) {
- case LTTNG_DST_IPV4:
- case LTTNG_DST_IPV6:
- DBG2("Setting network URI for kernel session %s", session->name);
-
- /* Set URI into consumer output object */
- ret = consumer_set_network_uri(consumer, uri);
- if (ret < 0) {
- ret = LTTCOMM_FATAL;
- goto error;
- }
-
- /* On a new subdir, reappend the default trace dir. */
- if (strlen(uri->subdir) != 0) {
- strncat(consumer->subdir, DEFAULT_KERNEL_TRACE_DIR,
- sizeof(consumer->subdir));
- }
-
- cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter,
- socket, node.node) {
- /* Code flow error */
- assert(socket->fd >= 0);
-
- pthread_mutex_lock(socket->lock);
- ret = send_socket_relayd_consumer(domain, session, uri, consumer,
- socket->fd);
- pthread_mutex_unlock(socket->lock);
- if (ret != LTTCOMM_OK) {
- goto error;
- }
- }
-
- break;
- case LTTNG_DST_PATH:
- DBG2("Setting trace directory path from URI to %s", uri->dst.path);
- memset(consumer->dst.trace_path, 0,
- sizeof(consumer->dst.trace_path));
- strncpy(consumer->dst.trace_path, uri->dst.path,
- sizeof(consumer->dst.trace_path));
- /* Append default kernel trace dir */
- strncat(consumer->dst.trace_path, DEFAULT_KERNEL_TRACE_DIR,
- sizeof(consumer->dst.trace_path));
- break;
- }
-
- /* All good! */
- break;
- }
- case LTTNG_DOMAIN_UST:
- /* Code flow error if we don't have a kernel session here. */
- assert(usess);
-
- /* Create consumer output if none exists */
- consumer = usess->tmp_consumer;
- if (consumer == NULL) {
- consumer = consumer_copy_output(usess->consumer);
- if (consumer == NULL) {
- ret = LTTCOMM_FATAL;
- goto error;
- }
- /* Reassign new pointer */
- usess->tmp_consumer = consumer;
- }
-
- switch (uri->dtype) {
- case LTTNG_DST_IPV4:
- case LTTNG_DST_IPV6:
- {
- struct consumer_socket *socket;
-
- DBG2("Setting network URI for UST session %s", session->name);
-
- /* Set URI into consumer object */
- ret = consumer_set_network_uri(consumer, uri);
- if (ret < 0) {
- ret = LTTCOMM_FATAL;
- goto error;
- }
-
- /* On a new subdir, reappend the default trace dir. */
- if (strlen(uri->subdir) != 0) {
- strncat(consumer->subdir, DEFAULT_UST_TRACE_DIR,
- sizeof(consumer->subdir));
- }
-
- rcu_read_lock();
- socket = consumer_find_socket(uatomic_read(&ust_consumerd64_fd),
- consumer);
- if (socket != NULL) {
- pthread_mutex_lock(socket->lock);
- ret = send_socket_relayd_consumer(domain, session, uri,
- consumer, socket->fd);
- pthread_mutex_unlock(socket->lock);
- if (ret != LTTCOMM_OK) {
- goto error;
- }
- }
-
- socket = consumer_find_socket(uatomic_read(&ust_consumerd32_fd),
- consumer);
- if (socket != NULL) {
- pthread_mutex_lock(socket->lock);
- ret = send_socket_relayd_consumer(domain, session, uri,
- consumer, socket->fd);
- pthread_mutex_unlock(socket->lock);
- if (ret != LTTCOMM_OK) {
- goto error;
- }
- }
- rcu_read_unlock();
- break;
- }
- case LTTNG_DST_PATH:
- DBG2("Setting trace directory path from URI to %s", uri->dst.path);
- memset(consumer->dst.trace_path, 0,
- sizeof(consumer->dst.trace_path));
- strncpy(consumer->dst.trace_path, uri->dst.path,
- sizeof(consumer->dst.trace_path));
- /* Append default UST trace dir */
- strncat(consumer->dst.trace_path, DEFAULT_UST_TRACE_DIR,
- sizeof(consumer->dst.trace_path));
- break;
- }
- break;
- }
-
- /* All good! */
- ret = LTTCOMM_OK;
-
-error:
- return ret;
-}
-
/*
* Command LTTNG_DISABLE_CONSUMER processed by the client thread.
*/
struct ltt_ust_session *usess = session->ust_session;
struct consumer_output *consumer;
+ assert(session);
+
if (session->enabled) {
/* Can't disable consumer on an already started session */
ret = LTTCOMM_TRACE_ALREADY_STARTED;
goto error;
}
+ if (!session->start_consumer) {
+ ret = LTTCOMM_NO_CONSUMER;
+ goto error;
+ }
+
switch (domain) {
+ case 0:
+ DBG("Disable tracing session %s consumer", session->name);
+ consumer = session->consumer;
+ break;
case LTTNG_DOMAIN_KERNEL:
/* Code flow error if we don't have a kernel session here. */
assert(ksess);
goto error;
}
- assert(consumer);
- consumer->enabled = 0;
-
- /* Success at this point */
- ret = LTTCOMM_OK;
+ if (consumer) {
+ consumer->enabled = 0;
+ /* Success at this point */
+ ret = LTTCOMM_OK;
+ } else {
+ ret = LTTCOMM_NO_CONSUMER;
+ }
error:
return ret;
int ret;
struct ltt_kernel_session *ksess = session->kernel_session;
struct ltt_ust_session *usess = session->ust_session;
- struct consumer_output *tmp_out;
+ struct consumer_output *consumer = NULL;
+
+ assert(session);
/* Can't enable consumer after session started. */
if (session->enabled) {
goto error;
}
+ if (!session->start_consumer) {
+ ret = LTTCOMM_NO_CONSUMER;
+ goto error;
+ }
+
switch (domain) {
+ case 0:
+ assert(session->consumer);
+ consumer = session->consumer;
+ break;
case LTTNG_DOMAIN_KERNEL:
/* Code flow error if we don't have a kernel session here. */
assert(ksess);
goto error;
}
- tmp_out = ksess->tmp_consumer;
- if (tmp_out == NULL) {
+ consumer = ksess->tmp_consumer;
+ if (consumer == NULL) {
+ ret = LTTCOMM_OK;
/* No temp. consumer output exists. Using the current one. */
DBG3("No temporary consumer. Using default");
- ret = LTTCOMM_OK;
+ consumer = ksess->consumer;
goto error;
}
- switch (tmp_out->type) {
+ switch (consumer->type) {
case CONSUMER_DST_LOCAL:
DBG2("Consumer output is local. Creating directory(ies)");
/* Create directory(ies) */
- ret = run_as_mkdir_recursive(tmp_out->dst.trace_path,
+ ret = run_as_mkdir_recursive(consumer->dst.trace_path,
S_IRWXU | S_IRWXG, session->uid, session->gid);
if (ret < 0) {
if (ret != -EEXIST) {
case CONSUMER_DST_NET:
DBG2("Consumer output is network. Validating URIs");
/* Validate if we have both control and data path set. */
- if (!tmp_out->dst.net.control_isset) {
- ret = LTTCOMM_URI_CTRL_MISS;
+ if (!consumer->dst.net.control_isset) {
+ ret = LTTCOMM_URL_CTRL_MISS;
goto error;
}
- if (!tmp_out->dst.net.data_isset) {
- ret = LTTCOMM_URI_DATA_MISS;
+ if (!consumer->dst.net.data_isset) {
+ ret = LTTCOMM_URL_DATA_MISS;
goto error;
}
goto error;
}
- /* Append default kernel trace dir to subdir */
- strncat(ksess->consumer->subdir, DEFAULT_KERNEL_TRACE_DIR,
- sizeof(ksess->consumer->subdir));
-
break;
}
+ /* Append default kernel trace dir to subdir */
+ strncat(ksess->consumer->subdir, DEFAULT_KERNEL_TRACE_DIR,
+ sizeof(ksess->consumer->subdir));
+
/*
* @session-lock
* This is race free for now since the session lock is acquired before
* session without this lock hence freeing the consumer output object
* is valid.
*/
+ rcu_read_lock();
consumer_destroy_output(ksess->consumer);
- ksess->consumer = tmp_out;
+ rcu_read_unlock();
+ ksess->consumer = consumer;
ksess->tmp_consumer = NULL;
break;
goto error;
}
- tmp_out = usess->tmp_consumer;
- if (tmp_out == NULL) {
+ consumer = usess->tmp_consumer;
+ if (consumer == NULL) {
+ ret = LTTCOMM_OK;
/* No temp. consumer output exists. Using the current one. */
DBG3("No temporary consumer. Using default");
- ret = LTTCOMM_OK;
+ consumer = usess->consumer;
goto error;
}
- switch (tmp_out->type) {
+ switch (consumer->type) {
case CONSUMER_DST_LOCAL:
DBG2("Consumer output is local. Creating directory(ies)");
/* Create directory(ies) */
- ret = run_as_mkdir_recursive(tmp_out->dst.trace_path,
+ ret = run_as_mkdir_recursive(consumer->dst.trace_path,
S_IRWXU | S_IRWXG, session->uid, session->gid);
if (ret < 0) {
if (ret != -EEXIST) {
case CONSUMER_DST_NET:
DBG2("Consumer output is network. Validating URIs");
/* Validate if we have both control and data path set. */
- if (!tmp_out->dst.net.control_isset) {
- ret = LTTCOMM_URI_CTRL_MISS;
+ if (!consumer->dst.net.control_isset) {
+ ret = LTTCOMM_URL_CTRL_MISS;
goto error;
}
- if (!tmp_out->dst.net.data_isset) {
- ret = LTTCOMM_URI_DATA_MISS;
+ if (!consumer->dst.net.data_isset) {
+ ret = LTTCOMM_URL_DATA_MISS;
goto error;
}
goto error;
}
- if (tmp_out->net_seq_index == -1) {
+ if (consumer->net_seq_index == -1) {
ret = LTTCOMM_ENABLE_CONSUMER_FAIL;
DBG2("Network index is not set on the consumer");
goto error;
}
- /* Append default kernel trace dir to subdir */
- strncat(usess->consumer->subdir, DEFAULT_UST_TRACE_DIR,
- sizeof(usess->consumer->subdir));
-
break;
}
+ /* Append default kernel trace dir to subdir */
+ strncat(usess->consumer->subdir, DEFAULT_UST_TRACE_DIR,
+ sizeof(usess->consumer->subdir));
+
/*
* @session-lock
* This is race free for now since the session lock is acquired before
* session without this lock hence freeing the consumer output object
* is valid.
*/
+ rcu_read_lock();
consumer_destroy_output(usess->consumer);
- usess->consumer = tmp_out;
+ rcu_read_unlock();
+ usess->consumer = consumer;
usess->tmp_consumer = NULL;
break;
}
- /* Success at this point */
- ret = LTTCOMM_OK;
+ /* Enable it */
+ if (consumer) {
+ consumer->enabled = 1;
+ /* Success at this point */
+ ret = LTTCOMM_OK;
+ } else {
+ /* Should not really happend... */
+ ret = LTTCOMM_NO_CONSUMER;
+ }
error:
return ret;
switch (cmd_ctx->lsm->cmd_type) {
case LTTNG_CREATE_SESSION:
- case LTTNG_CREATE_SESSION_URI:
case LTTNG_DESTROY_SESSION:
case LTTNG_LIST_SESSIONS:
case LTTNG_LIST_DOMAINS:
goto error;
}
+ /* Deny register consumer if we already have a spawned consumer. */
+ if (cmd_ctx->lsm->cmd_type == LTTNG_REGISTER_CONSUMER) {
+ pthread_mutex_lock(&kconsumer_data.pid_mutex);
+ if (kconsumer_data.pid > 0) {
+ ret = LTTCOMM_KERN_CONSUMER_FAIL;
+ goto error;
+ }
+ pthread_mutex_unlock(&kconsumer_data.pid_mutex);
+ }
+
/*
* Check for command that don't needs to allocate a returned payload. We do
* this here so we don't have to make the call for no payload at each
/* Commands that DO NOT need a session. */
switch (cmd_ctx->lsm->cmd_type) {
case LTTNG_CREATE_SESSION:
- case LTTNG_CREATE_SESSION_URI:
case LTTNG_CALIBRATE:
case LTTNG_LIST_SESSIONS:
case LTTNG_LIST_TRACEPOINTS:
if (!need_domain) {
goto skip_domain;
}
+
/*
* Check domain type for specific "pre-action".
*/
/* Need a session for kernel command */
if (need_tracing_session) {
- struct consumer_socket *socket;
-
if (cmd_ctx->session->kernel_session == NULL) {
ret = create_kernel_session(cmd_ctx->session);
if (ret < 0) {
/* Start the kernel consumer daemon */
pthread_mutex_lock(&kconsumer_data.pid_mutex);
if (kconsumer_data.pid == 0 &&
- cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) {
+ cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER &&
+ cmd_ctx->session->start_consumer) {
pthread_mutex_unlock(&kconsumer_data.pid_mutex);
ret = start_consumerd(&kconsumer_data);
if (ret < 0) {
pthread_mutex_unlock(&kconsumer_data.pid_mutex);
}
- /* Set kernel consumer socket fd */
- if (kconsumer_data.cmd_sock >= 0) {
- rcu_read_lock();
- socket = consumer_find_socket(kconsumer_data.cmd_sock,
- cmd_ctx->session->kernel_session->consumer);
- rcu_read_unlock();
- if (socket == NULL) {
- socket = consumer_allocate_socket(kconsumer_data.cmd_sock);
- if (socket == NULL) {
- goto error;
- }
-
- socket->lock = &kconsumer_data.lock;
- rcu_read_lock();
- consumer_add_socket(socket,
- cmd_ctx->session->kernel_session->consumer);
- rcu_read_unlock();
- }
+ /*
+ * The consumer was just spawned so we need to add the socket to
+ * the consumer output of the session if exist.
+ */
+ ret = consumer_create_socket(&kconsumer_data,
+ cmd_ctx->session->kernel_session->consumer);
+ if (ret < 0) {
+ goto error;
}
}
}
if (need_tracing_session) {
- struct consumer_socket *socket;
-
+ /* Create UST session if none exist. */
if (cmd_ctx->session->ust_session == NULL) {
ret = create_ust_session(cmd_ctx->session,
&cmd_ctx->lsm->domain);
pthread_mutex_lock(&ustconsumer64_data.pid_mutex);
if (consumerd64_bin[0] != '\0' &&
ustconsumer64_data.pid == 0 &&
- cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) {
+ cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER &&
+ cmd_ctx->session->start_consumer) {
pthread_mutex_unlock(&ustconsumer64_data.pid_mutex);
ret = start_consumerd(&ustconsumer64_data);
if (ret < 0) {
* Setup socket for consumer 64 bit. No need for atomic access
* since it was set above and can ONLY be set in this thread.
*/
- if (ust_consumerd64_fd >= 0) {
- rcu_read_lock();
- socket = consumer_find_socket(uatomic_read(&ust_consumerd64_fd),
- cmd_ctx->session->ust_session->consumer);
- rcu_read_unlock();
- if (socket == NULL) {
- socket = consumer_allocate_socket(ust_consumerd64_fd);
- if (socket == NULL) {
- goto error;
- }
- socket->lock = &ustconsumer32_data.lock;
-
- rcu_read_lock();
- consumer_add_socket(socket,
- cmd_ctx->session->ust_session->consumer);
- rcu_read_unlock();
- }
- DBG3("UST consumer 64 bit socket set to %d", socket->fd);
+ ret = consumer_create_socket(&ustconsumer64_data,
+ cmd_ctx->session->ust_session->consumer);
+ if (ret < 0) {
+ goto error;
}
/* 32-bit */
if (consumerd32_bin[0] != '\0' &&
ustconsumer32_data.pid == 0 &&
- cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER) {
+ cmd_ctx->lsm->cmd_type != LTTNG_REGISTER_CONSUMER &&
+ cmd_ctx->session->start_consumer) {
pthread_mutex_unlock(&ustconsumer32_data.pid_mutex);
ret = start_consumerd(&ustconsumer32_data);
if (ret < 0) {
* Setup socket for consumer 64 bit. No need for atomic access
* since it was set above and can ONLY be set in this thread.
*/
- if (ust_consumerd32_fd >= 0) {
- rcu_read_lock();
- socket = consumer_find_socket(uatomic_read(&ust_consumerd64_fd),
- cmd_ctx->session->ust_session->consumer);
- rcu_read_unlock();
- if (socket == NULL) {
- socket = consumer_allocate_socket(ust_consumerd32_fd);
- if (socket == NULL) {
- goto error;
- }
- socket->lock = &ustconsumer32_data.lock;
-
- rcu_read_lock();
- consumer_add_socket(socket,
- cmd_ctx->session->ust_session->consumer);
- rcu_read_unlock();
- }
- DBG3("UST consumer 32 bit socket set to %d", socket->fd);
+ ret = consumer_create_socket(&ustconsumer32_data,
+ cmd_ctx->session->ust_session->consumer);
+ if (ret < 0) {
+ goto error;
}
}
break;
}
case LTTNG_ENABLE_CONSUMER:
{
+ /*
+ * XXX: 0 means that this URI should be applied on the session. Should
+ * be a DOMAIN enuam.
+ */
ret = cmd_enable_consumer(cmd_ctx->lsm->domain.type, cmd_ctx->session);
+ if (ret != LTTCOMM_OK) {
+ goto error;
+ }
+
+ 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_enable_consumer(LTTNG_DOMAIN_UST, cmd_ctx->session);
+ } else if (cmd_ctx->session->kernel_session &&
+ cmd_ctx->session->kernel_session->consumer) {
+ ret = cmd_enable_consumer(LTTNG_DOMAIN_KERNEL,
+ cmd_ctx->session);
+ }
+ }
break;
}
case LTTNG_ENABLE_EVENT:
struct lttng_event_field *fields;
ssize_t nb_fields;
- nb_fields = cmd_list_tracepoint_fields(cmd_ctx->lsm->domain.type, &fields);
+ nb_fields = cmd_list_tracepoint_fields(cmd_ctx->lsm->domain.type,
+ &fields);
if (nb_fields < 0) {
ret = -nb_fields;
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_field) * nb_fields);
+ ret = setup_lttng_msg(cmd_ctx,
+ sizeof(struct lttng_event_field) * nb_fields);
if (ret < 0) {
free(fields);
goto setup_error;
}
case LTTNG_SET_CONSUMER_URI:
{
+ size_t nb_uri, len;
+ struct lttng_uri *uris;
+
+ nb_uri = cmd_ctx->lsm->u.uri.size;
+ len = nb_uri * sizeof(struct lttng_uri);
+
+ if (nb_uri == 0) {
+ ret = LTTCOMM_INVALID;
+ goto error;
+ }
+
+ uris = zmalloc(len);
+ if (uris == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ /* Receive variable len data */
+ DBG("Receiving %zu URI(s) from client ...", nb_uri);
+ ret = lttcomm_recv_unix_sock(sock, uris, len);
+ if (ret <= 0) {
+ DBG("No URIs received from client... continuing");
+ *sock_error = 1;
+ ret = LTTCOMM_SESSION_FAIL;
+ goto error;
+ }
+
ret = cmd_set_consumer_uri(cmd_ctx->lsm->domain.type, cmd_ctx->session,
- &cmd_ctx->lsm->u.uri);
+ nb_uri, uris);
+ if (ret != LTTCOMM_OK) {
+ 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);
+ }
+ }
+
break;
}
case LTTNG_START_TRACE:
}
case LTTNG_CREATE_SESSION:
{
- ret = cmd_create_session(cmd_ctx->lsm->session.name,
- cmd_ctx->lsm->session.path, &cmd_ctx->creds);
- break;
- }
- case LTTNG_CREATE_SESSION_URI:
- {
- ret = cmd_create_session_uri(cmd_ctx->lsm->session.name,
- &cmd_ctx->lsm->u.create_uri.ctrl_uri,
- &cmd_ctx->lsm->u.create_uri.data_uri,
- cmd_ctx->lsm->u.create_uri.enable_consumer, &cmd_ctx->creds);
+ size_t nb_uri, len;
+ struct lttng_uri *uris = NULL;
+
+ nb_uri = cmd_ctx->lsm->u.uri.size;
+ len = nb_uri * sizeof(struct lttng_uri);
+
+ if (nb_uri > 0) {
+ uris = zmalloc(len);
+ if (uris == NULL) {
+ ret = LTTCOMM_FATAL;
+ goto error;
+ }
+
+ /* Receive variable len data */
+ DBG("Waiting for %zu URIs from client ...", nb_uri);
+ ret = lttcomm_recv_unix_sock(sock, uris, len);
+ if (ret <= 0) {
+ DBG("No URIs received from client... continuing");
+ *sock_error = 1;
+ ret = LTTCOMM_SESSION_FAIL;
+ goto error;
+ }
+
+ if (nb_uri == 1 && uris[0].dtype != LTTNG_DST_PATH) {
+ DBG("Creating session with ONE network URI is a bad call");
+ ret = LTTCOMM_SESSION_FAIL;
+ goto error;
+ }
+ }
+
+ ret = cmd_create_session_uri(cmd_ctx->lsm->session.name, uris, nb_uri,
+ &cmd_ctx->creds);
+
break;
}
case LTTNG_DESTROY_SESSION:
{
ret = cmd_destroy_session(cmd_ctx->session,
cmd_ctx->lsm->session.name);
- /*
- * Set session to NULL so we do not unlock it after
- * free.
- */
+
+ /* Set session to NULL so we do not unlock it after free. */
cmd_ctx->session = NULL;
break;
}
*/
static void *thread_manage_health(void *data)
{
- int sock = -1, new_sock, ret, i, pollfd, err = -1;
+ int sock = -1, new_sock = -1, ret, i, pollfd, err = -1;
uint32_t revents, nb_fd;
struct lttng_poll_event events;
struct lttcomm_health_msg msg;