X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=src%2Fcommon%2Ftrace-chunk.c;h=5518051960e654b654c118429e00e81b211e3cdc;hb=420e125556b416f84193298c239410018a228697;hp=6039f63761b532ac36c2464559b94a5d008cc2a8;hpb=f3ce6f5d9f5cfbe70898ca94efb3c8b31968534d;p=lttng-tools.git diff --git a/src/common/trace-chunk.c b/src/common/trace-chunk.c index 6039f6376..551805196 100644 --- a/src/common/trace-chunk.c +++ b/src/common/trace-chunk.c @@ -97,8 +97,14 @@ struct lttng_trace_chunk { char *path; /* An unset id means the chunk is anonymous. */ LTTNG_OPTIONAL(uint64_t) id; + + /* + * The creation and close timestamps are NOT monotonic. + * They must not be used in context were monotonicity is required. + */ LTTNG_OPTIONAL(time_t) timestamp_creation; LTTNG_OPTIONAL(time_t) timestamp_close; + LTTNG_OPTIONAL(struct chunk_credentials) credentials; struct lttng_directory_handle *session_output_directory; struct lttng_directory_handle *chunk_directory; @@ -599,11 +605,20 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_close_timestamp( status = LTTNG_TRACE_CHUNK_STATUS_INVALID_OPERATION; goto end; } + + /* + * Note: we do not enforce that the closing timestamp be greater or + * equal to the begin timestamp. These timestamps are used for + * generating the chunk name and should only be used in context where + * the monotonicity of time is not important. The source of those + * timestamps is NOT monotonic and represent the system calendar time, + * also know as the wall time. + */ if (chunk->timestamp_creation.value > close_ts) { - ERR("Failed to set trace chunk close timestamp: close timestamp is before creation timestamp"); - status = LTTNG_TRACE_CHUNK_STATUS_INVALID_ARGUMENT; - goto end; + WARN("Set trace chunk close timestamp: close timestamp is before creation timestamp, begin : %ld, close : %ld", + chunk->timestamp_creation.value, close_ts); } + LTTNG_OPTIONAL_SET(&chunk->timestamp_close, close_ts); if (!chunk->name_overridden) { free(chunk->name); @@ -766,7 +781,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, @@ -804,7 +819,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); @@ -859,7 +874,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( @@ -905,9 +920,12 @@ 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: @@ -1027,7 +1045,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_as_owner( status = LTTNG_TRACE_CHUNK_STATUS_ERROR; goto end; } - if (chunk->path[0] != '\0') { + if (chunk->path && chunk->path[0] != '\0') { ret = lttng_directory_handle_create_subdirectory_as_user( session_output_directory, chunk->path, @@ -1491,7 +1509,7 @@ end: return status; } -LTTNG_HIDDEN +static int lttng_trace_chunk_remove_subdirectory_recursive(struct lttng_trace_chunk *chunk, const char *path) { @@ -1810,6 +1828,37 @@ const char *lttng_trace_chunk_command_type_get_name( } } +LTTNG_HIDDEN +bool lttng_trace_chunk_ids_equal(const struct lttng_trace_chunk *chunk_a, + const struct lttng_trace_chunk *chunk_b) +{ + bool equal = false; + + if (chunk_a == chunk_b) { + equal = true; + goto end; + } + + if (!!chunk_a ^ !!chunk_b) { + goto end; + } + + if (chunk_a->id.is_set ^ chunk_a->id.is_set) { + /* One id is set and not the other, thus they are not equal. */ + goto end; + } + + if (!chunk_a->id.is_set) { + /* Both ids are unset. */ + equal = true; + } else { + equal = chunk_a->id.value == chunk_b->id.value; + } + +end: + return equal; +} + LTTNG_HIDDEN bool lttng_trace_chunk_get(struct lttng_trace_chunk *chunk) { @@ -1822,7 +1871,6 @@ void free_lttng_trace_chunk_registry_element(struct rcu_head *node) struct lttng_trace_chunk_registry_element *element = container_of(node, typeof(*element), rcu_node); - lttng_trace_chunk_fini(&element->chunk); free(element); } @@ -1843,6 +1891,24 @@ void lttng_trace_chunk_release(struct urcu_ref *ref) if (chunk->in_registry_element) { struct lttng_trace_chunk_registry_element *element; + /* + * Release internal chunk attributes immediately and + * only use the deferred `call_rcu` work to reclaim the + * storage. + * + * This ensures that file handles are released as soon as + * possible which works around a problem we encounter with PRAM fs + * mounts (and possibly other non-POSIX compliant file systems): + * directories that contain files which are open can't be + * rmdir(). + * + * This means that the recording of a snapshot could be + * completed, but that it would be impossible for the user to + * delete it until the deferred clean-up released the file + * handles to its contents. + */ + lttng_trace_chunk_fini(chunk); + element = container_of(chunk, typeof(*element), chunk); if (element->registry) { rcu_read_lock(); @@ -1952,7 +2018,20 @@ LTTNG_HIDDEN struct lttng_trace_chunk * lttng_trace_chunk_registry_publish_chunk( struct lttng_trace_chunk_registry *registry, - uint64_t session_id, struct lttng_trace_chunk *chunk) + uint64_t session_id, + struct lttng_trace_chunk *chunk) +{ + bool unused; + + return lttng_trace_chunk_registry_publish_chunk_published( + registry, session_id, chunk, &unused); +} + +struct lttng_trace_chunk * +lttng_trace_chunk_registry_publish_chunk_published( + struct lttng_trace_chunk_registry *registry, + uint64_t session_id, struct lttng_trace_chunk *chunk, + bool *previously_published) { struct lttng_trace_chunk_registry_element *element; unsigned long element_hash; @@ -1987,6 +2066,7 @@ lttng_trace_chunk_registry_publish_chunk( element->registry = registry; /* Acquire a reference for the caller. */ if (lttng_trace_chunk_get(&element->chunk)) { + *previously_published = false; break; } else { /* @@ -2013,6 +2093,7 @@ lttng_trace_chunk_registry_publish_chunk( if (lttng_trace_chunk_get(published_chunk)) { lttng_trace_chunk_put(&element->chunk); element = published_element; + *previously_published = true; break; } /*