Leave block empty for unlocalized close errors and use zero for parity open errors
Some checks are pending
Build / build-mac (push) Waiting to run
Build / build-linux (push) Waiting to run
Build / build-arm32 (push) Waiting to run
Build / build-win (push) Waiting to run
Build / build-freebsd (push) Waiting to run
Build / build-musl (push) Waiting to run
CodeQL Advanced / Analyze (c-cpp) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run

This commit is contained in:
Andrea Mazzoleni 2026-09-23 16:25:32 +02:00
parent 1a5b28ad38
commit 222136f1e7
7 changed files with 157 additions and 73 deletions

View file

@ -1516,7 +1516,7 @@ static int file_post(struct snapraid_state* state, int fix, int partial, block_o
ret = handle_close(&handle[j]);
if (ret != 0) {
/* LCOV_EXCL_START */
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(report->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
return -1;
/* LCOV_EXCL_STOP */
@ -1580,7 +1580,7 @@ static int file_post(struct snapraid_state* state, int fix, int partial, block_o
ret = handle_close(&handle[j]);
if (ret != 0) {
/* LCOV_EXCL_START */
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(file->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
return -1;
/* LCOV_EXCL_STOP */
@ -1635,7 +1635,7 @@ close_and_continue:
ret = handle_close(&handle[j]);
if (ret != 0) {
/* LCOV_EXCL_START */
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(file->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(file->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
return -1;
/* LCOV_EXCL_STOP */
@ -2041,7 +2041,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
ret = handle_close(&handle[j]);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), i, disk->name, esc_tag(report->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %" PRIu64 "\n", i);
@ -2941,7 +2941,7 @@ bail:
* If handle_close fails, the handle was open (f != -1), which
* guarantees that both file and disk pointers are valid.
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(file->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(file->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
++unrecoverable_error;
@ -3126,7 +3126,7 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
*/
ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
log_tag("parity_%s:%" PRIu64 ":%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno));
if (is_hw(errno)) {
log_fatal_errno(errno, lev_config_name(l));
exit(EXIT_FAILURE);
@ -3180,7 +3180,7 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
parity_ptr[l] = &parity[l];
ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
log_tag("parity_%s:%" PRIu64 ":%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno));
if (is_hw(errno)) {
log_fatal_errno(errno, lev_config_name(l));
exit(EXIT_FAILURE);
@ -3217,7 +3217,7 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
ret = parity_close(parity_ptr[l]);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("parity_%s:%" PRIu64 ":%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
log_tag("parity_%s::%s: Close error. %s.\n", es(errno), lev_config_name(l), strerror(errno));
log_fatal_errno(errno, lev_config_name(l));
++process_error;

View file

@ -65,7 +65,7 @@ static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %" PRIu64 "\n", blockcur);
@ -377,7 +377,7 @@ bail:
* If handle_close fails, the handle was open (f != -1), which
* guarantees that both file and disk pointers are valid.
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(file->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
if (is_hw(errno)) {
@ -454,7 +454,7 @@ int state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t
ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("parity_%s:%" PRIu64 ":%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno));
log_fatal_errno(errno, lev_config_name(l));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
@ -479,7 +479,7 @@ int state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t
ret = parity_close(&parity_handle[l]);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("parity_%s:%" PRIu64 ":%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
log_tag("parity_%s::%s: Close error. %s.\n", es(errno), lev_config_name(l), strerror(errno));
log_fatal_errno(errno, lev_config_name(l));
++process_error;

View file

@ -370,7 +370,7 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %" PRIu64 "\n", blockcur);
@ -1034,7 +1034,7 @@ bail:
* If handle_close fails, the handle was open (f != -1), which
* guarantees that both file and disk pointers are valid.
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(file->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
if (is_hw(errno)) {
@ -1239,7 +1239,7 @@ int state_scrub(struct snapraid_state* state, int plan100, int olderthan)
ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("parity_%s:%" PRIu64 ":%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno));
log_fatal_errno(errno, lev_config_name(l));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
@ -1258,7 +1258,7 @@ int state_scrub(struct snapraid_state* state, int plan100, int olderthan)
ret = parity_close(&parity_handle[l]);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("parity_%s:%" PRIu64 ":%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
log_tag("parity_%s::%s: Close error. %s.\n", es(errno), lev_config_name(l), strerror(errno));
log_fatal_errno(errno, lev_config_name(l));
++process_error;

View file

@ -272,6 +272,47 @@
* both file size and modification time, may not be detected by a later scan.
* This is a general limitation of metadata-based change detection, not a
* special property of modifications occurring during sync.
*
* Structured error log model
* --------------------------
*
* Errors affecting data files are reported as:
*
* error:<block>:<disk>:<file>:<msg>
* error_io:<block>:<disk>:<file>:<msg>
* error_data:<block>:<disk>:<file>:<msg>
*
* Errors affecting parity are reported as:
*
* parity_error:<block>:<level>:<msg>
* parity_error_io:<block>:<level>:<msg>
* parity_error_data:<block>:<level>:<msg>
*
* "error" reports a soft or logical error that is not classified as a hardware
* I/O failure. "error_io" reports an I/O failure classified by is_hw().
* "error_data" reports data that was successfully read but did not match the
* expected hash or parity.
*
* The block field identifies the SnapRAID parity position associated with the
* error. It identifies the logical position affected by the failed operation,
* not necessarily the physical sector that caused the failure.
*
* Data file open/create errors occurring while processing a position report
* the current block, because that position could not be processed and may be
* marked bad for a later retry. Read/write and data errors report the position
* directly involved in the operation.
*
* Parity open/create errors report block 0. This is a retry marker rather than
* an indication that parity block 0 is bad: parity will be opened or created
* again by a subsequent command.
*
* The block field is empty when the error cannot be associated with a specific
* position. In particular, close errors use an empty block because an error
* reported by close() may originate from an earlier operation and cannot be
* reliably attributed to any previously processed block.
*
* Error classification and block localization are independent: for example,
* both error and error_io may have an empty block when reporting a close error.
*/
/****************************************************************************/
@ -400,7 +441,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %" PRIu64 "\n", blockcur);
@ -580,7 +621,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockmax, disk->name, esc_tag(report->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %" PRIu64 "\n", blockmax);
@ -634,7 +675,7 @@ bail:
* If handle_close fails, the handle was open (f != -1), which
* guarantees that both file and disk pointers are valid.
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(file->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
if (is_hw(errno)) {
@ -802,7 +843,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(report->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %" PRIu64 "\n", blockcur);
@ -1843,7 +1884,7 @@ bail_abort:
* If handle_close fails, the handle was open (f != -1), which
* guarantees that both file and disk pointers are valid.
*/
log_tag("%s:%" PRIu64 ":%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub), strerror(errno));
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(file->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
if (is_hw(errno)) {
@ -2234,7 +2275,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
ret = parity_close(&parity_handle[l]);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("parity_%s:%" PRIu64 ":%s: Close error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno));
log_tag("parity_%s::%s: Close error. %s.\n", es(errno), lev_config_name(l), strerror(errno));
log_fatal_errno(errno, lev_config_name(l));
++process_error;