mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Persist content state and bad block markings on sync errors while preserving deallocation state
This commit is contained in:
parent
0b64fb2eae
commit
45c032cd61
1 changed files with 46 additions and 13 deletions
|
|
@ -930,7 +930,7 @@ static void sync_parity_writer(struct snapraid_worker* worker, struct snapraid_t
|
|||
task->state = TASK_STATE_DONE;
|
||||
}
|
||||
|
||||
static int state_sync_process(struct snapraid_state* state, struct snapraid_parity_handle* parity_handle, block_off_t blockstart, block_off_t blockmax)
|
||||
static int state_sync_process(struct snapraid_state* state, struct snapraid_parity_handle* parity_handle, block_off_t blockstart, block_off_t blockmax, int* sync_durable)
|
||||
{
|
||||
struct snapraid_io io;
|
||||
struct snapraid_plan plan;
|
||||
|
|
@ -961,6 +961,8 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
|
|||
unsigned waiting_mac;
|
||||
bit_vect_t* block_enabled;
|
||||
|
||||
*sync_durable = 0;
|
||||
|
||||
/* get the present time */
|
||||
now = time(0);
|
||||
|
||||
|
|
@ -1728,6 +1730,9 @@ end:
|
|||
goto bail;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
*sync_durable = 1;
|
||||
|
||||
if (state->opt.kill_after_sync) {
|
||||
log_fatal(EUSER, "WARNING! Killing due --test-kill-after-sync option.\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
|
|
@ -1897,6 +1902,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
|
|||
unsigned l;
|
||||
int skip_sync = 0;
|
||||
int parity_shrink = 0;
|
||||
int sync_durable = 0;
|
||||
|
||||
msg_progress("Initializing...\n");
|
||||
|
||||
|
|
@ -2129,7 +2135,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
|
|||
log_fatal(EUSER, "WARNING! Killing due --test-kill-before-sync option.\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (blockstart < blockmax) {
|
||||
ret = state_sync_process(state, parity_handle, blockstart, blockmax);
|
||||
ret = state_sync_process(state, parity_handle, blockstart, blockmax, &sync_durable);
|
||||
if (ret == -1) {
|
||||
/* LCOV_EXCL_START */
|
||||
++process_error;
|
||||
|
|
@ -2138,6 +2144,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
|
|||
}
|
||||
} else {
|
||||
msg_status("Nothing to sync.\n");
|
||||
sync_durable = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2149,27 +2156,53 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
|
|||
log_fatal_errno(errno, lev_config_name(l));
|
||||
|
||||
++process_error;
|
||||
sync_durable = 0;
|
||||
/* continue, as we are already exiting */
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* On close errors, abort without committing or persisting state,
|
||||
* keeping the previous content file intact for recovery on the next run.
|
||||
* Only a clean full sync makes all deallocation records obsolete.
|
||||
*
|
||||
* When process_error == 0, parity has been fully updated without the deleted
|
||||
* files, so state_commit() clears the dealloclist.
|
||||
*
|
||||
* If any error occurred, state_commit() is skipped so the dealloclist remains
|
||||
* intact. Calling state_write() below will then persist both the accumulated
|
||||
* deallocation records and any error markings to the content file, keeping
|
||||
* recovery data available across consecutive interrupted or failed runs.
|
||||
*/
|
||||
if (process_error == 0) {
|
||||
msg_status("Everything OK\n");
|
||||
|
||||
state_commit(state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Persist progress, error markings, and pending deallocations only after
|
||||
* all parity handles are closed AND sync durability has been confirmed.
|
||||
*
|
||||
* If an asynchronous parity write, state_barrier(), or parity_close() failed,
|
||||
* parity on disk is uncertain or incomplete. In that case, we must not publish
|
||||
* in-memory BLK/EMPTY transitions to the content file, keeping the previous
|
||||
* content file intact for recovery on the next run.
|
||||
*
|
||||
* Similarly, if sync was skipped before parity modification (e.g. on prehash
|
||||
* failure), state_snapshot_pending() was bypassed (leaving SNAPSHOT_SCAN
|
||||
* unpromoted), and legacy parity splits or newly added levels may still have
|
||||
* split sizes set to PARITY_SIZE_INVALID (only resolved in the parity handles).
|
||||
* Requiring sync durability ensures that snapshots, split sizes, and physical
|
||||
* parity are completely consistent and serializable before invoking state_write().
|
||||
*/
|
||||
if (sync_durable) {
|
||||
if (state->need_write || state->opt.force_content_write)
|
||||
state_write(state);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue