From f453a7236900940237f26eaf7a81098e2821add1 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Fri, 14 Aug 2026 01:18:03 +0200 Subject: [PATCH] Preserve recovery state until a full clean sync completes --- cmdline/check.c | 7 +++---- cmdline/dry.c | 5 +++-- cmdline/scrub.c | 5 +++-- cmdline/snapraid.c | 18 +++++++++++++++++- cmdline/state.c | 11 ++++++++--- cmdline/sync.c | 38 +++++++++++++++++++------------------- 6 files changed, 53 insertions(+), 31 deletions(-) diff --git a/cmdline/check.c b/cmdline/check.c index bf6fafed..e615d96a 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -2091,11 +2091,7 @@ bail: /* without checking, we don't know if they are really recoverable or not */ if (!state->opt.auditonly) msg_status("%8u unrecoverable errors\n", unrecoverable_error); - if (fix) - msg_status("Everything OK\n"); } - } else { - msg_status("Everything OK\n"); } if ((soft_error || io_error || silent_error) && !fix) { @@ -2329,6 +2325,9 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b if (process_error != 0) return -1; + + msg_status("Everything OK\n"); + return 0; } diff --git a/cmdline/dry.c b/cmdline/dry.c index c6bdaaf9..bfe9bd07 100644 --- a/cmdline/dry.c +++ b/cmdline/dry.c @@ -388,8 +388,6 @@ bail: msg_status("\n"); msg_status("%8u soft errors\n", soft_error); msg_status("%8u io errors\n", io_error); - } else { - msg_status("Everything OK\n"); } if (soft_error) @@ -486,6 +484,9 @@ int state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t if (process_error != 0) return -1; + + msg_status("Everything OK\n"); + return 0; } diff --git a/cmdline/scrub.c b/cmdline/scrub.c index d6a2ffae..aa70962a 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -682,8 +682,6 @@ end: msg_status("%8u soft errors\n", soft_error); msg_status("%8u io errors\n", io_error); msg_status("%8u data errors\n", silent_error); - } else { - msg_status("Everything OK\n"); } if (soft_error) @@ -944,6 +942,9 @@ int state_scrub(struct snapraid_state* state, int plan100, int olderthan) if (process_error != 0) return -1; + + msg_status("Everything OK\n"); + return 0; } diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index 6db4d0d8..007909c9 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -1492,6 +1492,10 @@ int snapraid_main(int argc, char* argv[]) /* check options compatibility */ switch (operation) { #if HAVE_CHECKER + /* + * Ranged sync is retained only for checker regression scenarios. + * The checker never enables filesystem snapshots. + */ case OPERATION_SYNC : #endif case OPERATION_DRY : @@ -1886,8 +1890,12 @@ int snapraid_main(int argc, char* argv[]) ret = state_sync(&state, blockstart, blockcount); - /* commit the snapshot as stable */ + /* + * On an operation error, intentionally leave snapshot mounts available + * so that the user can inspect the filesystem state. + */ if (ret == 0) { + /* commit the snapshot as stable */ ret = state_snapshot_commit(&state); state_snapshot_cleanup(&state); } @@ -1940,6 +1948,10 @@ int snapraid_main(int argc, char* argv[]) ret = state_scrub(&state, plan100, olderthan); + /* + * On an operation error, intentionally leave snapshot mounts available + * so that the user can inspect the filesystem state. + */ if (ret == 0) { state_snapshot_cleanup(&state); } @@ -2076,6 +2088,10 @@ int snapraid_main(int argc, char* argv[]) state_scan(&state); } + /* + * On an operation error, intentionally leave snapshot mounts available + * so that the user can inspect the filesystem state. + */ if (ret == 0) { state_snapshot_cleanup(&state); } diff --git a/cmdline/state.c b/cmdline/state.c index 50d1fa90..6436c729 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -4946,9 +4946,14 @@ void state_commit(struct snapraid_state* state) for (i = state->disklist; i != 0; i = i->next) { struct snapraid_disk* disk = i->data; - /* clear the dealloc list */ - tommy_list_foreach(&disk->dealloclist, (tommy_foreach_func*)dealloc_free); - tommy_list_init(&disk->dealloclist); + if (!tommy_list_empty(&disk->dealloclist)) { + /* clear the dealloc list */ + tommy_list_foreach(&disk->dealloclist, (tommy_foreach_func*)dealloc_free); + tommy_list_init(&disk->dealloclist); + + /* mark the state as needing write */ + state->need_write = 1; + } } } diff --git a/cmdline/sync.c b/cmdline/sync.c index e1b00fe5..c9373236 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -286,7 +286,8 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta ++countpos; /* progress */ - if (state_progress(state, 0, blockcur, countpos, countmax, countsize)) { + alert = state_progress(state, 0, blockcur, countpos, countmax, countsize); + if (alert != 0) { /* LCOV_EXCL_START */ *skip_sync = 1; /* avoid to run the next sync due user interruption */ break; @@ -318,6 +319,9 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta /* LCOV_EXCL_STOP */ } } + + if (*skip_sync) + break; } end: @@ -334,8 +338,6 @@ end: msg_status("%8u soft errors\n", soft_error); msg_status("%8u io errors\n", io_error); msg_status("%8u data errors\n", silent_error); - } else { - msg_status("Everything OK\n"); } if (soft_error) @@ -378,7 +380,7 @@ finish: if (soft_error + io_error + silent_error != 0) return -1; - if (alert < 0) + if (alert != 0) return -1; return 0; @@ -1346,7 +1348,8 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari ++countpos; /* progress */ - if (state_progress(state, &io, blockcur, countpos, countmax, countsize)) { + alert = state_progress(state, &io, blockcur, countpos, countmax, countsize); + if (alert != 0) { /* LCOV_EXCL_START */ break; /* LCOV_EXCL_STOP */ @@ -1431,19 +1434,11 @@ end: goto bail; /* LCOV_EXCL_STOP */ } - - /* now the parity is fully written, no need to keep deallocated files */ - state_commit(state); - if (state->opt.kill_after_sync) { log_fatal(EUSER, "WARNING! Killing due --test-kill-after-sync option.\n"); exit(EXIT_SUCCESS); } - /* save the new state if required */ - if ((state->need_write || state->opt.force_content_write)) - state_write(state); - state_usage_print(state); if (soft_error || silent_error || io_error) { @@ -1451,10 +1446,6 @@ end: msg_status("%8u soft errors\n", soft_error); msg_status("%8u io errors\n", io_error); msg_status("%8u data errors\n", silent_error); - } else { - /* print the result only if processed something */ - if (countpos != 0) - msg_status("Everything OK\n"); } if (soft_error) @@ -1525,7 +1516,7 @@ bail: return -1; } - if (alert < 0) + if (alert != 0) return -1; return 0; @@ -1565,7 +1556,6 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t if (blockcount != 0 && blockcount < blockmax - blockstart) { blockmax = blockstart + blockcount; } - for (l = 0; l < state->level; ++l) { data_off_t out_size; block_off_t parityblocks; @@ -1723,6 +1713,16 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t if (process_error != 0) return -1; + + msg_status("Everything OK\n"); + + /* only a clean full sync makes all deallocation records obsolete */ + state_commit(state); + + /* persist progress and error markings only after all parity handles are closed */ + if (state->need_write || state->opt.force_content_write) + state_write(state); + return 0; }