Fix touch abort before the first sync when no content file exists

This commit is contained in:
Andrea Mazzoleni 2026-10-18 10:45:14 +02:00
parent 20e081d5ac
commit a0d6bc288a
3 changed files with 56 additions and 1 deletions

View file

@ -1530,7 +1530,8 @@ int snapraid_main(int argc, char* argv[])
if (state.opt.force_realloc)
state_locate_mark_tail_blocks_for_resync(&state, opt.parity_tail);
if (opt.gui_touch_before) {
/* skip touch itself until content is loaded and sync has initialized parity sizes */
if (opt.gui_touch_before && state_is_write_ready(&state)) {
ret = state_touch(&state);
/* save the new state if required */
@ -1627,6 +1628,9 @@ int snapraid_main(int argc, char* argv[])
} else if (operation == OPERATION_REHASH) {
state_read(&state);
/* prevent saving content with uninitialized parity split sizes */
state_require_write_ready(&state);
state_rehash(&state);
/*
@ -1645,6 +1649,9 @@ int snapraid_main(int argc, char* argv[])
} else if (operation == OPERATION_SCRUB) {
state_read(&state);
/* prevent saving content with uninitialized parity split sizes */
state_require_write_ready(&state);
/* refresh the size info before the content write */
state_refresh(&state);
@ -1667,6 +1674,9 @@ int snapraid_main(int argc, char* argv[])
} else if (operation == OPERATION_REWRITE) {
state_read(&state);
/* prevent saving content with uninitialized parity split sizes */
state_require_write_ready(&state);
/* intercept signals while operating */
os_signal_init(app_signal_handler, app_signal_handler);
@ -1682,6 +1692,9 @@ int snapraid_main(int argc, char* argv[])
} else if (operation == OPERATION_TOUCH) {
state_read(&state);
/* prevent saving content with uninitialized parity split sizes */
state_require_write_ready(&state);
memory();
ret = state_touch(&state);
@ -1696,6 +1709,7 @@ int snapraid_main(int argc, char* argv[])
*/
os_signal_init(app_signal_handler, app_signal_handler);
/* save the new state if required */
if (state.need_write)
state_write(&state);
} else if (operation == OPERATION_SPINUP) {

View file

@ -5428,6 +5428,37 @@ void state_read(struct snapraid_state* state)
state->checked_read = 1;
}
/**
* Check if all configured parity splits have persistent sizes.
*/
int state_is_write_ready(struct snapraid_state* state)
{
unsigned l, s;
for (l = 0; l < state->level; ++l) {
for (s = 0; s < state->parity[l].split_mac; ++s) {
if (state->parity[l].split_map[s].size == PARITY_SIZE_INVALID)
return 0;
}
}
return 1;
}
/**
* Require sync to initialize parity sizes before commands that can save content.
* Check before modifying timestamps or metadata, as a later write could fail
* even if the command has no blocks to process (e.g. a missing content replica).
*/
void state_require_write_ready(struct snapraid_state* state)
{
if (!state_is_write_ready(state)) {
log_fatal(EUSER, "The array has not been synced yet, or its parity configuration has changed.\n");
log_fatal(EUSER, "Run 'snapraid sync' before '%s'.\n", state->command);
exit(EXIT_FAILURE);
}
}
struct state_verify_thread_context {
struct snapraid_state* state;
struct snapraid_content* content;

View file

@ -240,6 +240,16 @@ void state_probe(struct snapraid_state* state);
*/
void state_read(struct snapraid_state* state);
/**
* Check if all configured parity splits have persistent sizes.
*/
int state_is_write_ready(struct snapraid_state* state);
/**
* Require initialized parity split sizes before commands that can save content.
*/
void state_require_write_ready(struct snapraid_state* state);
/**
* Count the number of unsynced parity positions using an event sweep across extents.
* Counts positions in [blockmin, blockmax). The caller must ensure that the disk list,