X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Ftrace-chunk.c;h=8ac00c12083e9acf9fe698238488b765f9a894a8;hp=7407f38f391ce60351d9746bfa0813a2429679be;hb=562f936f87b994cdd940d5142f6d3aedb2d95573;hpb=7ceefac4c8474606312e25ab822e510c41a3d644 diff --git a/src/common/trace-chunk.c b/src/common/trace-chunk.c index 7407f38f3..8ac00c120 100644 --- a/src/common/trace-chunk.c +++ b/src/common/trace-chunk.c @@ -1,41 +1,34 @@ /* - * Copyright (C) 2019 - Jérémie Galarneau + * Copyright (C) 2019 Jérémie Galarneau * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License, version 2.1 only, - * as published by the Free Software Foundation. + * SPDX-License-Identifier: LGPL-2.1-only * - * This library 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 Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include -#include -#include #include #include #include +#include +#include +#include /* * Two ISO 8601-compatible timestamps, separated by a hypen, followed an @@ -110,6 +103,14 @@ struct lttng_trace_chunk { struct lttng_directory_handle *session_output_directory; struct lttng_directory_handle *chunk_directory; LTTNG_OPTIONAL(enum lttng_trace_chunk_command_type) close_command; + /* + * fd_tracker instance through which file descriptors should be + * created/closed. + * + * An fd_tracker always outlives any trace chunk; there is no + * need to perform any reference counting of that object. + */ + struct fd_tracker *fd_tracker; }; /* A trace chunk is uniquely identified by its (session id, chunk id) tuple. */ @@ -127,6 +128,24 @@ struct lttng_trace_chunk_registry { struct cds_lfht *ht; }; +struct fs_handle_untracked { + struct fs_handle parent; + int fd; + struct { + struct lttng_directory_handle *directory_handle; + char *path; + } location; +}; + +static +int fs_handle_untracked_get_fd(struct fs_handle *handle); +static +void fs_handle_untracked_put_fd(struct fs_handle *handle); +static +int fs_handle_untracked_unlink(struct fs_handle *handle); +static +int fs_handle_untracked_close(struct fs_handle *handle); + static const char *close_command_names[] = { [LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED] = @@ -147,6 +166,92 @@ chunk_command close_command_post_release_funcs[] = { lttng_trace_chunk_delete_post_release, }; +static +struct fs_handle *fs_handle_untracked_create( + struct lttng_directory_handle *directory_handle, + const char *path, + int fd) +{ + struct fs_handle_untracked *handle = NULL; + bool reference_acquired; + char *path_copy = strdup(path); + + assert(fd >= 0); + if (!path_copy) { + PERROR("Failed to copy file path while creating untracked filesystem handle"); + goto end; + } + + handle = zmalloc(sizeof(typeof(*handle))); + if (!handle) { + PERROR("Failed to allocate untracked filesystem handle"); + goto end; + } + + handle->parent = (typeof(handle->parent)) { + .get_fd = fs_handle_untracked_get_fd, + .put_fd = fs_handle_untracked_put_fd, + .unlink = fs_handle_untracked_unlink, + .close = fs_handle_untracked_close, + }; + + handle->fd = fd; + reference_acquired = lttng_directory_handle_get(directory_handle); + assert(reference_acquired); + handle->location.directory_handle = directory_handle; + /* Ownership is transferred. */ + handle->location.path = path_copy; + path_copy = NULL; +end: + free(path_copy); + return handle ? &handle->parent : NULL; +} + +static +int fs_handle_untracked_get_fd(struct fs_handle *_handle) +{ + struct fs_handle_untracked *handle = container_of( + _handle, struct fs_handle_untracked, parent); + + return handle->fd; +} + +static +void fs_handle_untracked_put_fd(struct fs_handle *_handle) +{ + /* no-op. */ +} + +static +int fs_handle_untracked_unlink(struct fs_handle *_handle) +{ + struct fs_handle_untracked *handle = container_of( + _handle, struct fs_handle_untracked, parent); + + return lttng_directory_handle_unlink_file( + handle->location.directory_handle, + handle->location.path); +} + +static +void fs_handle_untracked_destroy(struct fs_handle_untracked *handle) +{ + lttng_directory_handle_put(handle->location.directory_handle); + free(handle->location.path); + free(handle); +} + +static +int fs_handle_untracked_close(struct fs_handle *_handle) +{ + struct fs_handle_untracked *handle = container_of( + _handle, struct fs_handle_untracked, parent); + int ret = close(handle->fd); + + fs_handle_untracked_destroy(handle); + return ret; +} + static bool lttng_trace_chunk_registry_element_equals( const struct lttng_trace_chunk_registry_element *a, @@ -352,6 +457,16 @@ error: return NULL; } +LTTNG_HIDDEN +void lttng_trace_chunk_set_fd_tracker(struct lttng_trace_chunk *chunk, + struct fd_tracker *fd_tracker) +{ + assert(!chunk->session_output_directory); + assert(!chunk->chunk_directory); + assert(lttng_dynamic_pointer_array_get_count(&chunk->files) == 0); + chunk->fd_tracker = fd_tracker; +} + LTTNG_HIDDEN struct lttng_trace_chunk *lttng_trace_chunk_copy( struct lttng_trace_chunk *source_chunk) @@ -413,6 +528,7 @@ struct lttng_trace_chunk *lttng_trace_chunk_copy( new_chunk->chunk_directory = source_chunk->chunk_directory; } new_chunk->close_command = source_chunk->close_command; + new_chunk->fd_tracker = source_chunk->fd_tracker; pthread_mutex_unlock(&source_chunk->lock); end: return new_chunk; @@ -650,7 +766,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_rename_path_no_lock( goto skip_move; } - if (old_path[0] != '\0' && path[0] != '\0') { + if (old_path && old_path[0] != '\0' && path[0] != '\0') { /* Rename chunk directory. */ ret = lttng_directory_handle_rename_as_user( chunk->session_output_directory, @@ -666,9 +782,14 @@ enum lttng_trace_chunk_status lttng_trace_chunk_rename_path_no_lock( status = LTTNG_TRACE_CHUNK_STATUS_ERROR; goto end; } - rename_directory = lttng_directory_handle_create_from_handle( - path, - chunk->session_output_directory); + rename_directory = chunk->fd_tracker ? + fd_tracker_create_directory_handle_from_handle( + chunk->fd_tracker, + chunk->session_output_directory, + path) : + lttng_directory_handle_create_from_handle( + path, + chunk->session_output_directory); if (!rename_directory) { ERR("Failed to get handle to trace chunk rename directory"); status = LTTNG_TRACE_CHUNK_STATUS_ERROR; @@ -683,7 +804,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_rename_path_no_lock( */ chunk->chunk_directory = rename_directory; rename_directory = NULL; - } else if (old_path[0] == '\0') { + } else if (old_path && old_path[0] == '\0') { size_t i, count = lttng_dynamic_pointer_array_get_count( &chunk->top_level_directories); @@ -738,7 +859,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_rename_path_no_lock( */ chunk->chunk_directory = rename_directory; rename_directory = NULL; - } else { + } else if (old_path) { size_t i, count = lttng_dynamic_pointer_array_get_count( &chunk->top_level_directories); const bool reference_acquired = lttng_directory_handle_get( @@ -784,21 +905,20 @@ enum lttng_trace_chunk_status lttng_trace_chunk_rename_path_no_lock( if (status != LTTNG_TRACE_CHUNK_STATUS_OK) { ERR("Error removing subdirectory '%s' file when deleting chunk", old_path); - ret = -1; goto end; } + } else { + /* Unexpected !old_path && !path. */ + status = LTTNG_TRACE_CHUNK_STATUS_INVALID_ARGUMENT; + goto end; } skip_move: - if (path) { - new_path = strdup(path); - if (!new_path) { - ERR("Failed to allocate new trace chunk path"); - status = LTTNG_TRACE_CHUNK_STATUS_ERROR; - goto end; - } - } else { - new_path = NULL; + new_path = strdup(path); + if (!new_path) { + ERR("Failed to allocate new trace chunk path"); + status = LTTNG_TRACE_CHUNK_STATUS_ERROR; + goto end; } free(chunk->path); chunk->path = new_path; @@ -924,9 +1044,14 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_as_owner( goto end; } chunk_directory_handle = - lttng_directory_handle_create_from_handle( - chunk->path, - session_output_directory); + chunk->fd_tracker ? + fd_tracker_create_directory_handle_from_handle( + chunk->fd_tracker, + session_output_directory, + chunk->path) : + lttng_directory_handle_create_from_handle( + chunk->path, + session_output_directory); if (!chunk_directory_handle) { /* The function already logs on all error paths. */ status = LTTNG_TRACE_CHUNK_STATUS_ERROR; @@ -1210,16 +1335,19 @@ void lttng_trace_chunk_remove_file( 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, bool expect_no_file) +static +enum lttng_trace_chunk_status _lttng_trace_chunk_open_fs_handle_locked( + struct lttng_trace_chunk *chunk, + const char *file_path, + int flags, + mode_t mode, + struct fs_handle **out_handle, + bool expect_no_file) { int ret; enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK; DBG("Opening trace chunk file \"%s\"", file_path); - pthread_mutex_lock(&chunk->lock); if (!chunk->credentials.is_set) { /* * Fatal error, credentials must be set before a @@ -1240,10 +1368,26 @@ enum lttng_trace_chunk_status lttng_trace_chunk_open_file( if (status != LTTNG_TRACE_CHUNK_STATUS_OK) { goto end; } - ret = lttng_directory_handle_open_file_as_user( - chunk->chunk_directory, file_path, flags, mode, - chunk->credentials.value.use_current_user ? - NULL : &chunk->credentials.value.user); + if (chunk->fd_tracker) { + assert(chunk->credentials.value.use_current_user); + *out_handle = fd_tracker_open_fs_handle(chunk->fd_tracker, + chunk->chunk_directory, file_path, flags, &mode); + ret = *out_handle ? 0 : -1; + } else { + ret = lttng_directory_handle_open_file_as_user( + chunk->chunk_directory, file_path, flags, mode, + chunk->credentials.value.use_current_user ? + NULL : + &chunk->credentials.value.user); + if (ret >= 0) { + *out_handle = fs_handle_untracked_create( + chunk->chunk_directory, file_path, ret); + if (!*out_handle) { + status = LTTNG_TRACE_CHUNK_STATUS_ERROR; + goto end; + } + } + } if (ret < 0) { if (errno == ENOENT && expect_no_file) { status = LTTNG_TRACE_CHUNK_STATUS_NO_FILE; @@ -1255,9 +1399,59 @@ enum lttng_trace_chunk_status lttng_trace_chunk_open_file( lttng_trace_chunk_remove_file(chunk, file_path); goto end; } - *out_fd = ret; end: + return status; +} + +LTTNG_HIDDEN +enum lttng_trace_chunk_status lttng_trace_chunk_open_fs_handle( + struct lttng_trace_chunk *chunk, + const char *file_path, + int flags, + mode_t mode, + struct fs_handle **out_handle, + bool expect_no_file) +{ + enum lttng_trace_chunk_status status; + + pthread_mutex_lock(&chunk->lock); + status = _lttng_trace_chunk_open_fs_handle_locked(chunk, file_path, + flags, mode, out_handle, expect_no_file); + pthread_mutex_unlock(&chunk->lock); + return status; +} + +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, + bool expect_no_file) +{ + enum lttng_trace_chunk_status status; + struct fs_handle *fs_handle; + + pthread_mutex_lock(&chunk->lock); + /* + * Using this method is never valid when an fd_tracker is being + * used since the resulting file descriptor would not be tracked. + */ + assert(!chunk->fd_tracker); + status = _lttng_trace_chunk_open_fs_handle_locked(chunk, file_path, + flags, mode, &fs_handle, expect_no_file); pthread_mutex_unlock(&chunk->lock); + + if (status == LTTNG_TRACE_CHUNK_STATUS_OK) { + *out_fd = fs_handle_get_fd(fs_handle); + /* + * Does not close the fd; we just "unbox" it from the fs_handle. + */ + fs_handle_untracked_destroy(container_of( + fs_handle, struct fs_handle_untracked, parent)); + } + return status; } @@ -1300,7 +1494,7 @@ end: return status; } -LTTNG_HIDDEN +static int lttng_trace_chunk_remove_subdirectory_recursive(struct lttng_trace_chunk *chunk, const char *path) { @@ -1388,9 +1582,14 @@ int lttng_trace_chunk_move_to_completed_post_release( goto end; } - archived_chunks_directory = lttng_directory_handle_create_from_handle( - DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY, - trace_chunk->session_output_directory); + archived_chunks_directory = trace_chunk->fd_tracker ? + fd_tracker_create_directory_handle_from_handle( + trace_chunk->fd_tracker, + trace_chunk->session_output_directory, + DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY) : + lttng_directory_handle_create_from_handle( + DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY, + trace_chunk->session_output_directory); if (!archived_chunks_directory) { PERROR("Failed to get handle to archived trace chunks directory"); ret = -1; @@ -1746,6 +1945,7 @@ lttng_trace_chunk_registry_element_create_from_chunk( */ chunk->name = NULL; chunk->path = NULL; + element->chunk.fd_tracker = chunk->fd_tracker; element->chunk.in_registry_element = true; end: return element;