From 65e6564e13aea19ce2632faeae00b58ce1f1f85f Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Mon, 17 Aug 2026 21:57:02 +0200 Subject: [PATCH] Clarify CHG block handling during interrupted sync recovery --- cmdline/check.c | 15 +++++++++++++-- cmdline/handle.c | 5 +++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/cmdline/check.c b/cmdline/check.c index e615d96a..69f93ca5 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -1298,8 +1298,19 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna */ if (block_state == BLOCK_STATE_CHG) { /* - * We DO NOT mark them as bad to avoid to overwrite them with wrong data. - * if we don't have a hash, we always assume the first read of the block correct. + * A CHG block has no hash for the current data. The stored hash + * refers to the previous content, and after an interrupted sync + * parity may refer either to the old or to the new content. + * + * If the block is readable, preserve it and assume it is the best + * available copy of the current data. We must not try to validate it + * against block->hash, as a match would only identify the old data + * and a mismatch would not prove that the current data is correct. + * + * This also intentionally applies to data reused from a previous + * multistep fix through an .unrecoverable file: already readable CHG + * data is preserved, while fix attempts to recover only missing or + * unreadable blocks. */ failed[failed_count].is_bad = 0; /* we assume the CHG block correct */ failed[failed_count].is_outofdate = 0; diff --git a/cmdline/handle.c b/cmdline/handle.c index 1f1259ac..b71afd8d 100644 --- a/cmdline/handle.c +++ b/cmdline/handle.c @@ -61,6 +61,11 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file, in /* check if exists a .unrecoverable copy, and rename to the real one */ pathprint(path_from, sizeof(path_from), "%s.unrecoverable", handle->path); + /* + * Reuse a previous partial recovery as the starting point for a + * multistep fix. Readable CHG blocks in this file are intentionally + * preserved because their current hash is not available. + */ if (rename(path_from, handle->path) == 0) { /* open for read write */ handle->f = open(handle->path, flags | O_RDWR);