diff --git a/cmdline/check.c b/cmdline/check.c index cb681574..51212121 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -33,25 +33,12 @@ static const char* es(int err) { - if (err == EIO) + if (is_hw(err)) return "error_io"; else return "error"; } -static void log_fatal_errno(int err, const char* name) -{ - if (err == EIO) { - log_fatal(err, "DANGER! Unexpected input/output error in disk %s. It isn't possible to continue.\n", name); - } else if (err == EACCES) { - log_fatal(err, "WARNING! Grant permission in the disk %s. It isn't possible to continue.\n", name); - } else if (err == ENOSPC) { - log_fatal(err, "WARNING! Ensure there is free space on the disk %s. It isn't possible to continue.\n", name); - } else { - log_fatal(err, "WARNING! Without a working %s disk, it isn't possible to continue.\n", name); - } -} - /** * A block that failed the hash check, or that was deleted. */ @@ -1134,7 +1121,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna log_tag("%s:%u:%s:%s: Open error at position %u. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -1219,7 +1206,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), i, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -1321,7 +1308,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna buffer_recov[l] = 0; /* no parity to use */ - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -1569,7 +1556,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna log_error(errno, "Error stating empty file '%s'. %s.\n", path, strerror(errno)); log_tag("empty_%s:%s:%s: Empty file stat error\n", es(errno), disk->name, esc_tag(file->sub, esc_buffer)); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -1689,7 +1676,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna log_error(errno, "Error stating hardlink '%s'. %s.\n", path, strerror(errno)); log_tag("hardlink_%s:%s:%s:%s: Hardlink stat error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -1723,7 +1710,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna log_error(errno, "Error stating hardlink-to '%s'. %s.\n", pathto, strerror(errno)); log_tag("hardlink_%s:%s:%s:%s: Hardlink to stat error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -1751,7 +1738,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna log_error(errno, "Error reading symlink '%s'. %s.\n", path, strerror(errno)); log_tag("symlink_%s:%s:%s: Symlink read error. %s.\n", es(errno), disk->name, esc_tag(slink->sub, esc_buffer), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -1871,7 +1858,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna log_error(errno, "Error stating dir '%s'. %s.\n", path, strerror(errno)); log_tag("dir_%s:%s:%s: Dir stat error. %s.\n", es(errno), disk->name, esc_tag(dir->sub, esc_buffer), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -2141,7 +2128,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:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { log_fatal_errno(errno, lev_config_name(l)); exit(EXIT_FAILURE); } @@ -2178,7 +2165,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:%u:%s: Open error. %s.\n", es(errno), blockmax, lev_config_name(l), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { log_fatal_errno(errno, lev_config_name(l)); exit(EXIT_FAILURE); } diff --git a/cmdline/dry.c b/cmdline/dry.c index 1f9c21a4..ec85b543 100644 --- a/cmdline/dry.c +++ b/cmdline/dry.c @@ -30,32 +30,12 @@ static const char* es(int err) { - if (err == EIO) + if (is_hw(err)) return "error_io"; else return "error"; } -static void log_fatal_errno(int err, const char* name) -{ - if (err == EIO) { - log_fatal(err, "DANGER! Unexpected input/output error in disk %s. It isn't possible to continue.\n", name); - } else if (err == EACCES) { - log_fatal(err, "WARNING! Grant permission in the disk %s. It isn't possible to continue.\n", name); - } else if (err == ENOSPC) { - log_fatal(err, "WARNING! Ensure there is free space on the disk %s. It isn't possible to continue.\n", name); - } else { - log_fatal(err, "WARNING! Without a working %s disk, it isn't possible to continue.\n", name); - } -} - -static void log_error_errno(int err, const char* name) -{ - if (err == EIO) { - log_fatal(err, "DANGER! Unexpected input/output error in disk %s.\n", name); - } -} - static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task* task) { struct snapraid_io* io = worker->io; @@ -102,7 +82,7 @@ static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task log_fatal_errno(errno, disk->name); log_fatal(errno, "Stopping at block %u\n", blockcur); - if (errno == EIO) { + if (is_hw(errno)) { task->state = TASK_STATE_IOERROR; } else { task->state = TASK_STATE_ERROR; @@ -115,7 +95,7 @@ static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task ret = handle_open(handle, task->file, state->file_mode, log_error, 0); /* for missing file don't output a message */ if (ret == -1) { log_tag("%s:%u:%s:%s: Open error. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { /* LCOV_EXCL_START */ log_fatal_errno(errno, disk->name); log_fatal(errno, "Stopping at block %u\n", blockcur); @@ -131,7 +111,7 @@ static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, log_error, 0); if (task->read_size == -1) { log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { /* LCOV_EXCL_START */ log_error_errno(errno, disk->name); task->state = TASK_STATE_IOERROR_CONTINUE; @@ -163,7 +143,7 @@ static void dry_parity_reader(struct snapraid_worker* worker, struct snapraid_ta ret = parity_read(parity_handle, blockcur, buffer, state->block_size, log_error); if (ret == -1) { log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { /* LCOV_EXCL_START */ log_error_errno(errno, lev_config_name(level)); task->state = TASK_STATE_IOERROR_CONTINUE; @@ -406,7 +386,7 @@ bail: log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); log_fatal_errno(errno, disk->name); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; diff --git a/cmdline/scrub.c b/cmdline/scrub.c index a36a091f..b0bfc7d9 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -30,32 +30,12 @@ static const char* es(int err) { - if (err == EIO) + if (is_hw(err)) return "error_io"; else return "error"; } -static void log_fatal_errno(int err, const char* name) -{ - if (err == EIO) { - log_fatal(err, "DANGER! Unexpected input/output error in disk %s. It isn't possible to continue.\n", name); - } else if (err == EACCES) { - log_fatal(err, "WARNING! Grant permission in the disk %s. It isn't possible to continue.\n", name); - } else if (err == ENOSPC) { - log_fatal(err, "WARNING! Ensure there is free space on the disk %s. It isn't possible to continue.\n", name); - } else { - log_fatal(err, "WARNING! Without a working %s disk, it isn't possible to continue.\n", name); - } -} - -static void log_error_errno(int err, const char* name) -{ - if (err == EIO) { - log_fatal(err, "DANGER! Unexpected input/output error in disk %s.\n", name); - } -} - /** * Buffer for storing the new hashes. */ @@ -174,7 +154,7 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta log_fatal_errno(errno, disk->name); log_fatal(errno, "Stopping at block %u\n", blockcur); - if (errno == EIO) { + if (is_hw(errno)) { task->state = TASK_STATE_IOERROR; } else { task->state = TASK_STATE_ERROR; @@ -187,7 +167,7 @@ static void scrub_data_reader(struct snapraid_worker* worker, struct snapraid_ta ret = handle_open(handle, task->file, state->file_mode, log_error, 0); /* for missing file don't output a message */ if (ret == -1) { log_tag("%s:%u:%s:%s: Open error. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { /* LCOV_EXCL_START */ log_fatal_errno(errno, disk->name); log_fatal(errno, "Stopping at block %u\n", blockcur); @@ -218,7 +198,7 @@ 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) { log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { /* LCOV_EXCL_START */ log_error_errno(errno, disk->name); task->state = TASK_STATE_IOERROR_CONTINUE; @@ -250,7 +230,7 @@ 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) { log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { /* LCOV_EXCL_START */ log_error_errno(errno, lev_config_name(level)); task->state = TASK_STATE_IOERROR_CONTINUE; @@ -742,7 +722,7 @@ bail: log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); log_fatal_errno(errno, disk->name); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; diff --git a/cmdline/support.c b/cmdline/support.c index c14bb00c..6515e9b1 100644 --- a/cmdline/support.c +++ b/cmdline/support.c @@ -133,6 +133,114 @@ uint64_t random_u64(void) return z ^ (z >> 31); } +/****************************************************************************/ +/* error */ + +int is_hw(int err) +{ + if (err == EIO) + return 1; +#ifdef EFSCORRUPTED + if (err == EFSCORRUPTED) /* used by XFS inside the kernel - never expected in user mode as converted to EUCLEAN */ + return 1; +#endif +#ifdef EUCLEAN + if (err == EUCLEAN) /* used by XFS at user level instead of EFSCORRUPTED */ + return 1; +#endif +#ifdef EBADCRC + if (err == EBADCRC) /* used by BTRFS - never expected in user mode as converted to EIO */ + return 1; +#endif +#ifdef EBADMSG + if (err == EBADMSG) /* used by BTRFS - never expected in user mode as converted to EIO */ + return 1; +#endif +#ifdef ENOMEDIUM + if (err == ENOMEDIUM) /* medium removed */ + return 1; +#endif +#ifdef EHWPOISON + if (err == EHWPOISON) /* hardware memory error */ + return 1; +#endif + return 0; +} + +void log_fatal_errno(int err, const char* name) +{ + if (err == EIO) { + log_fatal(err, "DANGER! Unexpected input/output error in disk %s. It isn't possible to continue.\n", name); +#ifdef EFSCORRUPTED + } else if (err == EFSCORRUPTED) { + log_fatal(err, "DANGER! Unexpected corrupted error in disk %s. It isn't possible to continue.\n", name); +#endif +#ifdef EUCLEAN + } else if (err == EUCLEAN) { + log_fatal(err, "DANGER! Unexpected corrupted error in disk %s. It isn't possible to continue.\n", name); +#endif +#ifdef EBADCRC + } else if (err == EBADCRC) { + log_fatal(err, "DANGER! Unexpected bad crc error in disk %s. It isn't possible to continue.\n", name); +#endif +#ifdef EBADMSG + } else if (err == EBADMSG) { + log_fatal(err, "DANGER! Unexpected bad crc error in disk %s. It isn't possible to continue.\n", name); +#endif +#ifdef ENOMEDIUM + } else if (err == ENOMEDIUM) { + log_fatal(err, "DANGER! Unexpected medium removed in disk %s. It isn't possible to continue.\n", name); +#endif +#ifdef EHWPOISON + } else if (err == EHWPOISON) { + log_fatal(err, "DANGER! Unexpected memory error in disk %s. It isn't possible to continue.\n", name); +#endif + } else if (err == EACCES) { + log_fatal(err, "WARNING! Grant permission in the disk %s. It isn't possible to continue.\n", name); + } else if (err == ENOSPC) { + log_fatal(err, "WARNING! Ensure there is free space on the disk %s. It isn't possible to continue.\n", name); + } else { + log_fatal(err, "WARNING! Without a working %s disk, it isn't possible to continue.\n", name); + } +} + +void log_error_errno(int err, const char* name) +{ + if (err == EIO) { + log_fatal(err, "DANGER! Unexpected input/output error in disk %s.\n", name); +#ifdef EFSCORRUPTED + } else if (err == EFSCORRUPTED) { + log_fatal(err, "DANGER! Unexpected corrupted error in disk %s.\n", name); +#endif +#ifdef EUCLEAN + } else if (err == EUCLEAN) { + log_fatal(err, "DANGER! Unexpected corrupted error in disk %s.\n", name); +#endif +#ifdef EBADCRC + } else if (err == EBADCRC) { + log_fatal(err, "DANGER! Unexpected bad crc error in disk %s.\n", name); +#endif +#ifdef EBADMSG + } else if (err == EBADMSG) { + log_fatal(err, "DANGER! Unexpected bad crc error in disk %s.\n", name); +#endif +#ifdef ENOMEDIUM + } else if (err == ENOMEDIUM) { + log_fatal(err, "DANGER! Unexpected medium removed in disk %s.\n", name); +#endif +#ifdef EHWPOISON + } else if (err == EHWPOISON) { + log_fatal(err, "DANGER! Unexpected memory error in disk %s.\n", name); +#endif + } else if (err == EACCES) { + log_error(err, "WARNING! Grant permission in the disk %s.\n", name); + } else if (err == ENOSPC) { + log_error(err, "WARNING! Ensure there is free space on the disk %s.\n", name); + } else if (err == ENOENT) { + log_error(err, "WARNING! You cannot modify files while running.\n"); + } +} + /****************************************************************************/ /* print */ @@ -211,7 +319,7 @@ void log_fatal(int err, const char* format, ...) lock_msg(); if (stdlog) { - if (err == EIO) + if (is_hw(err)) fprintf(stdlog, "msg:fatal_hardware: "); else fprintf(stdlog, "msg:fatal: "); @@ -239,7 +347,7 @@ void log_error(int err, const char* format, ...) lock_msg(); if (stdlog) { - if (err == EIO) + if (is_hw(err)) fprintf(stdlog, "msg:error_hardware: "); else fprintf(stdlog, "msg:error: "); @@ -267,7 +375,7 @@ void log_expected(int err, const char* format, ...) lock_msg(); if (stdlog) { - if (err == EIO) + if (is_hw(err)) fprintf(stdlog, "msg:error_hardware: "); /* we never expect an hardware error */ else fprintf(stdlog, "msg:expected: "); diff --git a/cmdline/support.h b/cmdline/support.h index bf3d6c02..3007caa8 100644 --- a/cmdline/support.h +++ b/cmdline/support.h @@ -70,6 +70,20 @@ unsigned char random_u8(void); */ uint64_t random_u64(void); +/****************************************************************************/ +/* error */ + +/** + * Return if the error is at hardware level + */ +int is_hw(int err); + +/** + * Log errors with standard messages + */ +void log_fatal_errno(int err, const char* name); +void log_error_errno(int err, const char* name); + /****************************************************************************/ /* log */ diff --git a/cmdline/sync.c b/cmdline/sync.c index d442f9e5..7cdd28c0 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -30,40 +30,12 @@ static const char* es(int err) { - if (err == EIO) + if (is_hw(err)) return "error_io"; else return "error"; } -static void log_fatal_errno(int err, const char* name) -{ - if (err == EIO) { - log_fatal(err, "DANGER! Unexpected input/output error in disk %s. It isn't possible to continue.\n", name); - } else if (err == EACCES) { - log_fatal(err, "WARNING! Grant permission in the disk %s. It isn't possible to continue.\n", name); - } else if (err == ENOSPC) { - log_fatal(err, "WARNING! Ensure there is free space on the disk %s. It isn't possible to continue.\n", name); - } else { - log_fatal(err, "WARNING! Without a working %s disk, it isn't possible to continue.\n", name); - } -} - -static void log_error_errno(int err, const char* name) -{ - if (err == EIO) { - log_fatal(err, "DANGER! Unexpected input/output error in disk %s.\n", name); - } else if (err == EACCES) { - log_error(err, "WARNING! Grant permission in the disk %s.\n", name); - log_error(err, "Rerun the sync command when finished.\n"); - } else if (err == ENOSPC) { - log_error(err, "WARNING! Ensure there is free space on the disk %s.\n", name); - } else if (err == ENOENT) { - log_error(err, "WARNING! You cannot modify files during a sync.\n"); - log_error(err, "Rerun the sync command when finished.\n"); - } -} - static int state_hash_process(struct snapraid_state* state, block_off_t blockstart, block_off_t blockmax, int* skip_sync) { struct snapraid_handle* handle; @@ -183,7 +155,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta log_fatal_errno(errno, disk->name); log_fatal(errno, "Stopping at block %u\n", blockcur); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -216,7 +188,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta /* LCOV_EXCL_START */ log_fatal_errno(errno, disk->name); - if (errno == EIO) { + if (is_hw(errno)) { log_fatal(errno, "Stopping at block %u\n", blockcur); ++io_error; } else { @@ -259,7 +231,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub, esc_buffer), file_pos, strerror(errno)); log_fatal_errno(errno, disk->name); - if (errno == EIO) { + if (is_hw(errno)) { log_fatal(errno, "Stopping at block %u\n", blockcur); ++io_error; } else { @@ -349,7 +321,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta log_fatal_errno(errno, disk->name); log_fatal(errno, "Stopping at block %u\n", blockmax); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -398,7 +370,7 @@ bail: log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); log_fatal_errno(errno, disk->name); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error; @@ -549,7 +521,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas log_fatal_errno(errno, disk->name); log_fatal(errno, "Stopping at block %u\n", blockcur); - if (errno == EIO) { + if (is_hw(errno)) { task->state = TASK_STATE_IOERROR; } else { task->state = TASK_STATE_ERROR; @@ -582,7 +554,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas /* LCOV_EXCL_START */ log_fatal_errno(errno, disk->name); - if (errno == EIO) { + if (is_hw(errno)) { log_fatal(errno, "Stopping at block %u\n", blockcur); task->state = TASK_STATE_IOERROR; } else { @@ -621,7 +593,7 @@ static void sync_data_reader(struct snapraid_worker* worker, struct snapraid_tas /* LCOV_EXCL_START */ log_tag("%s:%u:%s:%s: Read error at position %u. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub, esc_buffer), task->file_pos, strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { log_error_errno(errno, disk->name); /* continue until the error limit is reached */ task->state = TASK_STATE_IOERROR_CONTINUE; @@ -656,7 +628,7 @@ static void sync_parity_writer(struct snapraid_worker* worker, struct snapraid_t /* LCOV_EXCL_START */ log_tag("parity_%s:%u:%s: Write error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { log_error_errno(errno, lev_config_name(level)); /* continue until the error limit is reached */ task->state = TASK_STATE_IOERROR_CONTINUE; @@ -1091,7 +1063,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari if (ret == -1) { /* LCOV_EXCL_START */ log_tag("parity_%s:%u:%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(l), strerror(errno)); - if (errno == EIO) { + if (is_hw(errno)) { log_error_errno(errno, lev_config_name(l)); if (io_error >= state->opt.io_error_limit) { log_fatal(errno, "DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", lev_config_name(l)); @@ -1441,7 +1413,7 @@ bail: log_tag("%s:%u:%s:%s: Close error. %s.\n", es(errno), blockcur, disk->name, esc_tag(file->sub, esc_buffer), strerror(errno)); log_fatal_errno(errno, disk->name); - if (errno == EIO) { + if (is_hw(errno)) { ++io_error; } else { ++soft_error;