* Only used by _owner_ mode chunks.
*/
struct lttng_dynamic_pointer_array top_level_directories;
+ /*
+ * All files contained within the trace chunk.
+ * Array of paths (char *).
+ */
+ struct lttng_dynamic_pointer_array files;
/* Is contained within an lttng_trace_chunk_registry_element? */
bool in_registry_element;
bool name_overridden;
LTTNG_OPTIONAL(time_t) timestamp_creation;
LTTNG_OPTIONAL(time_t) timestamp_close;
LTTNG_OPTIONAL(struct chunk_credentials) credentials;
- LTTNG_OPTIONAL(struct lttng_directory_handle) session_output_directory;
- LTTNG_OPTIONAL(struct lttng_directory_handle) chunk_directory;
+ struct lttng_directory_handle *session_output_directory;
+ struct lttng_directory_handle *chunk_directory;
LTTNG_OPTIONAL(enum lttng_trace_chunk_command_type) close_command;
};
char *close_command_names[] = {
[LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED] =
"move to completed chunk folder",
+ [LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION] =
+ "no operation",
+ [LTTNG_TRACE_CHUNK_COMMAND_TYPE_DELETE] =
+ "delete",
};
static const
urcu_ref_init(&chunk->ref);
pthread_mutex_init(&chunk->lock, NULL);
lttng_dynamic_pointer_array_init(&chunk->top_level_directories, free);
+ lttng_dynamic_pointer_array_init(&chunk->files, free);
}
static
void lttng_trace_chunk_fini(struct lttng_trace_chunk *chunk)
{
- if (chunk->session_output_directory.is_set) {
- lttng_directory_handle_fini(
- &chunk->session_output_directory.value);
+ if (chunk->session_output_directory) {
+ lttng_directory_handle_put(
+ chunk->session_output_directory);
+ chunk->session_output_directory = NULL;
}
- if (chunk->chunk_directory.is_set) {
- lttng_directory_handle_fini(&chunk->chunk_directory.value);
+ if (chunk->chunk_directory) {
+ lttng_directory_handle_put(chunk->chunk_directory);
+ chunk->chunk_directory = NULL;
}
free(chunk->name);
chunk->name = NULL;
lttng_dynamic_pointer_array_reset(&chunk->top_level_directories);
+ lttng_dynamic_pointer_array_reset(&chunk->files);
pthread_mutex_destroy(&chunk->lock);
}
new_chunk->timestamp_creation = source_chunk->timestamp_creation;
new_chunk->timestamp_close = source_chunk->timestamp_close;
new_chunk->credentials = source_chunk->credentials;
- if (source_chunk->session_output_directory.is_set) {
- if (lttng_directory_handle_copy(
- &source_chunk->session_output_directory.value,
- &new_chunk->session_output_directory.value)) {
- goto error_unlock;
- } else {
- new_chunk->session_output_directory.is_set = true;
- }
+ if (source_chunk->session_output_directory) {
+ const bool reference_acquired = lttng_directory_handle_get(
+ source_chunk->session_output_directory);
+
+ assert(reference_acquired);
+ new_chunk->session_output_directory =
+ source_chunk->session_output_directory;
}
- if (source_chunk->chunk_directory.is_set) {
- if (lttng_directory_handle_copy(
- &source_chunk->chunk_directory.value,
- &new_chunk->chunk_directory.value)) {
- goto error_unlock;
- } else {
- new_chunk->chunk_directory.is_set = true;
- }
+ if (source_chunk->chunk_directory) {
+ const bool reference_acquired = lttng_directory_handle_get(
+ source_chunk->chunk_directory);
+
+ assert(reference_acquired);
+ new_chunk->chunk_directory = source_chunk->chunk_directory;
}
new_chunk->close_command = source_chunk->close_command;
pthread_mutex_unlock(&source_chunk->lock);
return status;
}
+LTTNG_HIDDEN
+bool lttng_trace_chunk_get_name_overridden(struct lttng_trace_chunk *chunk)
+{
+ bool name_overridden;
+
+ pthread_mutex_lock(&chunk->lock);
+ name_overridden = chunk->name_overridden;
+ pthread_mutex_unlock(&chunk->lock);
+ return name_overridden;
+}
+
static
bool is_valid_chunk_name(const char *name)
{
{
int ret;
enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
- struct lttng_directory_handle chunk_directory_handle;
+ struct lttng_directory_handle *chunk_directory_handle = NULL;
+ bool reference_acquired;
pthread_mutex_lock(&chunk->lock);
if (chunk->mode.is_set) {
goto end;
}
}
- ret = lttng_directory_handle_init_from_handle(&chunk_directory_handle,
+ chunk_directory_handle = lttng_directory_handle_create_from_handle(
chunk->name,
session_output_directory);
- if (ret) {
+ if (!chunk_directory_handle) {
/* The function already logs on all error paths. */
status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
goto end;
}
- LTTNG_OPTIONAL_SET(&chunk->session_output_directory,
- lttng_directory_handle_move(session_output_directory));
- LTTNG_OPTIONAL_SET(&chunk->chunk_directory,
- lttng_directory_handle_move(&chunk_directory_handle));
+ chunk->chunk_directory = chunk_directory_handle;
+ chunk_directory_handle = NULL;
+ reference_acquired = lttng_directory_handle_get(
+ session_output_directory);
+ assert(reference_acquired);
+ chunk->session_output_directory = session_output_directory;
LTTNG_OPTIONAL_SET(&chunk->mode, TRACE_CHUNK_MODE_OWNER);
end:
pthread_mutex_unlock(&chunk->lock);
struct lttng_directory_handle *chunk_directory)
{
enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+ bool reference_acquired;
pthread_mutex_lock(&chunk->lock);
if (chunk->mode.is_set) {
status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
goto end;
}
- LTTNG_OPTIONAL_SET(&chunk->chunk_directory,
- lttng_directory_handle_move(chunk_directory));
+ reference_acquired = lttng_directory_handle_get(chunk_directory);
+ assert(reference_acquired);
+ chunk->chunk_directory = chunk_directory;
LTTNG_OPTIONAL_SET(&chunk->mode, TRACE_CHUNK_MODE_USER);
end:
pthread_mutex_unlock(&chunk->lock);
}
LTTNG_HIDDEN
-enum lttng_trace_chunk_status lttng_trace_chunk_get_chunk_directory_handle(
+enum lttng_trace_chunk_status lttng_trace_chunk_borrow_chunk_directory_handle(
struct lttng_trace_chunk *chunk,
const struct lttng_directory_handle **handle)
{
enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
pthread_mutex_lock(&chunk->lock);
- if (!chunk->chunk_directory.is_set) {
+ if (!chunk->chunk_directory) {
status = LTTNG_TRACE_CHUNK_STATUS_NONE;
goto end;
}
- *handle = &chunk->chunk_directory.value;
+ *handle = chunk->chunk_directory;
end:
pthread_mutex_unlock(&chunk->lock);
return status;
status = LTTNG_TRACE_CHUNK_STATUS_INVALID_OPERATION;
goto end;
}
- if (!chunk->chunk_directory.is_set) {
+ if (!chunk->chunk_directory) {
ERR("Attempted to create trace chunk subdirectory \"%s\" before setting the chunk output directory",
path);
status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
goto end;
}
ret = lttng_directory_handle_create_subdirectory_recursive_as_user(
- &chunk->chunk_directory.value, path,
+ chunk->chunk_directory, path,
DIR_CREATION_MODE,
chunk->credentials.value.use_current_user ?
NULL : &chunk->credentials.value.user);
return status;
}
+/*
+ * TODO: Implement O(1) lookup.
+ */
+static
+bool lttng_trace_chunk_find_file(struct lttng_trace_chunk *chunk,
+ const char *path, size_t *index)
+{
+ size_t i, count;
+
+ count = lttng_dynamic_pointer_array_get_count(&chunk->files);
+ for (i = 0; i < count; i++) {
+ const char *iter_path =
+ lttng_dynamic_pointer_array_get_pointer(
+ &chunk->files, i);
+ if (!strcmp(iter_path, path)) {
+ if (index) {
+ *index = i;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+static
+enum lttng_trace_chunk_status lttng_trace_chunk_add_file(
+ struct lttng_trace_chunk *chunk,
+ const char *path)
+{
+ char *copy;
+ int ret;
+ enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+
+ if (lttng_trace_chunk_find_file(chunk, path, NULL)) {
+ return LTTNG_TRACE_CHUNK_STATUS_OK;
+ }
+ DBG("Adding new file \"%s\" to trace chunk \"%s\"",
+ path, chunk->name ? : "(unnamed)");
+ copy = strdup(path);
+ if (!copy) {
+ PERROR("Failed to copy path");
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+ ret = lttng_dynamic_pointer_array_add_pointer(
+ &chunk->files, copy);
+ if (ret) {
+ ERR("Allocation failure while adding file to a trace chunk");
+ free(copy);
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+end:
+ return status;
+}
+
+static
+void lttng_trace_chunk_remove_file(
+ struct lttng_trace_chunk *chunk,
+ const char *path)
+{
+ size_t index;
+ bool found;
+ int ret;
+
+ found = lttng_trace_chunk_find_file(chunk, path, &index);
+ if (!found) {
+ return;
+ }
+ ret = lttng_dynamic_pointer_array_remove_pointer(
+ &chunk->files, index);
+ assert(!ret);
+}
+
LTTNG_HIDDEN
enum lttng_trace_chunk_status lttng_trace_chunk_open_file(
struct lttng_trace_chunk *chunk, const char *file_path,
- int flags, mode_t mode, int *out_fd)
+ int flags, mode_t mode, int *out_fd, bool expect_no_file)
{
int ret;
enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
goto end;
}
- if (!chunk->chunk_directory.is_set) {
+ if (!chunk->chunk_directory) {
ERR("Attempted to open trace chunk file \"%s\" before setting the chunk output directory",
file_path);
status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
goto end;
}
+ status = lttng_trace_chunk_add_file(chunk, file_path);
+ if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ goto end;
+ }
ret = lttng_directory_handle_open_file_as_user(
- &chunk->chunk_directory.value, file_path, flags, mode,
+ chunk->chunk_directory, file_path, flags, mode,
chunk->credentials.value.use_current_user ?
NULL : &chunk->credentials.value.user);
if (ret < 0) {
- PERROR("Failed to open file relative to trace chunk file_path = \"%s\", flags = %d, mode = %d",
+ if (errno == ENOENT && expect_no_file) {
+ status = LTTNG_TRACE_CHUNK_STATUS_NO_FILE;
+ } else {
+ PERROR("Failed to open file relative to trace chunk file_path = \"%s\", flags = %d, mode = %d",
file_path, flags, (int) mode);
- status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ }
+ lttng_trace_chunk_remove_file(chunk, file_path);
goto end;
}
*out_fd = ret;
status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
goto end;
}
- if (!chunk->chunk_directory.is_set) {
+ if (!chunk->chunk_directory) {
ERR("Attempted to unlink trace chunk file \"%s\" before setting the chunk output directory",
file_path);
status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
goto end;
}
ret = lttng_directory_handle_unlink_file_as_user(
- &chunk->chunk_directory.value, file_path,
+ chunk->chunk_directory, file_path,
chunk->credentials.value.use_current_user ?
NULL : &chunk->credentials.value.user);
if (ret < 0) {
status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
goto end;
}
+ lttng_trace_chunk_remove_file(chunk, file_path);
end:
pthread_mutex_unlock(&chunk->lock);
return status;
LTTNG_OPTIONAL_GET(trace_chunk->timestamp_creation);
const time_t close_timestamp =
LTTNG_OPTIONAL_GET(trace_chunk->timestamp_close);
- LTTNG_OPTIONAL(struct lttng_directory_handle) archived_chunks_directory = {};
+ struct lttng_directory_handle *archived_chunks_directory = NULL;
if (!trace_chunk->mode.is_set ||
trace_chunk->mode.value != TRACE_CHUNK_MODE_OWNER ||
- !trace_chunk->session_output_directory.is_set) {
+ !trace_chunk->session_output_directory) {
/*
* This command doesn't need to run if the output is remote
* or if the trace chunk is not owned by this process.
* is renamed to match the chunk's name.
*/
if (chunk_id == 0) {
- struct lttng_directory_handle temporary_rename_directory;
+ struct lttng_directory_handle *temporary_rename_directory =
+ NULL;
size_t i, count = lttng_dynamic_pointer_array_get_count(
- &trace_chunk->top_level_directories);
+ &trace_chunk->top_level_directories);
ret = lttng_directory_handle_create_subdirectory_as_user(
- &trace_chunk->session_output_directory.value,
+ trace_chunk->session_output_directory,
DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY,
DIR_CREATION_MODE,
!trace_chunk->credentials.value.use_current_user ?
DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY);
}
- ret = lttng_directory_handle_init_from_handle(&temporary_rename_directory,
+ temporary_rename_directory = lttng_directory_handle_create_from_handle(
DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY,
- &trace_chunk->session_output_directory.value);
- if (ret) {
+ trace_chunk->session_output_directory);
+ if (!temporary_rename_directory) {
ERR("Failed to get handle to temporary trace chunk rename directory");
goto end;
}
&trace_chunk->top_level_directories, i);
ret = lttng_directory_handle_rename_as_user(
- &trace_chunk->session_output_directory.value,
+ trace_chunk->session_output_directory,
top_level_name,
- &temporary_rename_directory,
+ temporary_rename_directory,
top_level_name,
LTTNG_OPTIONAL_GET(trace_chunk->credentials).use_current_user ?
NULL :
if (ret) {
PERROR("Failed to move \"%s\" to temporary trace chunk rename directory",
top_level_name);
- lttng_directory_handle_fini(
- &temporary_rename_directory);
+ lttng_directory_handle_put(
+ temporary_rename_directory);
goto end;
}
}
- lttng_directory_handle_fini(&temporary_rename_directory);
+ lttng_directory_handle_put(temporary_rename_directory);
directory_to_rename = DEFAULT_TEMPORARY_CHUNK_RENAME_DIRECTORY;
free_directory_to_rename = false;
} else {
}
ret = lttng_directory_handle_create_subdirectory_as_user(
- &trace_chunk->session_output_directory.value,
+ trace_chunk->session_output_directory,
DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY,
DIR_CREATION_MODE,
!trace_chunk->credentials.value.use_current_user ?
goto end;
}
- ret = lttng_directory_handle_init_from_handle(
- &archived_chunks_directory.value,
+ archived_chunks_directory = lttng_directory_handle_create_from_handle(
DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY,
- &trace_chunk->session_output_directory.value);
- if (ret) {
+ trace_chunk->session_output_directory);
+ if (!archived_chunks_directory) {
PERROR("Failed to get handle to archived trace chunks directory");
goto end;
}
- archived_chunks_directory.is_set = true;
ret = lttng_directory_handle_rename_as_user(
- &trace_chunk->session_output_directory.value,
+ trace_chunk->session_output_directory,
directory_to_rename,
- &archived_chunks_directory.value,
+ archived_chunks_directory,
archived_chunk_name,
LTTNG_OPTIONAL_GET(trace_chunk->credentials).use_current_user ?
NULL :
}
end:
- if (archived_chunks_directory.is_set) {
- lttng_directory_handle_fini(&archived_chunks_directory.value);
- }
+ lttng_directory_handle_put(archived_chunks_directory);
free(archived_chunk_name);
if (free_directory_to_rename) {
free(directory_to_rename);
DBG("Setting trace chunk close command to \"%s\"",
close_command_names[close_command]);
}
- LTTNG_OPTIONAL_SET(&chunk->close_command, close_command);
+ /*
+ * Unset close command for no-op for backward compatibility with relayd
+ * 2.11.
+ */
+ if (close_command != LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION) {
+ LTTNG_OPTIONAL_SET(&chunk->close_command, close_command);
+ } else {
+ LTTNG_OPTIONAL_UNSET(&chunk->close_command);
+ }
pthread_mutex_unlock(&chunk->lock);
end:
return status;
switch (command) {
case LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED:
return "move to completed trace chunk folder";
+ case LTTNG_TRACE_CHUNK_COMMAND_TYPE_NO_OPERATION:
+ return "no operation";
+ case LTTNG_TRACE_CHUNK_COMMAND_TYPE_DELETE:
+ return "delete";
default:
abort();
}
element->chunk = *chunk;
lttng_trace_chunk_init(&element->chunk);
- if (chunk->session_output_directory.is_set) {
- element->chunk.session_output_directory.value =
- lttng_directory_handle_move(
- &chunk->session_output_directory.value);
- }
- if (chunk->chunk_directory.is_set) {
- element->chunk.chunk_directory.value =
- lttng_directory_handle_move(
- &chunk->chunk_directory.value);
+ if (chunk->session_output_directory) {
+ /* Transferred ownership. */
+ element->chunk.session_output_directory =
+ chunk->session_output_directory;
+ chunk->session_output_directory = NULL;
+ }
+ if (chunk->chunk_directory) {
+ /* Transferred ownership. */
+ element->chunk.chunk_directory = chunk->chunk_directory;
+ chunk->chunk_directory = NULL;
}
/*
* The original chunk becomes invalid; the name attribute is transferred