/*
- * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
- * Copyright (C) 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
+ * 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.
*/
+#include "bin/lttng-sessiond/tracker.h"
+#include "lttng/lttng-error.h"
+#include "lttng/tracker.h"
#define _LGPL_SOURCE
#include <assert.h>
#include <inttypes.h>
/* Create socket for control stream. */
if (uri->stype == LTTNG_STREAM_CONTROL) {
+ uint64_t result_flags;
+
DBG3("Creating relayd stream socket from URI");
/* Check relayd version */
}
consumer->relay_major_version = rsock->major;
consumer->relay_minor_version = rsock->minor;
+ ret = relayd_get_configuration(rsock, 0,
+ &result_flags);
+ if (ret < 0) {
+ ERR("Unable to get relayd configuration");
+ status = LTTNG_ERR_RELAYD_CONNECT_FAIL;
+ goto close_sock;
+ }
+ if (result_flags & LTTCOMM_RELAYD_CONFIGURATION_FLAG_CLEAR_ALLOWED) {
+ consumer->relay_allows_clear = true;
+ }
} else if (uri->stype == LTTNG_STREAM_DATA) {
DBG3("Creating relayd data socket from URI");
} else {
DBG("Setting relayd for session %s", session->name);
+ rcu_read_lock();
if (session->current_trace_chunk) {
enum lttng_trace_chunk_status status = lttng_trace_chunk_get_id(
session->current_trace_chunk, ¤t_chunk_id.value);
}
}
- rcu_read_lock();
-
if (usess && usess->consumer && usess->consumer->type == CONSUMER_DST_NET
&& usess->consumer->enabled) {
/* For each consumer socket, send relayd sockets */
usess->consumer->relay_major_version;
session->consumer->relay_minor_version =
usess->consumer->relay_minor_version;
+ session->consumer->relay_allows_clear =
+ usess->consumer->relay_allows_clear;
}
if (ksess && ksess->consumer && ksess->consumer->type == CONSUMER_DST_NET
ksess->consumer->relay_major_version;
session->consumer->relay_minor_version =
ksess->consumer->relay_minor_version;
+ session->consumer->relay_allows_clear =
+ ksess->consumer->relay_allows_clear;
}
error:
/*
* Start a kernel session by opening all necessary streams.
*/
-static int start_kernel_session(struct ltt_kernel_session *ksess)
+int start_kernel_session(struct ltt_kernel_session *ksess)
{
int ret;
struct ltt_kernel_channel *kchan;
return ret;
}
-/*
- * Command LTTNG_DISABLE_CHANNEL processed by the client thread.
- */
-int cmd_disable_channel(struct ltt_session *session,
- enum lttng_domain_type domain, char *channel_name)
+int stop_kernel_session(struct ltt_kernel_session *ksess)
{
+ struct ltt_kernel_channel *kchan;
+ bool error_occurred = false;
int ret;
- struct ltt_ust_session *usess;
-
- usess = session->ust_session;
-
- rcu_read_lock();
-
- switch (domain) {
- case LTTNG_DOMAIN_KERNEL:
- {
- ret = channel_kernel_disable(session->kernel_session,
- channel_name);
- if (ret != LTTNG_OK) {
- goto error;
- }
- kernel_wait_quiescent();
- break;
+ if (!ksess || !ksess->active) {
+ return LTTNG_OK;
}
- case LTTNG_DOMAIN_UST:
- {
- struct ltt_ust_channel *uchan;
- struct lttng_ht *chan_ht;
-
- chan_ht = usess->domain_global.channels;
-
- uchan = trace_ust_find_channel_by_name(chan_ht, channel_name);
- if (uchan == NULL) {
- ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
- goto error;
- }
+ DBG("Stopping kernel tracing");
- ret = channel_ust_disable(usess, uchan);
- if (ret != LTTNG_OK) {
- goto error;
- }
- break;
- }
- default:
- ret = LTTNG_ERR_UNKNOWN_DOMAIN;
+ ret = kernel_stop_session(ksess);
+ if (ret < 0) {
+ ret = LTTNG_ERR_KERN_STOP_FAIL;
goto error;
}
- ret = LTTNG_OK;
-
-error:
- rcu_read_unlock();
- return ret;
-}
-
-/*
- * Command LTTNG_TRACK_PID processed by the client thread.
- *
- * Called with session lock held.
- */
-int cmd_track_pid(struct ltt_session *session, enum lttng_domain_type domain,
- int pid)
-{
- int ret;
-
- rcu_read_lock();
-
- switch (domain) {
- case LTTNG_DOMAIN_KERNEL:
- {
- struct ltt_kernel_session *ksess;
-
- ksess = session->kernel_session;
+ kernel_wait_quiescent();
- ret = kernel_track_pid(ksess, pid);
- if (ret != LTTNG_OK) {
- goto error;
+ /* Flush metadata after stopping (if exists) */
+ if (ksess->metadata_stream_fd >= 0) {
+ ret = kernel_metadata_flush_buffer(ksess->metadata_stream_fd);
+ if (ret < 0) {
+ ERR("Kernel metadata flush failed");
+ error_occurred = true;
}
-
- kernel_wait_quiescent();
- break;
}
- case LTTNG_DOMAIN_UST:
- {
- struct ltt_ust_session *usess;
- usess = session->ust_session;
-
- ret = trace_ust_track_pid(usess, pid);
- if (ret != LTTNG_OK) {
- goto error;
+ /* Flush all buffers after stopping */
+ cds_list_for_each_entry(kchan, &ksess->channel_list.head, list) {
+ ret = kernel_flush_buffer(kchan);
+ if (ret < 0) {
+ ERR("Kernel flush buffer error");
+ error_occurred = true;
}
- break;
- }
- default:
- ret = LTTNG_ERR_UNKNOWN_DOMAIN;
- goto error;
}
- ret = LTTNG_OK;
-
+ ksess->active = 0;
+ if (error_occurred) {
+ ret = LTTNG_ERR_UNK;
+ } else {
+ ret = LTTNG_OK;
+ }
error:
- rcu_read_unlock();
return ret;
}
/*
- * Command LTTNG_UNTRACK_PID processed by the client thread.
- *
- * Called with session lock held.
+ * Command LTTNG_DISABLE_CHANNEL processed by the client thread.
*/
-int cmd_untrack_pid(struct ltt_session *session, enum lttng_domain_type domain,
- int pid)
+int cmd_disable_channel(struct ltt_session *session,
+ enum lttng_domain_type domain, char *channel_name)
{
int ret;
+ struct ltt_ust_session *usess;
+
+ usess = session->ust_session;
rcu_read_lock();
switch (domain) {
case LTTNG_DOMAIN_KERNEL:
{
- struct ltt_kernel_session *ksess;
-
- ksess = session->kernel_session;
-
- ret = kernel_untrack_pid(ksess, pid);
+ ret = channel_kernel_disable(session->kernel_session,
+ channel_name);
if (ret != LTTNG_OK) {
goto error;
}
}
case LTTNG_DOMAIN_UST:
{
- struct ltt_ust_session *usess;
+ struct ltt_ust_channel *uchan;
+ struct lttng_ht *chan_ht;
- usess = session->ust_session;
+ chan_ht = usess->domain_global.channels;
+
+ uchan = trace_ust_find_channel_by_name(chan_ht, channel_name);
+ if (uchan == NULL) {
+ ret = LTTNG_ERR_UST_CHAN_NOT_FOUND;
+ goto error;
+ }
- ret = trace_ust_untrack_pid(usess, pid);
+ ret = channel_ust_disable(usess, uchan);
if (ret != LTTNG_OK) {
goto error;
}
return ret;
}
+enum lttng_error_code cmd_process_attr_tracker_get_tracking_policy(
+ struct ltt_session *session,
+ enum lttng_domain_type domain,
+ enum lttng_process_attr process_attr,
+ enum lttng_tracking_policy *policy)
+{
+ enum lttng_error_code ret_code = LTTNG_OK;
+ const struct process_attr_tracker *tracker;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ if (!session->kernel_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ tracker = kernel_get_process_attr_tracker(
+ session->kernel_session, process_attr);
+ break;
+ case LTTNG_DOMAIN_UST:
+ if (!session->ust_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ tracker = trace_ust_get_process_attr_tracker(
+ session->ust_session, process_attr);
+ break;
+ default:
+ ret_code = LTTNG_ERR_UNSUPPORTED_DOMAIN;
+ goto end;
+ }
+ if (tracker) {
+ *policy = process_attr_tracker_get_tracking_policy(tracker);
+ } else {
+ ret_code = LTTNG_ERR_INVALID;
+ }
+end:
+ return ret_code;
+}
+
+enum lttng_error_code cmd_process_attr_tracker_set_tracking_policy(
+ struct ltt_session *session,
+ enum lttng_domain_type domain,
+ enum lttng_process_attr process_attr,
+ enum lttng_tracking_policy policy)
+{
+ enum lttng_error_code ret_code = LTTNG_OK;
+
+ switch (policy) {
+ case LTTNG_TRACKING_POLICY_INCLUDE_SET:
+ case LTTNG_TRACKING_POLICY_EXCLUDE_ALL:
+ case LTTNG_TRACKING_POLICY_INCLUDE_ALL:
+ break;
+ default:
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ if (!session->kernel_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ ret_code = kernel_process_attr_tracker_set_tracking_policy(
+ session->kernel_session, process_attr, policy);
+ break;
+ case LTTNG_DOMAIN_UST:
+ if (!session->ust_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ ret_code = trace_ust_process_attr_tracker_set_tracking_policy(
+ session->ust_session, process_attr, policy);
+ break;
+ default:
+ ret_code = LTTNG_ERR_UNSUPPORTED_DOMAIN;
+ break;
+ }
+end:
+ return ret_code;
+}
+
+enum lttng_error_code cmd_process_attr_tracker_inclusion_set_add_value(
+ struct ltt_session *session,
+ enum lttng_domain_type domain,
+ enum lttng_process_attr process_attr,
+ const struct process_attr_value *value)
+{
+ enum lttng_error_code ret_code = LTTNG_OK;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ if (!session->kernel_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ ret_code = kernel_process_attr_tracker_inclusion_set_add_value(
+ session->kernel_session, process_attr, value);
+ break;
+ case LTTNG_DOMAIN_UST:
+ if (!session->ust_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ ret_code = trace_ust_process_attr_tracker_inclusion_set_add_value(
+ session->ust_session, process_attr, value);
+ break;
+ default:
+ ret_code = LTTNG_ERR_UNSUPPORTED_DOMAIN;
+ break;
+ }
+end:
+ return ret_code;
+}
+
+enum lttng_error_code cmd_process_attr_tracker_inclusion_set_remove_value(
+ struct ltt_session *session,
+ enum lttng_domain_type domain,
+ enum lttng_process_attr process_attr,
+ const struct process_attr_value *value)
+{
+ enum lttng_error_code ret_code = LTTNG_OK;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ if (!session->kernel_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ ret_code = kernel_process_attr_tracker_inclusion_set_remove_value(
+ session->kernel_session, process_attr, value);
+ break;
+ case LTTNG_DOMAIN_UST:
+ if (!session->ust_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ ret_code = trace_ust_process_attr_tracker_inclusion_set_remove_value(
+ session->ust_session, process_attr, value);
+ break;
+ default:
+ ret_code = LTTNG_ERR_UNSUPPORTED_DOMAIN;
+ break;
+ }
+end:
+ return ret_code;
+}
+
+enum lttng_error_code cmd_process_attr_tracker_get_inclusion_set(
+ struct ltt_session *session,
+ enum lttng_domain_type domain,
+ enum lttng_process_attr process_attr,
+ struct lttng_process_attr_values **values)
+{
+ enum lttng_error_code ret_code = LTTNG_OK;
+ const struct process_attr_tracker *tracker;
+ enum process_attr_tracker_status status;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ if (!session->kernel_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ tracker = kernel_get_process_attr_tracker(
+ session->kernel_session, process_attr);
+ break;
+ case LTTNG_DOMAIN_UST:
+ if (!session->ust_session) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+ tracker = trace_ust_get_process_attr_tracker(
+ session->ust_session, process_attr);
+ break;
+ default:
+ ret_code = LTTNG_ERR_UNSUPPORTED_DOMAIN;
+ goto end;
+ }
+
+ if (!tracker) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ status = process_attr_tracker_get_inclusion_set(tracker, values);
+ switch (status) {
+ case PROCESS_ATTR_TRACKER_STATUS_OK:
+ ret_code = LTTNG_OK;
+ break;
+ case PROCESS_ATTR_TRACKER_STATUS_INVALID_TRACKING_POLICY:
+ ret_code = LTTNG_ERR_PROCESS_ATTR_TRACKER_INVALID_TRACKING_POLICY;
+ break;
+ case PROCESS_ATTR_TRACKER_STATUS_ERROR:
+ ret_code = LTTNG_ERR_NOMEM;
+ break;
+ default:
+ ret_code = LTTNG_ERR_UNK;
+ break;
+ }
+
+end:
+ return ret_code;
+}
+
/*
* Command LTTNG_DISABLE_EVENT processed by the client thread.
*/
return syscall_table_list(events);
}
-/*
- * Command LTTNG_LIST_TRACKER_PIDS processed by the client thread.
- *
- * Called with session lock held.
- */
-ssize_t cmd_list_tracker_pids(struct ltt_session *session,
- enum lttng_domain_type domain, int32_t **pids)
-{
- int ret;
- ssize_t nr_pids = 0;
-
- switch (domain) {
- case LTTNG_DOMAIN_KERNEL:
- {
- struct ltt_kernel_session *ksess;
-
- ksess = session->kernel_session;
- nr_pids = kernel_list_tracker_pids(ksess, pids);
- if (nr_pids < 0) {
- ret = LTTNG_ERR_KERN_LIST_FAIL;
- goto error;
- }
- break;
- }
- case LTTNG_DOMAIN_UST:
- {
- struct ltt_ust_session *usess;
-
- usess = session->ust_session;
- nr_pids = trace_ust_list_tracker_pids(usess, pids);
- if (nr_pids < 0) {
- ret = LTTNG_ERR_UST_LIST_FAIL;
- goto error;
- }
- break;
- }
- case LTTNG_DOMAIN_LOG4J:
- case LTTNG_DOMAIN_JUL:
- case LTTNG_DOMAIN_PYTHON:
- default:
- ret = LTTNG_ERR_UND;
- goto error;
- }
-
- return nr_pids;
-
-error:
- /* Return negative value to differentiate return code */
- return -ret;
-}
-
/*
* Command LTTNG_START_TRACE processed by the client thread.
*
unsigned long nb_chan = 0;
struct ltt_kernel_session *ksession;
struct ltt_ust_session *usess;
+ const bool session_rotated_after_last_stop =
+ session->rotated_after_last_stop;
+ const bool session_cleared_after_last_stop =
+ session->cleared_after_last_stop;
assert(session);
/* Is the session already started? */
if (session->active) {
ret = LTTNG_ERR_TRACE_ALREADY_STARTED;
+ /* Perform nothing */
+ goto end;
+ }
+
+ if (session->rotation_state == LTTNG_ROTATION_STATE_ONGOING &&
+ !session->current_trace_chunk) {
+ /*
+ * A rotation was launched while the session was stopped and
+ * it has not been completed yet. It is not possible to start
+ * the session since starting the session here would require a
+ * rotation from "NULL" to a new trace chunk. That rotation
+ * would overlap with the ongoing rotation, which is not
+ * supported.
+ */
+ WARN("Refusing to start session \"%s\" as a rotation launched after the last \"stop\" is still ongoing",
+ session->name);
+ ret = LTTNG_ERR_ROTATION_PENDING;
goto error;
}
goto error;
}
+ session->active = 1;
+ session->rotated_after_last_stop = false;
+ session->cleared_after_last_stop = false;
if (session->output_traces && !session->current_trace_chunk) {
- struct lttng_trace_chunk *trace_chunk;
+ if (!session->has_been_started) {
+ struct lttng_trace_chunk *trace_chunk;
- trace_chunk = session_create_new_trace_chunk(
- session, NULL, NULL, NULL);
- if (!trace_chunk) {
- ret = LTTNG_ERR_CREATE_DIR_FAIL;
- goto error;
- }
- assert(!session->current_trace_chunk);
- ret = session_set_trace_chunk(session, trace_chunk, NULL);
- lttng_trace_chunk_put(trace_chunk);
- if (ret) {
- ret = LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER;
- goto error;
+ DBG("Creating initial trace chunk of session \"%s\"",
+ session->name);
+ trace_chunk = session_create_new_trace_chunk(
+ session, NULL, NULL, NULL);
+ if (!trace_chunk) {
+ ret = LTTNG_ERR_CREATE_DIR_FAIL;
+ goto error;
+ }
+ assert(!session->current_trace_chunk);
+ ret = session_set_trace_chunk(session, trace_chunk,
+ NULL);
+ lttng_trace_chunk_put(trace_chunk);
+ if (ret) {
+ ret = LTTNG_ERR_CREATE_TRACE_CHUNK_FAIL_CONSUMER;
+ goto error;
+ }
+ } else {
+ DBG("Rotating session \"%s\" from its current \"NULL\" trace chunk to a new chunk",
+ session->name);
+ /*
+ * Rotate existing streams into the new chunk.
+ * This is a "quiet" rotation has no client has
+ * explicitly requested this operation.
+ *
+ * There is also no need to wait for the rotation
+ * to complete as it will happen immediately. No data
+ * was produced as the session was stopped, so the
+ * rotation should happen on reception of the command.
+ */
+ ret = cmd_rotate_session(session, NULL, true,
+ LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION);
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
}
}
}
}
- /* Flag this after a successful start. */
- session->has_been_started = 1;
- session->active = 1;
-
/*
* Clear the flag that indicates that a rotation was done while the
* session was stopped.
ret = LTTNG_OK;
error:
+ if (ret == LTTNG_OK) {
+ /* Flag this after a successful start. */
+ session->has_been_started |= 1;
+ } else {
+ session->active = 0;
+ /* Restore initial state on error. */
+ session->rotated_after_last_stop =
+ session_rotated_after_last_stop;
+ session->cleared_after_last_stop =
+ session_cleared_after_last_stop;
+ }
+end:
return ret;
}
int cmd_stop_trace(struct ltt_session *session)
{
int ret;
- struct ltt_kernel_channel *kchan;
struct ltt_kernel_session *ksession;
struct ltt_ust_session *usess;
- bool error_occurred = false;
assert(session);
- DBG("Begin stop session %s (id %" PRIu64 ")", session->name, session->id);
+ DBG("Begin stop session \"%s\" (id %" PRIu64 ")", session->name, session->id);
/* Short cut */
ksession = session->kernel_session;
usess = session->ust_session;
goto error;
}
- /* Kernel tracer */
- if (ksession && ksession->active) {
- DBG("Stop kernel tracing");
-
- ret = kernel_stop_session(ksession);
- if (ret < 0) {
- ret = LTTNG_ERR_KERN_STOP_FAIL;
- goto error;
- }
-
- kernel_wait_quiescent();
-
- /* Flush metadata after stopping (if exists) */
- if (ksession->metadata_stream_fd >= 0) {
- ret = kernel_metadata_flush_buffer(ksession->metadata_stream_fd);
- if (ret < 0) {
- ERR("Kernel metadata flush failed");
- error_occurred = true;
- }
- }
-
- /* Flush all buffers after stopping */
- cds_list_for_each_entry(kchan, &ksession->channel_list.head, list) {
- ret = kernel_flush_buffer(kchan);
- if (ret < 0) {
- ERR("Kernel flush buffer error");
- error_occurred = true;
- }
- }
-
- ksession->active = 0;
- DBG("Kernel session stopped %s (id %" PRIu64 ")", session->name,
- session->id);
+ ret = stop_kernel_session(ksession);
+ if (ret != LTTNG_OK) {
+ goto error;
}
if (usess && usess->active) {
}
}
+ DBG("Completed stop session \"%s\" (id %" PRIu64 ")", session->name,
+ session->id);
/* Flag inactive after a successful stop. */
session->active = 0;
- ret = !error_occurred ? LTTNG_OK : LTTNG_ERR_UNK;
+ ret = LTTNG_OK;
error:
return ret;
}
+/*
+ * Set the base_path of the session only if subdir of a control uris is set.
+ * Return LTTNG_OK on success, otherwise LTTNG_ERR_*.
+ */
+static int set_session_base_path_from_uris(struct ltt_session *session,
+ size_t nb_uri,
+ struct lttng_uri *uris)
+{
+ int ret;
+ size_t i;
+
+ for (i = 0; i < nb_uri; i++) {
+ if (uris[i].stype != LTTNG_STREAM_CONTROL ||
+ uris[i].subdir[0] == '\0') {
+ /* Not interested in these URIs */
+ continue;
+ }
+
+ if (session->base_path != NULL) {
+ free(session->base_path);
+ session->base_path = NULL;
+ }
+
+ /* Set session base_path */
+ session->base_path = strdup(uris[i].subdir);
+ if (!session->base_path) {
+ PERROR("Failed to copy base path \"%s\" to session \"%s\"",
+ uris[i].subdir, session->name);
+ ret = LTTNG_ERR_NOMEM;
+ goto error;
+ }
+ DBG2("Setting base path \"%s\" for session \"%s\"",
+ session->base_path, session->name);
+ }
+ ret = LTTNG_OK;
+error:
+ return ret;
+}
+
/*
* Command LTTNG_SET_CONSUMER_URI processed by the client thread.
*/
goto error;
}
+ /*
+ * Set the session base path if any. This is done inside
+ * cmd_set_consumer_uri to preserve backward compatibility of the
+ * previous session creation api vs the session descriptor api.
+ */
+ ret = set_session_base_path_from_uris(session, nb_uri, uris);
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
+
/* Set the "global" consumer URIs */
for (i = 0; i < nb_uri; i++) {
- ret = add_uri_to_consumer(session,
- session->consumer,
- &uris[i], LTTNG_DOMAIN_NONE);
+ ret = add_uri_to_consumer(session, session->consumer, &uris[i],
+ LTTNG_DOMAIN_NONE);
if (ret != LTTNG_OK) {
goto error;
}
const char *session_name;
struct ltt_session *new_session = NULL;
enum lttng_session_descriptor_status descriptor_status;
- const char *base_path;
session_lock_list();
if (home_path) {
ret_code = LTTNG_ERR_INVALID;
goto end;
}
- ret = lttng_session_descriptor_get_base_path(descriptor, &base_path);
- if (ret) {
- ret_code = LTTNG_ERR_INVALID;
- goto end;
- }
+
ret_code = session_create(session_name, creds->uid, creds->gid,
- base_path, &new_session);
+ &new_session);
if (ret_code != LTTNG_OK) {
goto end;
}
session->rotate_size = 0;
}
- if (session->most_recent_chunk_id.is_set &&
- session->most_recent_chunk_id.value != 0 &&
- session->current_trace_chunk && session->output_traces) {
+ if (session->rotated && session->current_trace_chunk && session->output_traces) {
/*
* Perform a last rotation on destruction if rotations have
* occurred during the session's lifetime.
*/
- ret = cmd_rotate_session(session, NULL, false);
+ ret = cmd_rotate_session(session, NULL, false,
+ LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED);
if (ret != LTTNG_OK) {
ERR("Failed to perform an implicit rotation as part of the destruction of session \"%s\": %s",
session->name, lttng_strerror(-ret));
* emitted and no renaming of the current trace chunk takes
* place.
*/
- ret = cmd_rotate_session(session, NULL, true);
- if (ret != LTTNG_OK) {
+ ret = cmd_rotate_session(session, NULL, true,
+ LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION);
+ /*
+ * Rotation operations may not be supported by the kernel
+ * tracer. Hence, do not consider this implicit rotation as
+ * a session destruction error. The library has already stopped
+ * the session and waited for pending data; there is nothing
+ * left to do but complete the destruction of the session.
+ */
+ if (ret != LTTNG_OK &&
+ ret != -LTTNG_ERR_ROTATION_NOT_AVAILABLE_KERNEL) {
ERR("Failed to perform a quiet rotation as part of the destruction of session \"%s\": %s",
- session->name, lttng_strerror(-ret));
+ session->name, lttng_strerror(ret));
destruction_last_error = -ret;
}
}
}
cur_nb_packets++;
}
- if (!cur_nb_packets) {
+ if (!cur_nb_packets && size_left != max_size) {
/* Not enough room to grab one packet of each stream, error. */
return -1;
}
snapshot_output->max_size);
if (nb_packets_per_stream < 0) {
ret_code = LTTNG_ERR_MAX_SIZE_INVALID;
- goto error;
+ goto error_close_trace_chunk;
}
if (session->kernel_session) {
snapshot_kernel_consumer_output, session,
wait, nb_packets_per_stream);
if (ret_code != LTTNG_OK) {
- goto error;
+ goto error_close_trace_chunk;
}
}
snapshot_ust_consumer_output, session,
wait, nb_packets_per_stream);
if (ret_code != LTTNG_OK) {
- goto error;
+ goto error_close_trace_chunk;
}
}
- if (session_close_trace_chunk(
- session, session->current_trace_chunk, NULL, NULL)) {
+error_close_trace_chunk:
+ if (session_set_trace_chunk(session, NULL, &snapshot_trace_chunk)) {
+ ERR("Failed to release the current trace chunk of session \"%s\"",
+ session->name);
+ ret_code = LTTNG_ERR_UNK;
+ }
+
+ if (session_close_trace_chunk(session, snapshot_trace_chunk,
+ LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION, NULL)) {
/*
* Don't goto end; make sure the chunk is closed for the session
* to allow future snapshots.
session->name);
ret_code = LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER;
}
- if (session_set_trace_chunk(session, NULL, NULL)) {
- ERR("Failed to release the current trace chunk of session \"%s\"",
- session->name);
- ret_code = LTTNG_ERR_UNK;
- }
error:
if (original_ust_consumer_output) {
session->ust_session->consumer = original_ust_consumer_output;
*/
int cmd_rotate_session(struct ltt_session *session,
struct lttng_rotate_session_return *rotate_return,
- bool quiet_rotation)
+ bool quiet_rotation,
+ enum lttng_trace_chunk_command_type command)
{
int ret;
uint64_t ongoing_rotation_chunk_id;
goto end;
}
+ /* Unsupported feature in lttng-modules before 2.8 (lack of sequence number). */
+ if (session->kernel_session && !kernel_supports_ring_buffer_packet_sequence_number()) {
+ cmd_ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE_KERNEL;
+ goto end;
+ }
+
if (session->rotation_state == LTTNG_ROTATION_STATE_ONGOING) {
DBG("Refusing to launch a rotation; a rotation is already in progress for session %s",
session->name);
goto end;
}
- session->rotation_state = LTTNG_ROTATION_STATE_ONGOING;
+ /*
+ * After a stop followed by a clear, disallow following rotations a they would
+ * generate empty chunks.
+ */
+ if (session->cleared_after_last_stop) {
+ DBG("Session \"%s\" was already cleared after stop, refusing rotation",
+ session->name);
+ cmd_ret = LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR;
+ goto end;
+ }
if (session->active) {
new_trace_chunk = session_create_new_trace_chunk(session, NULL,
goto error;
}
- assert(chunk_being_archived);
- chunk_status = lttng_trace_chunk_get_id(chunk_being_archived,
- &ongoing_rotation_chunk_id);
- assert(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK);
-
if (session->kernel_session) {
cmd_ret = kernel_rotate_session(session);
if (cmd_ret != LTTNG_OK) {
}
}
+ if (!session->active) {
+ session->rotated_after_last_stop = true;
+ }
+
+ if (!chunk_being_archived) {
+ DBG("Rotating session \"%s\" from a \"NULL\" trace chunk to a new trace chunk, skipping completion check",
+ session->name);
+ if (failed_to_rotate) {
+ cmd_ret = rotation_fail_code;
+ goto error;
+ }
+ cmd_ret = LTTNG_OK;
+ goto end;
+ }
+
+ session->rotation_state = LTTNG_ROTATION_STATE_ONGOING;
+ chunk_status = lttng_trace_chunk_get_id(chunk_being_archived,
+ &ongoing_rotation_chunk_id);
+ assert(chunk_status == LTTNG_TRACE_CHUNK_STATUS_OK);
+
ret = session_close_trace_chunk(session, chunk_being_archived,
- quiet_rotation ?
- NULL :
- &((enum lttng_trace_chunk_command_type){
- LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED}),
- session->last_chunk_path);
+ command, session->last_chunk_path);
if (ret) {
cmd_ret = LTTNG_ERR_CLOSE_TRACE_CHUNK_FAIL_CONSUMER;
goto error;
goto error;
}
- if (!session->active) {
- session->rotated_after_last_stop = true;
- }
-
if (rotate_return) {
rotate_return->rotation_id = ongoing_rotation_chunk_id;
}