From 67638a6638a3077356e8b98a92b4d4acbbbc79dc Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Thu, 27 Aug 2026 16:54:16 +0200 Subject: [PATCH] Create missing files as .unrecoverable during fix to ensure crash safety on SIGKILL --- cmdline/check.c | 58 +----------------------------------------------- cmdline/handle.c | 23 +++++++++++++++---- 2 files changed, 20 insertions(+), 61 deletions(-) diff --git a/cmdline/check.c b/cmdline/check.c index 9afcf9f3..367bf058 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -2082,63 +2082,6 @@ bail: } } - /* - * Remove all the files created from scratch that have not finished the processing - * it happens only when aborting pressing Ctrl+C or other reason. - */ - if (fix) { - /* for each disk */ - for (i = 0; i < diskmax; ++i) { - tommy_node* node; - struct snapraid_disk* disk; - - if (!handle[i].disk) - continue; - - /* for each file in the disk */ - disk = handle[i].disk; - node = disk->filelist; - while (node) { - char path[PATH_MAX]; - struct snapraid_file* file; - - file = node->data; - node = node->next; /* next node */ - - /* if the file was not created, meaning that it was already existing */ - if (!file_flag_has(file, FILE_IS_CREATED)) { - /* nothing to do */ - continue; - } - - /* if processing was finished */ - if (file_flag_has(file, FILE_IS_FINISHED)) { - /* nothing to do */ - continue; - } - - /* - * If the file was originally missing, and processing not yet finished - * we have to throw it away to ensure that at the next run we will retry - * to fix it, in case we select to undelete missing files - */ - pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub); - - ret = remove(path); - if (ret != 0) { - /* LCOV_EXCL_START */ - log_fatal(errno, "Error removing '%s'. %s.\n", path, strerror(errno)); - log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(file->sub), strerror(errno)); - log_fatal_errno(errno, disk->name); - - ++unrecoverable_error; - /* continue, as we are already exiting */ - /* LCOV_EXCL_STOP */ - } - } - } - } - if (soft_error || io_error || silent_error || recovered_error || unrecoverable_error) { msg_status("\n"); msg_status("%8u soft errors\n", soft_error); @@ -2399,3 +2342,4 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b return 0; } + diff --git a/cmdline/handle.c b/cmdline/handle.c index ae53ad4d..06f2ebab 100644 --- a/cmdline/handle.c +++ b/cmdline/handle.c @@ -74,11 +74,26 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file, in handle->is_unrecoverable = 1; pathcpy(handle->path, sizeof(handle->path), path_unrecoverable); } else if (errno == ENOENT) { - /* create it */ - handle->f = open(handle->path, flags | O_RDWR | O_CREAT, 0600); + /* + * Create missing file as .unrecoverable so that an interruption or + * crash (e.g. SIGKILL) during recovery never leaves a partially recovered + * file visible under its final name. + */ + handle->f = open(path_unrecoverable, flags | O_RDWR | O_CREAT | O_EXCL, 0600); if (handle->f != -1) { - /* mark it as created if really done */ - handle->created = 1; + handle->is_unrecoverable = 1; + pathcpy(handle->path, sizeof(handle->path), path_unrecoverable); + } else if (errno == EEXIST) { + /* if created concurrently, reopen safely */ + handle->f = open(path_unrecoverable, flags | O_RDWR); + if (handle->f != -1) { + handle->is_unrecoverable = 1; + pathcpy(handle->path, sizeof(handle->path), path_unrecoverable); + } else { + pathcpy(handle->path, sizeof(handle->path), path_unrecoverable); + } + } else { + pathcpy(handle->path, sizeof(handle->path), path_unrecoverable); } } else { /* report the path that failed to open */