From 1a5b28ad386a8caeea7a458a7fbd29d685a3ecd9 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 23 Sep 2026 16:11:20 +0200 Subject: [PATCH] Mark scrub/sync blocks bad when data file open fails with an I/O error --- cmdline/io.h | 1 + cmdline/scrub.c | 10 ++++++++++ cmdline/sync.c | 14 +++++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/cmdline/io.h b/cmdline/io.h index 42e7f127..df535946 100644 --- a/cmdline/io.h +++ b/cmdline/io.h @@ -66,6 +66,7 @@ struct snapraid_task { block_off_t file_pos; ssize_t read_size; /**< Size of the data read. */ int is_timestamp_different; /**< Report if file has a changed timestamp. */ + int unrelated_error; /**< Error unrelated to the current parity position. */ }; /** diff --git a/cmdline/scrub.c b/cmdline/scrub.c index f5d23474..094210c0 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -333,6 +333,10 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta block_off_t blockcur = task->position; unsigned char* buffer = task->buffer; int ret; + + /* tasks are reused, so a previous close failure must not affect this position */ + task->unrelated_error = 0; + /* if the disk position is not used */ if (!disk) { /* use an empty block */ @@ -370,6 +374,7 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta log_fatal_errno(errno, disk->name); log_fatal(errno, "Stopping at block %" PRIu64 "\n", blockcur); + task->unrelated_error = 1; if (is_hw(errno)) { task->state = TASK_STATE_IOERROR; } else { @@ -676,6 +681,11 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par if (task->state == TASK_STATE_IOERROR) { /* LCOV_EXCL_START */ ++io_error; + /* closing the previous file says nothing about this parity position */ + if (!task->unrelated_error) { + info_set(&state->infoarr, blockcur, info_set_bad(info)); + state->need_write = 1; + } goto bail; /* LCOV_EXCL_STOP */ } diff --git a/cmdline/sync.c b/cmdline/sync.c index 3c7450bd..c85ccaab 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -762,6 +762,10 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas block_off_t blockcur = task->position; unsigned char* buffer = task->buffer; int ret; + + /* tasks are reused, so a previous close failure must not affect this position */ + task->unrelated_error = 0; + /* if the disk position is not used */ if (!disk) { /* use an empty block */ @@ -802,6 +806,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas log_fatal_errno(errno, disk->name); log_fatal(errno, "Stopping at block %" PRIu64 "\n", blockcur); + task->unrelated_error = 1; if (is_hw(errno)) { task->state = TASK_STATE_IOERROR; } else { @@ -1192,9 +1197,12 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari if (task->state == TASK_STATE_IOERROR) { /* LCOV_EXCL_START */ ++io_error; - /* preserve the failing stripe before publishing partial sync progress */ - info_set(&state->infoarr, blockcur, info_set_bad(info)); - state->need_write = 1; + /* only errors in the current file identify this stripe as bad */ + if (!task->unrelated_error) { + /* preserve the failing stripe before publishing partial sync progress */ + info_set(&state->infoarr, blockcur, info_set_bad(info)); + state->need_write = 1; + } goto bail_durable; /* LCOV_EXCL_STOP */ }