+ 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,
+ 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));
+ destruction_last_error = -ret;
+ }
+ if (reply_context) {
+ reply_context->implicit_rotation_on_destroy = true;
+ }
+ } else if (session->has_been_started && session->current_trace_chunk) {
+ /*
+ * The user has not triggered a session rotation. However, to
+ * ensure all data has been consumed, the session is rotated
+ * to a 'null' trace chunk before it is destroyed.
+ *
+ * This is a "quiet" rotation meaning that no notification is
+ * emitted and no renaming of the current trace chunk takes
+ * place.
+ */
+ ret = cmd_rotate_session(session, NULL, true,
+ LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION);
+ if (ret != LTTNG_OK) {
+ ERR("Failed to perform a quiet rotation as part of the destruction of session \"%s\": %s",
+ session->name, lttng_strerror(-ret));
+ destruction_last_error = -ret;
+ }
+ }
+
+ if (session->shm_path[0]) {
+ /*
+ * When a session is created with an explicit shm_path,
+ * the consumer daemon will create its shared memory files
+ * at that location and will *not* unlink them. This is normal
+ * as the intention of that feature is to make it possible
+ * to retrieve the content of those files should a crash occur.
+ *
+ * To ensure the content of those files can be used, the
+ * sessiond daemon will replicate the content of the metadata
+ * cache in a metadata file.
+ *
+ * On clean-up, it is expected that the consumer daemon will
+ * unlink the shared memory files and that the session daemon
+ * will unlink the metadata file. Then, the session's directory
+ * in the shm path can be removed.
+ *
+ * Unfortunately, a flaw in the design of the sessiond's and
+ * consumerd's tear down of channels makes it impossible to
+ * determine when the sessiond _and_ the consumerd have both
+ * destroyed their representation of a channel. For one, the
+ * unlinking, close, and rmdir happen in deferred 'call_rcu'
+ * callbacks in both daemons.
+ *
+ * However, it is also impossible for the sessiond to know when
+ * the consumer daemon is done destroying its channel(s) since
+ * it occurs as a reaction to the closing of the channel's file
+ * descriptor. There is no resulting communication initiated
+ * from the consumerd to the sessiond to confirm that the
+ * operation is completed (and was successful).
+ *
+ * Until this is all fixed, the session daemon checks for the
+ * removal of the session's shm path which makes it possible
+ * to safely advertise a session as having been destroyed.
+ *
+ * Prior to this fix, it was not possible to reliably save
+ * a session making use of the --shm-path option, destroy it,
+ * and load it again. This is because the creation of the
+ * session would fail upon seeing the session's shm path
+ * already in existence.
+ *
+ * Note that none of the error paths in the check for the
+ * directory's existence return an error. This is normal
+ * as there isn't much that can be done. The session will
+ * be destroyed properly, except that we can't offer the
+ * guarantee that the same session can be re-created.
+ */
+ current_completion_handler = &destroy_completion_handler.handler;
+ ret = lttng_strncpy(destroy_completion_handler.shm_path,
+ session->shm_path,
+ sizeof(destroy_completion_handler.shm_path));
+ assert(!ret);
+ }
+
+ /*
+ * The session is destroyed. However, note that the command context
+ * still holds a reference to the session, thus delaying its destruction
+ * _at least_ up to the point when that reference is released.
+ */
+ session_destroy(session);
+ if (reply_context) {
+ reply_context->destruction_status = destruction_last_error;
+ ret = session_add_destroy_notifier(session,
+ cmd_destroy_session_reply,
+ (void *) reply_context);
+ if (ret) {
+ ret = LTTNG_ERR_FATAL;
+ goto end;
+ } else {
+ *sock_fd = -1;
+ }
+ }
+ ret = LTTNG_OK;
+end:
+ return ret;
+}
+
+/*