/*
- * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2 only,
- * as published by the Free Software Foundation.
+ * SPDX-License-Identifier: GPL-2.0-only
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define _LGPL_SOURCE
-#include <errno.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdio.h>
#include <urcu/compiler.h>
#include <signal.h>
+#include <common/compat/errno.h>
#include <common/common.h>
#include <common/sessiond-comm/sessiond-comm.h>
#include "notification-thread-commands.h"
#include "rotate.h"
+struct lttng_ht *ust_app_ht;
+struct lttng_ht *ust_app_ht_by_sock;
+struct lttng_ht *ust_app_ht_by_notify_sock;
+
static
int ust_app_flush_app_session(struct ust_app *app, struct ust_app_session *ua_sess);
{
struct buffer_reg_uid *reg_uid = buffer_reg_uid_find(
ua_sess->tracing_id, ua_sess->bits_per_long,
- ua_sess->real_credentials.uid);
+ lttng_credentials_get_uid(&ua_sess->real_credentials));
if (!reg_uid) {
goto error;
}
* Alloc new UST app channel.
*/
static
-struct ust_app_channel *alloc_ust_app_channel(char *name,
+struct ust_app_channel *alloc_ust_app_channel(const char *name,
struct ust_app_session *ua_sess,
struct lttng_ust_channel_attr *attr)
{
if (uctx) {
memcpy(&ua_ctx->ctx, uctx, sizeof(ua_ctx->ctx));
if (uctx->ctx == LTTNG_UST_CONTEXT_APP_CONTEXT) {
- char *provider_name = NULL, *ctx_name = NULL;
+ char *provider_name = NULL, *ctx_name = NULL;
provider_name = strdup(uctx->u.app_ctx.provider_name);
ctx_name = strdup(uctx->u.app_ctx.ctx_name);
ua_sess->tracing_id = usess->id;
ua_sess->id = get_next_session_id();
- ua_sess->real_credentials.uid = app->uid;
- ua_sess->real_credentials.gid = app->gid;
- ua_sess->effective_credentials.uid = usess->uid;
- ua_sess->effective_credentials.gid = usess->gid;
+ LTTNG_OPTIONAL_SET(&ua_sess->real_credentials.uid, app->uid);
+ LTTNG_OPTIONAL_SET(&ua_sess->real_credentials.gid, app->gid);
+ LTTNG_OPTIONAL_SET(&ua_sess->effective_credentials.uid, usess->uid);
+ LTTNG_OPTIONAL_SET(&ua_sess->effective_credentials.gid, usess->gid);
ua_sess->buffer_type = usess->buffer_type;
ua_sess->bits_per_long = app->bits_per_long;
case LTTNG_BUFFER_PER_UID:
ret = snprintf(ua_sess->path, sizeof(ua_sess->path),
DEFAULT_UST_TRACE_UID_PATH,
- ua_sess->real_credentials.uid,
+ lttng_credentials_get_uid(&ua_sess->real_credentials),
app->bits_per_long);
break;
default:
app->uint64_t_alignment, app->long_alignment,
app->byte_order, app->version.major, app->version.minor,
reg_pid->root_shm_path, reg_pid->shm_path,
- ua_sess->effective_credentials.uid,
- ua_sess->effective_credentials.gid, ua_sess->tracing_id,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_sess->tracing_id,
app->uid);
if (ret < 0) {
/*
*/
static
int create_ust_app_channel_context(struct ust_app_channel *ua_chan,
- struct lttng_ust_context_attr *uctx,
+ struct lttng_ust_context_attr *uctx,
struct ust_app *app)
{
int ret = 0;
notification_ret = notification_thread_command_add_channel(
notification_thread_handle, session->name,
- ua_sess->effective_credentials.uid,
- ua_sess->effective_credentials.gid, ua_chan->name,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_chan->name,
ua_chan->key, LTTNG_DOMAIN_UST,
ua_chan->attr.subbuf_size * ua_chan->attr.num_subbuf);
if (notification_ret != LTTNG_OK) {
cmd_ret = notification_thread_command_add_channel(
notification_thread_handle, session->name,
- ua_sess->effective_credentials.uid,
- ua_sess->effective_credentials.gid, ua_chan->name,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_chan->name,
ua_chan->key, LTTNG_DOMAIN_UST,
ua_chan->attr.subbuf_size * ua_chan->attr.num_subbuf);
if (cmd_ret != LTTNG_OK) {
ret = ust_app_channel_allocate(ua_sess, uchan,
LTTNG_UST_CHAN_PER_CPU, usess,
&ua_chan);
- if (ret == 0) {
- ret = ust_app_channel_send(app, usess,
- ua_sess, ua_chan);
- } else {
- goto end;
+ if (ret < 0) {
+ goto error;
+ }
+
+ ret = ust_app_channel_send(app, usess,
+ ua_sess, ua_chan);
+ if (ret) {
+ goto error;
}
/* Add contexts. */
ret = create_ust_app_channel_context(ua_chan,
&uctx->ctx, app);
if (ret) {
- goto end;
+ goto error;
}
}
}
+
+error:
if (ret < 0) {
switch (ret) {
case -ENOTCONN:
break;
}
}
-end:
+
if (ret == 0 && _ua_chan) {
/*
* Only return the application's channel on success. Note
goto end;
}
+ if (ua_sess->enabled) {
+ pthread_mutex_unlock(&ua_sess->lock);
+ goto end;
+ }
+
/* Upon restart, we skip the setup, already done */
if (ua_sess->started) {
goto skip_setup;
/* Indicate that the session has been started once */
ua_sess->started = 1;
+ ua_sess->enabled = 1;
pthread_mutex_unlock(&ua_sess->lock);
}
health_code_update();
+ ua_sess->enabled = 0;
/* Quiescent wait after stopping trace */
pthread_mutex_lock(&app->sock_lock);
/*
* The caller must ensure that the application is compatible and is tracked
- * by the PID tracker.
+ * by the process attribute trackers.
*/
static
void ust_app_synchronize(struct ltt_ust_session *usess,
* allocated (if necessary) and sent to the application, and
* all enabled contexts will be added to the channel.
*/
- ret = find_or_create_ust_app_channel(usess, ua_sess,
+ ret = find_or_create_ust_app_channel(usess, ua_sess,
app, uchan, &ua_chan);
if (ret) {
/* Tracer is probably gone or ENOMEM. */
if (!app->compatible) {
return;
}
- if (trace_ust_id_tracker_lookup(LTTNG_TRACKER_VPID, usess, app->pid) &&
+ if (trace_ust_id_tracker_lookup(LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID,
+ usess, app->pid) &&
trace_ust_id_tracker_lookup(
- LTTNG_TRACKER_VUID, usess, app->uid) &&
+ LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID,
+ usess, app->uid) &&
trace_ust_id_tracker_lookup(
- LTTNG_TRACKER_VGID, usess, app->gid)) {
+ LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID,
+ usess, app->gid)) {
/*
* Synchronize the application's internal tracing configuration
* and start tracing.
status = LTTNG_ERR_INVALID;
goto error;
}
- /* Add the UST default trace dir to path. */
+ /* Add the UST default trace dir to path. */
cds_lfht_for_each_entry(reg->registry->channels->ht, &iter.iter,
reg_chan, node.node) {
status = consumer_snapshot_channel(socket,
status = LTTNG_ERR_INVALID;
goto error;
}
- cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter,
+ cds_lfht_for_each_entry(ua_sess->channels->ht, &chan_iter.iter,
ua_chan, node.node) {
status = consumer_snapshot_channel(socket,
ua_chan->key, output, 0,
- ua_sess->effective_credentials
- .uid,
- ua_sess->effective_credentials
- .gid,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
&trace_path[consumer_path_offset], wait,
nb_packets_per_stream);
switch (status) {
}
status = consumer_snapshot_channel(socket,
registry->metadata_key, output, 1,
- ua_sess->effective_credentials.uid,
- ua_sess->effective_credentials.gid,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
&trace_path[consumer_path_offset], wait, 0);
switch (status) {
case LTTNG_OK:
ua_chan, node.node) {
ret = consumer_rotate_channel(socket,
ua_chan->key,
- ua_sess->effective_credentials
- .uid,
- ua_sess->effective_credentials
- .gid,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
ua_sess->consumer,
/* is_metadata_channel */ false);
if (ret < 0) {
(void) push_metadata(registry, usess->consumer);
ret = consumer_rotate_channel(socket,
registry->metadata_key,
- ua_sess->effective_credentials.uid,
- ua_sess->effective_credentials.gid,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
ua_sess->consumer,
/* is_metadata_channel */ true);
if (ret < 0) {
rcu_read_unlock();
return cmd_ret;
}
+
+/*
+ * This function skips the metadata channel as the begin/end timestamps of a
+ * metadata packet are useless.
+ *
+ * Moreover, opening a packet after a "clear" will cause problems for live
+ * sessions as it will introduce padding that was not part of the first trace
+ * chunk. The relay daemon expects the content of the metadata stream of
+ * successive metadata trace chunks to be strict supersets of one another.
+ *
+ * For example, flushing a packet at the beginning of the metadata stream of
+ * a trace chunk resulting from a "clear" session command will cause the
+ * size of the metadata stream of the new trace chunk to not match the size of
+ * the metadata stream of the original chunk. This will confuse the relay
+ * daemon as the same "offset" in a metadata stream will no longer point
+ * to the same content.
+ */
+enum lttng_error_code ust_app_open_packets(struct ltt_session *session)
+{
+ enum lttng_error_code ret = LTTNG_OK;
+ struct lttng_ht_iter iter;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ assert(usess);
+
+ rcu_read_lock();
+
+ switch (usess->buffer_type) {
+ case LTTNG_BUFFER_PER_UID:
+ {
+ struct buffer_reg_uid *reg;
+
+ cds_list_for_each_entry (
+ reg, &usess->buffer_reg_uid_list, lnode) {
+ struct buffer_reg_channel *reg_chan;
+ struct consumer_socket *socket;
+
+ socket = consumer_find_socket_by_bitness(
+ reg->bits_per_long, usess->consumer);
+ if (!socket) {
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+
+ cds_lfht_for_each_entry(reg->registry->channels->ht,
+ &iter.iter, reg_chan, node.node) {
+ const int open_ret =
+ consumer_open_channel_packets(
+ socket,
+ reg_chan->consumer_key);
+
+ if (open_ret < 0) {
+ ret = LTTNG_ERR_UNK;
+ goto error;
+ }
+ }
+ }
+ break;
+ }
+ case LTTNG_BUFFER_PER_PID:
+ {
+ struct ust_app *app;
+
+ cds_lfht_for_each_entry (
+ ust_app_ht->ht, &iter.iter, app, pid_n.node) {
+ struct consumer_socket *socket;
+ struct lttng_ht_iter chan_iter;
+ struct ust_app_channel *ua_chan;
+ struct ust_app_session *ua_sess;
+ struct ust_registry_session *registry;
+
+ ua_sess = lookup_session_by_app(usess, app);
+ if (!ua_sess) {
+ /* Session not associated with this app. */
+ continue;
+ }
+
+ /* Get the right consumer socket for the application. */
+ socket = consumer_find_socket_by_bitness(
+ app->bits_per_long, usess->consumer);
+ if (!socket) {
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+
+ registry = get_session_registry(ua_sess);
+ if (!registry) {
+ DBG("Application session is being torn down. Skip application.");
+ continue;
+ }
+
+ cds_lfht_for_each_entry(ua_sess->channels->ht,
+ &chan_iter.iter, ua_chan, node.node) {
+ const int open_ret =
+ consumer_open_channel_packets(
+ socket,
+ ua_chan->key);
+
+ if (open_ret < 0) {
+ /*
+ * Per-PID buffer and application going
+ * away.
+ */
+ if (open_ret == -LTTNG_ERR_CHAN_NOT_FOUND) {
+ continue;
+ }
+
+ ret = LTTNG_ERR_UNK;
+ goto error;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ abort();
+ break;
+ }
+
+error:
+ rcu_read_unlock();
+ return ret;
+}