Extend the log error tags to differentiate between io/silent to generic errors
Some checks are pending
Build / build-mac (push) Waiting to run
Build / build-linux (push) Waiting to run
Build / build-win (push) Waiting to run
CodeQL / Analyze (push) Waiting to run

This commit is contained in:
Andrea Mazzoleni 2026-01-13 23:45:31 +01:00
parent 9f14dd94e5
commit 276b06f0a6
6 changed files with 199 additions and 93 deletions

View file

@ -143,7 +143,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 */
if (errno == EIO) {
log_tag("error:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to scrub.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path);
log_fatal("Stopping at block %u\n", blockcur);
@ -165,7 +165,7 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta
if (ret == -1) {
if (errno == EIO) {
/* LCOV_EXCL_START */
log_tag("error:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno));
log_tag("error_io:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to scrub.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path);
log_fatal("Stopping at block %u\n", blockcur);
@ -197,7 +197,8 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta
task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, log_error, 0);
if (task->read_size == -1) {
if (errno == EIO) {
log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno));
log_tag("error_io:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno));
log_error("DANGER! Unexpected input/output error in a data disk, it isn't possible to scrub.\n");
log_error("Input/Output error in file '%s' at position '%u'\n", handle->path, task->file_pos);
task->state = TASK_STATE_IOERROR_CONTINUE;
return;
@ -228,7 +229,8 @@ static void scrub_parity_reader(struct snapraid_worker* worker, struct snapraid_
ret = parity_read(parity_handle, blockcur, buffer, state->block_size, log_error);
if (ret == -1) {
if (errno == EIO) {
log_tag("parity_error:%u:%s: Read EIO error. %s\n", blockcur, lev_config_name(level), strerror(errno));
log_tag("parity_error_io:%u:%s: Read EIO error. %s\n", blockcur, lev_config_name(level), strerror(errno));
log_error("DANGER! Unexpected input/output error in a parity disk, it isn't possible to scrub.\n");
log_error("Input/Output error in parity '%s' at position '%u'\n", lev_config_name(level), blockcur);
task->state = TASK_STATE_IOERROR_CONTINUE;
return;
@ -482,13 +484,13 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
if (memcmp(hash, block->hash, BLOCK_HASH_SIZE) != 0) {
unsigned diff = memdiff(hash, block->hash, BLOCK_HASH_SIZE);
log_tag("error:%u:%s:%s: Data error at position %u, diff bits %u/%u\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), file_pos, diff, BLOCK_HASH_SIZE * 8);
/* it's a silent error only if we are dealing with synced files */
if (file_is_unsynced) {
log_tag("error:%u:%s:%s: Data error at position %u, diff bits %u/%u\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), file_pos, diff, BLOCK_HASH_SIZE * 8);
++error;
error_on_this_block = 1;
} else {
log_tag("error_data:%u:%s:%s: Data error at position %u, diff bits %u/%u\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), file_pos, diff, BLOCK_HASH_SIZE * 8);
log_error("Data error in file '%s' at position '%u', diff bits %u/%u\n", task->path, file_pos, diff, BLOCK_HASH_SIZE * 8);
++silent_error;
silent_error_on_this_block = 1;
@ -575,14 +577,14 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par
if (buffer_recov[l] && memcmp(buffer[diskmax + l], buffer_recov[l], state->block_size) != 0) {
unsigned diff = memdiff(buffer[diskmax + l], buffer_recov[l], state->block_size);
log_tag("parity_error:%u:%s: Data error, diff bits %u/%u\n", blockcur, lev_config_name(l), diff, state->block_size * 8);
/* it's a silent error only if we are dealing with synced blocks */
if (block_is_unsynced) {
log_tag("parity_error:%u:%s: Data error, diff bits %u/%u\n", blockcur, lev_config_name(l), diff, state->block_size * 8);
++error;
error_on_this_block = 1;
} else {
log_fatal("Data error in parity '%s' at position '%u', diff bits %u/%u\n", lev_config_name(l), blockcur, diff, state->block_size * 8);
log_tag("parity_error_data:%u:%s: Data error, diff bits %u/%u\n", blockcur, lev_config_name(l), diff, state->block_size * 8);
log_error("Data error in parity '%s' at position '%u', diff bits %u/%u\n", lev_config_name(l), blockcur, diff, state->block_size * 8);
++silent_error;
silent_error_on_this_block = 1;
}
@ -701,6 +703,8 @@ end:
log_tag("summary:error_data:%u\n", silent_error);
if (error + silent_error + io_error == 0)
log_tag("summary:exit:ok\n");
else if (silent_error + io_error == 0)
log_tag("summary:exit:alert\n");
else
log_tag("summary:exit:error\n");
log_flush();
@ -715,9 +719,17 @@ bail:
ret = handle_close(&handle[j]);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected close error in a data disk.\n");
++error;
if (errno == EIO) {
log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output close error in a data disk.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path);
++io_error;
} else {
log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("WARNING! Unexpected close error in a data disk.\n");
log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path);
++error;
}
/* continue, as we are already exiting */
/* LCOV_EXCL_STOP */
}

View file

@ -139,7 +139,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 */
if (errno == EIO) {
log_tag("error:%u:%s:%s: Close EIO error. %s\n", i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", i, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to sync.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path);
log_fatal("Stopping at block %u\n", i);
@ -161,7 +161,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
if (ret == -1) {
if (errno == EIO) {
/* LCOV_EXCL_START */
log_tag("error:%u:%s:%s: Open EIO error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_tag("error_io:%u:%s:%s: Open EIO error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to sync.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path);
log_fatal("Stopping at block %u\n", i);
@ -207,13 +207,15 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
|| STAT_NSEC(&handle[j].st) != file->mtime_nsec
|| handle[j].st.st_ino != file->inode
) {
log_tag("error:%u:%s:%s: Unexpected attribute change\n", i, disk->name, esc_tag(file->sub, esc_buffer));
if (handle[j].st.st_size != file->size) {
log_tag("error:%u:%s:%s: Unexpected size change\n", i, disk->name, esc_tag(file->sub, esc_buffer));
log_error("Unexpected size change at file '%s' from %" PRIu64 " to %" PRIu64 ".\n", handle[j].path, file->size, (uint64_t)handle[j].st.st_size);
} else if (handle[j].st.st_mtime != file->mtime_sec
|| STAT_NSEC(&handle[j].st) != file->mtime_nsec) {
log_tag("error:%u:%s:%s: Unexpected time change\n", i, disk->name, esc_tag(file->sub, esc_buffer));
log_error("Unexpected time change at file '%s' from %" PRIu64 ".%d to %" PRIu64 ".%d.\n", handle[j].path, file->mtime_sec, file->mtime_nsec, (uint64_t)handle[j].st.st_mtime, STAT_NSEC(&handle[j].st));
} else {
log_tag("error:%u:%s:%s: Unexpected inode change\n", i, disk->name, esc_tag(file->sub, esc_buffer));
log_error("Unexpected inode change from %" PRIu64 " to %" PRIu64 " at file '%s'.\n", file->inode, (uint64_t)handle[j].st.st_ino, handle[j].path);
}
log_error("WARNING! You cannot modify files during a sync.\n");
@ -228,7 +230,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
if (read_size == -1) {
/* LCOV_EXCL_START */
if (errno == EIO) {
log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno));
log_tag("error_io:%u:%s:%s: Read EIO error at position %u. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno));
log_fatal("DANGER! Unexpected input/output read error in a data disk, it isn't possible to sync.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be read.\n", disk->dir, handle[j].path);
log_fatal("Stopping at block %u\n", i);
@ -265,7 +267,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta
if (block_state == BLOCK_STATE_REP) {
/* compare the hash */
if (memcmp(hash, block->hash, BLOCK_HASH_SIZE) != 0) {
log_tag("error:%u:%s:%s: Unexpected data change\n", i, disk->name, esc_tag(file->sub, esc_buffer));
log_tag("error_data:%u:%s:%s: Unexpected data change\n", i, disk->name, esc_tag(file->sub, esc_buffer));
log_error("Data change at file '%s' at position '%u'\n", handle[j].path, file_pos);
log_error("WARNING! Unexpected data modification of a file without parity!\n");
@ -321,7 +323,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 */
if (errno == EIO) {
log_tag("error:%u:%s:%s: Close EIO error. %s\n", blockmax, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockmax, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to sync.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path);
log_fatal("Stopping at block %u\n", blockmax);
@ -376,10 +378,20 @@ bail:
struct snapraid_disk* disk = handle[j].disk;
ret = handle_close(&handle[j]);
if (ret == -1) {
log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected close error in a data disk.\n");
++error;
/* LCOV_EXCL_START */
if (errno == EIO) {
log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output close error in a data disk.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path);
++io_error;
} else {
log_tag("error:%u:%s:%s: Close error. %s\n", i, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("WARNING! Unexpected close error in a data disk.\n");
log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path);
++error;
}
/* continue, as we are already exiting */
/* LCOV_EXCL_STOP */
}
}
@ -517,7 +529,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 */
if (errno == EIO) {
log_tag("error:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(report->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output close error in a data disk, it isn't possible to sync.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path);
log_fatal("Stopping at block %u\n", blockcur);
@ -539,7 +551,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
if (ret == -1) {
if (errno == EIO) {
/* LCOV_EXCL_START */
log_tag("error:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno));
log_tag("error_io:%u:%s:%s: Open EIO error. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to sync.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle->path);
log_fatal("Stopping at block %u\n", blockcur);
@ -606,7 +618,8 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas
if (task->read_size == -1) {
/* LCOV_EXCL_START */
if (errno == EIO) {
log_tag("error:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno));
log_tag("error_io:%u:%s:%s: Read EIO error at position %u. %s\n", blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno));
log_fatal("DANGER! Unexpected input/output open error in a data disk, it isn't possible to sync.\n");
log_error("Input/Output error in file '%s' at position '%u'\n", handle->path, task->file_pos);
task->state = TASK_STATE_IOERROR_CONTINUE;
return;
@ -642,7 +655,7 @@ static void sync_parity_writer(struct snapraid_worker* worker, struct snapraid_t
if (ret == -1) {
/* LCOV_EXCL_START */
if (errno == EIO) {
log_tag("parity_error:%u:%s: Write EIO error. %s\n", blockcur, lev_config_name(level), strerror(errno));
log_tag("parity_error_io:%u:%s: Write EIO error. %s\n", blockcur, lev_config_name(level), strerror(errno));
log_error("Input/Output error in parity '%s' at position '%u'\n", lev_config_name(level), blockcur);
task->state = TASK_STATE_IOERROR_CONTINUE;
return;
@ -974,7 +987,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
continue;
} else { /* otherwise it's a BLK with silent error */
unsigned diff = memdiff(hash, block->hash, BLOCK_HASH_SIZE);
log_tag("error:%u:%s:%s: Data error at position %u, diff bits %u/%u\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), file_pos, diff, BLOCK_HASH_SIZE * 8);
log_tag("error_data:%u:%s:%s: Data error at position %u, diff bits %u/%u\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), file_pos, diff, BLOCK_HASH_SIZE * 8);
log_error("Data error in file '%s' at position '%u', diff bits %u/%u\n", task->path, file_pos, diff, BLOCK_HASH_SIZE * 8);
/* save the failed block for the fix */
@ -1077,7 +1090,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari
if (ret == -1) {
/* LCOV_EXCL_START */
if (errno == EIO) {
log_tag("parity_error:%u:%s: Read EIO error. %s\n", blockcur, lev_config_name(l), strerror(errno));
log_tag("parity_error_io:%u:%s: Read EIO error. %s\n", blockcur, lev_config_name(l), strerror(errno));
if (io_error >= state->opt.io_error_limit) {
log_fatal("DANGER! Unexpected input/output read error in the %s disk, it isn't possible to sync.\n", lev_name(l));
log_fatal("Ensure that disk '%s' is sane and can be read.\n", lev_config_name(l));
@ -1411,6 +1424,8 @@ end:
log_tag("summary:error_data:%u\n", silent_error);
if (error + silent_error + io_error == 0)
log_tag("summary:exit:ok\n");
else if (silent_error + io_error == 0)
log_tag("summary:exit:alert\n");
else
log_tag("summary:exit:error\n");
log_flush();
@ -1425,8 +1440,17 @@ bail:
ret = handle_close(&handle[j]);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected close error in a data disk.\n");
if (errno == EIO) {
log_tag("error_io:%u:%s:%s: Close EIO error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("DANGER! Unexpected input/output close error in a data disk.\n");
log_fatal("Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path);
++io_error;
} else {
log_tag("error:%u:%s:%s: Close error. %s\n", blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno));
log_fatal("WARNING! Unexpected close error in a data disk.\n");
log_fatal("Ensure that file '%s' can be accessed.\n", handle[j].path);
++error;
}
++error;
/* continue, as we are already exiting */
/* LCOV_EXCL_STOP */

View file

@ -309,25 +309,32 @@ is assumed to be correct.
These tags provide a final count of all detected changes.
.TP
.B summary:equal:<count>
Total number of equal (unchanged) files/links/firs found (uint).
Total number of files/dirs/links whose metadata and data match
the current parity (uint).
.TP
.B summary:added:<count>
Total number of new files/links/dirs found (uint).
Total number of new brand new files/dirs/links that have no
relationship to existing parity (uint).
.TP
.B summary:removed:<count>
Total number of removed files/links/dirs found (uint).
Total number of files/dirs/links that existed in the last sync
but are now missing (uint).
.TP
.B summary:updated:<count>
Total number of updated files/links found (uint).
Total number of existing files where the timestamp or size has
changed (uint).
.TP
.B summary:moved:<count>
Total number of moved files found (uint).
Total number of files relocated to a new path but retaining
the same inode (uint).
.TP
.B summary:copied:<count>
Total number of copied files found (uint).
Total number of new files created by copying an existing
protected file to a new path (uint).
.TP
.B summary:restored:<count>
Total number of restored files found (uint).
Total number of new files matching a parity entry by
name/time/size but with a new inode (uint).
.TP
.B summary:exit:equal
A zero\-argument tag indicating that no differences were found.
@ -846,8 +853,8 @@ Unix timestamp of the scrub/sync.
Number of blocks processed at this timestamp.
.HP 4
.I <status>
\[dq]scrubbed\[dq] (for blocks verified to be correct) or
\[dq]new\[dq] (for synced blocks that haven\'t been scrubbed yet).
\`scrubbed\` (for blocks verified to be correct) or
\`new\` (for synced blocks that haven\'t been scrubbed yet).
.PD
.RE
.TP
@ -929,7 +936,7 @@ The total number of I/O errors encountered (uint).
.RE
.TP
.B summary:error_data:<count>
Logs the total count of \[dq]silent data errors\[dq] (data blocks
Logs the total count of \`silent data errors\` (data blocks
not matching their expected hash) encountered during the sync
process.
.RS 4
@ -947,10 +954,16 @@ one of the following:
.PD 0
.HP 4
.I ok
No errors were found.
No issues. The array is fully synchronized and healthy.
.HP 4
.I alert
Incomplete. Some files were skipped due to modifications
during execution or permission issues. No hardware risk.
.HP 4
.I error
If any errors were found (file, I/O, or data errors).
Critical failure. Indicates serious issues like I/O failures
or silent data corruption. Requires immediate hardware
or filesystem inspection.
.PD
.RE
.SH COMMAND CHECK/FIX TAGS
@ -989,7 +1002,7 @@ recomputed and written.
The block position being processed (uint).
.HP 4
.I <parity>
The name of the parity level (e.g., \[dq]parity\[dq], \[dq]2\-parity\[dq]).
The name of the parity level (e.g., \`parity\`, \`2\-parity\`).
.HP 4
.I <msg>
A descriptive message indicating the nature of the fix
@ -1217,22 +1230,22 @@ the following:
.RS 4
.PD 0
.HP 4
.I \`ok\`
.I ok
Indicates that the operation completed with no errors.
.HP 4
.I \`recovered\`
.I recovered
Indicates that the operation completed with all
errors successfully recovered (fix mode only).
.HP 4
.I \`recoverable\`
.I recoverable
Indicates that errors were found but are all
recoverable (check mode only).
.HP 4
.I \`unrecoverable\`
.I unrecoverable
Indicates that unrecoverable errors were
found.
.HP 4
.I \`error\`
.I error
Indicates that errors were found (audit\-only mode).
.PD
.RE
@ -1555,9 +1568,9 @@ rotational speed in RPM.
.B attr:<device_file>:<disk_name>[/<split_index>]:flags:<flags_decimal>:<flags_hex>
Logs the SMART status flags from the \`smartctl\` utility.
Per the smartctl manpage, these flags are bit\-mapped
to indicate specific issues like \[dq]Command line did not parse\[dq],
\[dq]Device could not be opened\[dq], or \[dq]SMART status check
returned \'DISK FAILING\'\[dq].
to indicate specific issues like \`Command line did not parse\`,
\`Device could not be opened\`, or \`SMART status check
returned \'DISK FAILING\'\`.
.RS 4
.PD 0
.HP 4
@ -1687,12 +1700,22 @@ process.
These tags report specific errors that occur on data disks during the
commands that access files and parities.
.TP
.B error:<block>:<disk_name>:<file>:<msg>
.B error[_io|_data]:<block>:<disk_name>:<file>:<msg>
Logs file access errors (open, read, file changed) during the
data disk read operation for parity calculation or verification.
.RS 4
.PD 0
.HP 4
.I _io
Indicates a physical Input/Output error.
The disk was unable to read or write a specific block,
typically signaling a failing sector or cable issue.
.HP 4
.I _data
Indicates the data was read successfully but failed
the checksum/hash verification. This signals \`silent\`
corruption or an unsuccessful parity match.
.HP 4
.I <block>
The zero\-based index of the block where the error occurred (uint).
.HP 4
@ -1710,11 +1733,21 @@ error (e.g., \`Open/Read/Write EIO error\`, \`Open/Read/Write error\`,
.PD
.RE
.TP
.B parity_error:<block>:<level>:<msg>
.B parity_error[_io|_data]:<block>:<level>:<msg>
Logs errors during parity disk read or write operations.
.RS 4
.PD 0
.HP 4
.I _io
Indicates a physical Input/Output error.
The disk was unable to read or write a specific block,
typically signaling a failing sector or cable issue.
.HP 4
.I _data
Indicates the data was read successfully but failed
the checksum/hash verification. This signals \`silent\`
corruption or an unsuccessful parity match.
.HP 4
.I <block>
The zero\-based index of the block where the error occurred (uint).
.HP 4

View file

@ -226,25 +226,32 @@ Scan Tags
These tags provide a final count of all detected changes.
=summary:equal:<count>
Total number of equal (unchanged) files/links/firs found (uint).
Total number of files/dirs/links whose metadata and data match
the current parity (uint).
=summary:added:<count>
Total number of new files/links/dirs found (uint).
Total number of new brand new files/dirs/links that have no
relationship to existing parity (uint).
=summary:removed:<count>
Total number of removed files/links/dirs found (uint).
Total number of files/dirs/links that existed in the last sync
but are now missing (uint).
=summary:updated:<count>
Total number of updated files/links found (uint).
Total number of existing files where the timestamp or size has
changed (uint).
=summary:moved:<count>
Total number of moved files found (uint).
Total number of files relocated to a new path but retaining
the same inode (uint).
=summary:copied:<count>
Total number of copied files found (uint).
Total number of new files created by copying an existing
protected file to a new path (uint).
=summary:restored:<count>
Total number of restored files found (uint).
Total number of new files matching a parity entry by
name/time/size but with a new inode (uint).
=summary:exit:equal
A zero-argument tag indicating that no differences were found.
@ -568,8 +575,8 @@ Command Status Tags
<time> - Unix timestamp of the scrub/sync.
<count> - Number of blocks processed at this timestamp.
<status> - "scrubbed" (for blocks verified to be correct) or
"new" (for synced blocks that haven't been scrubbed yet).
<status> - `scrubbed` (for blocks verified to be correct) or
`new` (for synced blocks that haven't been scrubbed yet).
=scrub_graph_range:<max_columns>:<max_height>
Dimensions of the scrub history graph obtained from the
@ -618,7 +625,7 @@ Command Sync/Scrub Tags
<count> - The total number of I/O errors encountered (uint).
=summary:error_data:<count>
Logs the total count of "silent data errors" (data blocks
Logs the total count of `silent data errors` (data blocks
not matching their expected hash) encountered during the sync
process.
@ -628,8 +635,12 @@ Command Sync/Scrub Tags
Logs the overall exit status of the command. The `status` is
one of the following:
ok - No errors were found.
error - If any errors were found (file, I/O, or data errors).
ok - No issues. The array is fully synchronized and healthy.
alert - Incomplete. Some files were skipped due to modifications
during execution or permission issues. No hardware risk.
error - Critical failure. Indicates serious issues like I/O failures
or silent data corruption. Requires immediate hardware
or filesystem inspection.
Command Check/Fix Tags
Tags specific for the `check` and `fix` commands.
@ -652,7 +663,7 @@ Command Check/Fix Tags
recomputed and written.
<block_pos> - The block position being processed (uint).
<parity> - The name of the parity level (e.g., "parity", "2-parity").
<parity> - The name of the parity level (e.g., `parity`, `2-parity`).
<msg> - A descriptive message indicating the nature of the fix
(e.g., `Fixed data error`).
@ -769,14 +780,14 @@ Command Check/Fix Tags
Logs the overall exit status of the command. The `status` is one of
the following:
`ok` - Indicates that the operation completed with no errors.
`recovered` - Indicates that the operation completed with all
ok - Indicates that the operation completed with no errors.
recovered - Indicates that the operation completed with all
errors successfully recovered (fix mode only).
`recoverable` - Indicates that errors were found but are all
recoverable - Indicates that errors were found but are all
recoverable (check mode only).
`unrecoverable` - Indicates that unrecoverable errors were
unrecoverable - Indicates that unrecoverable errors were
found.
`error` - Indicates that errors were found (audit-only mode).
error - Indicates that errors were found (audit-only mode).
Command List Tags
This section describes the tags output with the `list` command.
@ -994,9 +1005,9 @@ Command Smart And Probe Tags
=attr:<device_file>:<disk_name>[/<split_index>]:flags:<flags_decimal>:<flags_hex>
Logs the SMART status flags from the `smartctl` utility.
Per the smartctl manpage, these flags are bit-mapped
to indicate specific issues like "Command line did not parse",
"Device could not be opened", or "SMART status check
returned 'DISK FAILING'".
to indicate specific issues like `Command line did not parse`,
`Device could not be opened`, or `SMART status check
returned 'DISK FAILING'`.
<flags_decimal> - The raw flags value (uint64, decimal).
<flags_hex> - The raw flags value (uint64, hexadecimal).
@ -1082,10 +1093,16 @@ Error Tags
These tags report specific errors that occur on data disks during the
commands that access files and parities.
=error:<block>:<disk_name>:<file>:<msg>
=error[_io|_data]:<block>:<disk_name>:<file>:<msg>
Logs file access errors (open, read, file changed) during the
data disk read operation for parity calculation or verification.
_io - Indicates a physical Input/Output error.
The disk was unable to read or write a specific block,
typically signaling a failing sector or cable issue.
_data - Indicates the data was read successfully but failed
the checksum/hash verification. This signals `silent`
corruption or an unsuccessful parity match.
<block> - The zero-based index of the block where the error occurred (uint).
<disk_name> - The name of the data disk.
<file> - The path (relative to the disk mount point) of the
@ -1094,9 +1111,15 @@ Error Tags
error (e.g., `Open/Read/Write EIO error`, `Open/Read/Write error`,
`Data error at position <pos>, diff bits <diff>/<bits>`).
=parity_error:<block>:<level>:<msg>
=parity_error[_io|_data]:<block>:<level>:<msg>
Logs errors during parity disk read or write operations.
_io - Indicates a physical Input/Output error.
The disk was unable to read or write a specific block,
typically signaling a failing sector or cable issue.
_data - Indicates the data was read successfully but failed
the checksum/hash verification. This signals `silent`
corruption or an unsuccessful parity match.
<block> - The zero-based index of the block where the error occurred (uint).
<level> - The configuration name of the parity level (e.g.,
`parity`, `2-parity`).
@ -1106,7 +1129,7 @@ Error Tags
=hardlink_error:<disk_name>:<link_path>:<target_path>:<msg>
Indicates an error when attempting to access a hard link.
<disk_name> - The name of the disk.
<link_path> - The hard link path relative to disk root (escaped).
<target_path> - The target path of the hard link (escaped).

View file

@ -589,8 +589,8 @@ These tags provide details on the scrub/sync time distribution.
<time> - Unix timestamp of the scrub/sync.
<count> - Number of blocks processed at this timestamp.
<status> - "scrubbed" (for blocks verified to be correct) or
"new" (for synced blocks that haven't been scrubbed yet).
<status> - `scrubbed` (for blocks verified to be correct) or
`new` (for synced blocks that haven't been scrubbed yet).
scrub_graph_range:<max_columns>:<max_height>
Dimensions of the scrub history graph obtained from the
@ -642,7 +642,7 @@ These tags provide summary statistics at the end of the command.
<count> - The total number of I/O errors encountered (uint).
summary:error_data:<count>
Logs the total count of "silent data errors" (data blocks
Logs the total count of `silent data errors` (data blocks
not matching their expected hash) encountered during the sync
process.
@ -652,8 +652,12 @@ These tags provide summary statistics at the end of the command.
Logs the overall exit status of the command. The `status` is
one of the following:
ok - No errors were found.
error - If any errors were found (file, I/O, or data errors).
ok - No issues. The array is fully synchronized and healthy.
alert - Incomplete. Some files were skipped due to modifications
during execution or permission issues. No hardware risk.
error - Critical failure. Indicates serious issues like I/O failures
or silent data corruption. Requires immediate hardware
or filesystem inspection.
9 COMMAND CHECK/FIX TAGS
@ -679,7 +683,7 @@ These tags log successful repairs during fix operations.
recomputed and written.
<block_pos> - The block position being processed (uint).
<parity> - The name of the parity level (e.g., "parity", "2-parity").
<parity> - The name of the parity level (e.g., `parity`, `2-parity`).
<msg> - A descriptive message indicating the nature of the fix
(e.g., `Fixed data error`).
@ -796,14 +800,14 @@ These tags provide summary statistics at the end of the command.
Logs the overall exit status of the command. The `status` is one of
the following:
`ok` - Indicates that the operation completed with no errors.
`recovered` - Indicates that the operation completed with all
ok - Indicates that the operation completed with no errors.
recovered - Indicates that the operation completed with all
errors successfully recovered (fix mode only).
`recoverable` - Indicates that errors were found but are all
recoverable - Indicates that errors were found but are all
recoverable (check mode only).
`unrecoverable` - Indicates that unrecoverable errors were
unrecoverable - Indicates that unrecoverable errors were
found.
`error` - Indicates that errors were found (audit-only mode).
error - Indicates that errors were found (audit-only mode).
10 COMMAND LIST TAGS
@ -1036,9 +1040,9 @@ Tags logging specific disk identification and attribute values.
attr:<device_file>:<disk_name>[/<split_index>]:flags:<flags_decimal>:<flags_hex>
Logs the SMART status flags from the `smartctl` utility.
Per the smartctl manpage, these flags are bit-mapped
to indicate specific issues like "Command line did not parse",
"Device could not be opened", or "SMART status check
returned 'DISK FAILING'".
to indicate specific issues like `Command line did not parse`,
`Device could not be opened`, or `SMART status check
returned 'DISK FAILING'`.
<flags_decimal> - The raw flags value (uint64, decimal).
<flags_hex> - The raw flags value (uint64, hexadecimal).
@ -1130,10 +1134,16 @@ command execution with the `smartctl` command.
These tags report specific errors that occur on data disks during the
commands that access files and parities.
error:<block>:<disk_name>:<file>:<msg>
error[_io|_data]:<block>:<disk_name>:<file>:<msg>
Logs file access errors (open, read, file changed) during the
data disk read operation for parity calculation or verification.
_io - Indicates a physical Input/Output error.
The disk was unable to read or write a specific block,
typically signaling a failing sector or cable issue.
_data - Indicates the data was read successfully but failed
the checksum/hash verification. This signals `silent`
corruption or an unsuccessful parity match.
<block> - The zero-based index of the block where the error occurred (uint).
<disk_name> - The name of the data disk.
<file> - The path (relative to the disk mount point) of the
@ -1142,9 +1152,13 @@ commands that access files and parities.
error (e.g., `Open/Read/Write EIO error`, `Open/Read/Write error`,
`Data error at position <pos>, diff bits <diff>/<bits>`).
parity_error:<block>:<level>:<msg>
parity_error[_io|_data]:<block>:<level>:<msg>
Logs errors during parity disk read or write operations.
---- 16.0.1 _io - Indicates a physical Input/Output error. ----
_data - Indicates the data was read successfully but failed
the checksum/hash verification. This signals `silent`
corruption or an unsuccessful parity match.
<block> - The zero-based index of the block where the error occurred (uint).
<level> - The configuration name of the parity level (e.g.,
`parity`, `2-parity`).

View file

@ -1,3 +1,3 @@
#!/bin/sh
uncrustify -c uncrustify.cfg --replace cmdline/*.c cmdline/*.h
uncrustify -c uncrustify.cfg --replace --no-backup cmdline/*.c cmdline/*.h