From 1f70f1ea33990bc514c2734332f9750b5ff7b3a9 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Sat, 27 Dec 2014 23:14:06 +0100 Subject: [PATCH] Uses a better error detection in sync/scrub. --- cmdline/scrub.c | 72 +++++++++++----- cmdline/sync.c | 212 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 204 insertions(+), 80 deletions(-) diff --git a/cmdline/scrub.c b/cmdline/scrub.c index 5afe7ec6..b6e4b0ec 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -141,7 +141,6 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par snapraid_info info; int error_on_this_block; int silent_error_on_this_block; - int io_error_on_this_block; int block_is_unsynced; int rehash; @@ -188,7 +187,6 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par /* by default process the block, and skip it if something goes wrong */ error_on_this_block = 0; silent_error_on_this_block = 0; - io_error_on_this_block = 0; /* if all the blocks at this address are synced */ /* if not, parity is not even checked */ @@ -232,7 +230,6 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par /* report that the block and the file are not synced */ block_is_unsynced = 1; file_is_unsynced = 1; - /* follow */ } @@ -248,8 +245,18 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ + if (errno == EIO) { + fprintf(stdlog, "error:%u:%s:%s: Close EIO error. %s\n", i, disk->name, file->sub, strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output close error in a data disk, it isn't possible to scrub.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + } + fprintf(stdlog, "error:%u:%s:%s: Close error. %s\n", i, disk->name, file->sub, strerror(errno)); - fprintf(stderr, "DANGER! Unexpected close error in a data disk, it isn't possible to scrub.\n"); + fprintf(stderr, "WARNING! Unexpected close error in a data disk, it isn't possible to scrub.\n"); + fprintf(stderr, "Ensure that file '%s' can be accessed.\n", handle[j].path); printf("Stopping at block %u\n", i); ++error; goto bail; @@ -261,6 +268,17 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par if (ret == -1) { /* file we have tried to open for error reporting */ struct snapraid_file* file = block_file_get(block); + if (errno == EIO) { + /* LCOV_EXCL_START */ + fprintf(stdlog, "error:%u:%s:%s: Open EIO error. %s\n", i, disk->name, file->sub, strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output open error in a data disk, it isn't possible to scrub.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + /* LCOV_EXCL_STOP */ + } + fprintf(stdlog, "error:%u:%s:%s: Open error. %s\n", i, disk->name, file->sub, strerror(errno)); ++error; error_on_this_block = 1; @@ -276,7 +294,6 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par /* report that the block and the file are not synced */ block_is_unsynced = 1; file_is_unsynced = 1; - /* follow */ } @@ -286,15 +303,22 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par read_size = handle_read(&handle[j], block, buffer[j], state->block_size, stderr); if (read_size == -1) { + /* file we are processing for error reporting */ + struct snapraid_file* file = block_file_get(block); if (errno == EIO) { - fprintf(stdlog, "error:%u:%s:%s: Input/Output error at position %u. %s\n", i, disk->name, handle[j].file->sub, block_file_pos(block), strerror(errno)); + /* LCOV_EXCL_START */ + fprintf(stdlog, "error:%u:%s:%s: Read EIO error at position %u. %s\n", i, disk->name, file->sub, block_file_pos(block), strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output read error in a data disk, it isn't possible to scrub.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", i); ++io_error; - io_error_on_this_block = 1; - } else { - fprintf(stdlog, "error:%u:%s:%s: Read error at position %u. %s\n", i, disk->name, handle[j].file->sub, block_file_pos(block), strerror(errno)); - ++error; - error_on_this_block = 1; + goto bail; + /* LCOV_EXCL_STOP */ } + + fprintf(stdlog, "error:%u:%s:%s: Read error at position %u. %s\n", i, disk->name, file->sub, block_file_pos(block), strerror(errno)); + ++error; + error_on_this_block = 1; continue; } @@ -337,7 +361,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par } /* if we have read all the data required and it's correct, proceed with the parity check */ - if (!error_on_this_block && !silent_error_on_this_block && !io_error_on_this_block) { + if (!error_on_this_block && !silent_error_on_this_block) { unsigned char* buffer_recov[LEV_MAX]; /* until now is CPU */ @@ -356,15 +380,19 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par buffer_recov[l] = 0; if (errno == EIO) { - fprintf(stdlog, "parity_error:%u:%s: Input/Output error. %s\n", i, lev_config_name(l), strerror(errno)); + /* LCOV_EXCL_START */ + fprintf(stdlog, "parity_error:%u:%s: Read EIO error. %s\n", i, lev_config_name(l), strerror(errno)); + fprintf(stderr, "DANGER! input/output read error in the %s disk, it isn't possible to sync.\n", lev_name(l)); + fprintf(stderr, "Ensure that disk '%s' is sane and can be read.\n", lev_config_name(l)); + printf("Stopping at block %u\n", i); ++io_error; - io_error_on_this_block = 1; - } else { - fprintf(stdlog, "parity_error:%u:%s: Read error. %s\n", i, lev_config_name(l), strerror(errno)); - ++error; - error_on_this_block = 1; + goto bail; + /* LCOV_EXCL_STOP */ } + fprintf(stdlog, "parity_error:%u:%s: Read error. %s\n", i, lev_config_name(l), strerror(errno)); + ++error; + error_on_this_block = 1; /* follow */ } @@ -396,7 +424,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par } } - if (silent_error_on_this_block || io_error_on_this_block) { + if (silent_error_on_this_block) { /* set the error status keeping the existing time and hash */ info_set(&state->infoarr, i, info_set_bad(info)); } else if (error_on_this_block) { @@ -458,7 +486,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par if (error || silent_error || io_error) { printf("\n"); - printf("%8u other errors\n", error); + printf("%8u file errors\n", error); printf("%8u io errors\n", io_error); printf("%8u data errors\n", silent_error); printf("WARNING! There are errors!\n"); @@ -468,10 +496,10 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par printf("Everything OK\n"); } - fprintf(stdlog, "summary:error_other:%u\n", error); + fprintf(stdlog, "summary:error_file:%u\n", error); fprintf(stdlog, "summary:error_io:%u\n", io_error); fprintf(stdlog, "summary:error_data:%u\n", silent_error); - if (error + silent_error == 0) + if (error + silent_error + io_error == 0) fprintf(stdlog, "summary:exit:ok\n"); else fprintf(stdlog, "summary:exit:error\n"); diff --git a/cmdline/sync.c b/cmdline/sync.c index ac2b15ca..f1aece86 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -27,7 +27,7 @@ /****************************************************************************/ /* hash */ -static int state_hash_process(struct snapraid_state* state, block_off_t blockstart, block_off_t blockmax) +static int state_hash_process(struct snapraid_state* state, block_off_t blockstart, block_off_t blockmax, int* skip_sync) { struct snapraid_handle* handle; unsigned diskmax; @@ -39,7 +39,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta block_off_t countmax; int ret; unsigned error; - int skip_sync = 0; + unsigned io_error; /* maps the disks to handles */ handle = handle_map(state, &diskmax); @@ -50,6 +50,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta mtest_vector(1, state->block_size, &buffer); error = 0; + io_error = 0; /* first count the number of blocks to process */ countmax = 0; @@ -123,16 +124,25 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta /* if the file is different than the current one, close it */ if (handle[j].file != 0 && handle[j].file != block_file_get(block)) { - /* file we are processing for error reporting */ + /* keep a pointer at the file we are going to close for error reporting */ struct snapraid_file* file = handle[j].file; ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ + if (errno == EIO) { + fprintf(stdlog, "error:%u:%s:%s: Close EIO error. %s\n", i, disk->name, file->sub, strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output close error in a data disk, it isn't possible to scrub.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + } + fprintf(stdlog, "error:%u:%s:%s: Close error. %s\n", i, disk->name, file->sub, strerror(errno)); - fprintf(stderr, "DANGER! Unexpected close error in a data disk, it isn't possible to sync.\n"); - fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + fprintf(stderr, "WARNING! Unexpected close error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that file '%s' can be accessed.\n", handle[j].path); printf("Stopping at block %u\n", i); ++error; goto bail; @@ -142,38 +152,45 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta ret = handle_open(&handle[j], block_file_get(block), state->file_mode, stderr); if (ret == -1) { - /* file we are processing for error reporting */ + /* file we have tried to open for error reporting */ struct snapraid_file* file = block_file_get(block); + if (errno == EIO) { + /* LCOV_EXCL_START */ + fprintf(stdlog, "error:%u:%s:%s: Open EIO error. %s\n", i, disk->name, file->sub, strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output open error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + /* LCOV_EXCL_STOP */ + } + if (errno == ENOENT) { - fprintf(stdlog, "error:%u:%s:%s: Open missing error. %s\n", i, disk->name, file->sub, strerror(errno)); + fprintf(stdlog, "error:%u:%s:%s: Open ENOENT error. %s\n", i, disk->name, file->sub, strerror(errno)); fprintf(stderr, "Missing file '%s'.\n", handle[j].path); fprintf(stderr, "WARNING! You cannot modify data disk during a sync.\n"); fprintf(stderr, "Rerun the sync command when finished.\n"); - ++error; - /* if the file is missing, it means that it was removed during sync */ /* this isn't a serious error, so we skip this block, and continue with others */ continue; } + if (errno == EACCES) { - fprintf(stdlog, "error:%u:%s:%s: Open access error. %s\n", i, disk->name, file->sub, strerror(errno)); + fprintf(stdlog, "error:%u:%s:%s: Open EACCES error. %s\n", i, disk->name, file->sub, strerror(errno)); fprintf(stderr, "No access at file '%s'.\n", handle[j].path); fprintf(stderr, "WARNING! Please fix the access permission in the data disk.\n"); fprintf(stderr, "Rerun the sync command when finished.\n"); - ++error; - /* this isn't a serious error, so we skip this block, and continue with others */ continue; } /* LCOV_EXCL_START */ fprintf(stdlog, "error:%u:%s:%s: Open error. %s\n", i, disk->name, file->sub, strerror(errno)); - fprintf(stderr, "DANGER! Unexpected open error in a data disk, it isn't possible to sync.\n"); - fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + fprintf(stderr, "WARNING! Unexpected open error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that file '%s' can be accessed.\n", handle[j].path); printf("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", file->sub); - ++error; goto bail; /* LCOV_EXCL_STOP */ @@ -198,9 +215,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta } fprintf(stderr, "WARNING! You cannot modify files during a sync.\n"); fprintf(stderr, "Rerun the sync command when finished.\n"); - ++error; - /* if the file is changed, it means that it was modified during sync */ /* this isn't a serious error, so we skip this block, and continue with others */ continue; @@ -211,9 +226,18 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta /* LCOV_EXCL_START */ /* file we are processing for error reporting */ struct snapraid_file* file = block_file_get(block); + if (errno == EIO) { + fprintf(stdlog, "error:%u:%s:%s: Read EIO error at position %u. %s\n", i, disk->name, file->sub, block_file_pos(block), strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output read error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be read.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + } + fprintf(stdlog, "error:%u:%s:%s: Read error at position %u. %s\n", i, disk->name, file->sub, block_file_pos(block), strerror(errno)); - fprintf(stderr, "DANGER! Unexpected read error in a data disk, it isn't possible to sync.\n"); - fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be read.\n", disk->dir, handle[j].path); + fprintf(stderr, "WARNING! Unexpected read error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that file '%s' can be read.\n", handle[j].path); printf("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", file->sub); ++error; goto bail; @@ -247,7 +271,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta /* progress */ if (state_progress(state, i, countpos, countmax, countsize)) { /* LCOV_EXCL_START */ - skip_sync = 1; + *skip_sync = 1; /* avoid to run the next sync */ break; /* LCOV_EXCL_STOP */ } @@ -255,17 +279,25 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta /* close the last file in the disk */ if (handle[j].file != 0) { - /* file we are processing for error reporting */ + /* keep a pointer at the file we are going to close for error reporting */ struct snapraid_file* file = handle[j].file; ret = handle_close(&handle[j]); - if (ret == -1) { /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ + if (errno == EIO) { + fprintf(stdlog, "error:%u:%s:%s: Close EIO error. %s\n", blockmax, disk->name, file->sub, strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output close error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", blockmax); + ++io_error; + goto bail; + } + fprintf(stdlog, "error:%u:%s:%s: Close error. %s\n", blockmax, disk->name, file->sub, strerror(errno)); - fprintf(stderr, "DANGER! Unexpected close error in a data disk, it isn't possible to sync.\n"); - fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + fprintf(stderr, "WARNING! Unexpected close error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that file '%s' can be accessed.\n", handle[j].path); printf("Stopping at block %u\n", blockmax); ++error; goto bail; @@ -277,9 +309,10 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta end: state_progress_end(state, countpos, countmax, countsize); - if (error) { + if (error || io_error) { printf("\n"); - printf("%8u read/write errors\n", error); + printf("%8u file errors\n", error); + printf("%8u io errors\n", io_error); printf("WARNING! There are errors!\n"); } else { /* print the result only if processed something */ @@ -289,7 +322,14 @@ end: fprintf(stdlog, "hash_summary:error_readwrite:%u\n", error); + /* proceed without bailing out */ + goto finish; + bail: + /* on bail, don't run the next sync */ + *skip_sync = 1; + + /* close files left open */ for (j = 0; j < diskmax; ++j) { ret = handle_close(&handle[j]); if (ret == -1) { @@ -299,10 +339,13 @@ bail: } } +finish: free(handle); free(buffer); - return skip_sync; + if (error + io_error != 0) + return -1; + return 0; } /****************************************************************************/ @@ -346,6 +389,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari int ret; unsigned error; unsigned silent_error; + unsigned io_error; time_t now; struct failed_struct* failed; int* failed_map; @@ -380,6 +424,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari error = 0; silent_error = 0; + io_error = 0; /* first count the number of blocks to process */ countmax = 0; @@ -550,16 +595,25 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari /* if the file is different than the current one, close it */ if (handle[j].file != 0 && handle[j].file != block_file_get(block)) { - /* file we are processing for error reporting */ + /* keep a pointer at the file we are going to close for error reporting */ struct snapraid_file* file = handle[j].file; ret = handle_close(&handle[j]); if (ret == -1) { /* LCOV_EXCL_START */ /* This one is really an unexpected error, because we are only reading */ /* and closing a descriptor should never fail */ + if (errno == EIO) { + fprintf(stdlog, "error:%u:%s:%s: Close EIO error. %s\n", i, disk->name, file->sub, strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output close error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + } + fprintf(stdlog, "error:%u:%s:%s: Close error. %s\n", i, disk->name, file->sub, strerror(errno)); - fprintf(stderr, "DANGER! Unexpected close error in a data disk, it isn't possible to sync.\n"); - fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + fprintf(stderr, "WARNING! Unexpected close error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that file '%s' can be accessed.\n", handle[j].path); printf("Stopping at block %u\n", i); ++error; goto bail; @@ -569,29 +623,37 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari ret = handle_open(&handle[j], block_file_get(block), state->file_mode, stderr); if (ret == -1) { - /* file we are processing for error reporting */ + /* file we have tried to open for error reporting */ struct snapraid_file* file = block_file_get(block); + if (errno == EIO) { + /* LCOV_EXCL_START */ + fprintf(stdlog, "error:%u:%s:%s: Open EIO error. %s\n", i, disk->name, file->sub, strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output open error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + /* LCOV_EXCL_STOP */ + } + if (errno == ENOENT) { - fprintf(stdlog, "error:%u:%s:%s: Open missing error\n", i, disk->name, file->sub); + fprintf(stdlog, "error:%u:%s:%s: Open ENOENT error. %s\n", i, disk->name, file->sub, strerror(errno)); fprintf(stderr, "Missing file '%s'.\n", handle[j].path); fprintf(stderr, "WARNING! You cannot modify data disk during a sync.\n"); fprintf(stderr, "Rerun the sync command when finished.\n"); - ++error; - /* if the file is missing, it means that it was removed during sync */ /* this isn't a serious error, so we skip this block, and continue with others */ error_on_this_block = 1; continue; } + if (errno == EACCES) { - fprintf(stdlog, "error:%u:%s:%s: Open access error\n", i, disk->name, file->sub); + fprintf(stdlog, "error:%u:%s:%s: Open EACCES error. %s\n", i, disk->name, file->sub, strerror(errno)); fprintf(stderr, "No access at file '%s'.\n", handle[j].path); fprintf(stderr, "WARNING! Please fix the access permission in the data disk.\n"); fprintf(stderr, "Rerun the sync command when finished.\n"); - ++error; - /* this isn't a serious error, so we skip this block, and continue with others */ error_on_this_block = 1; continue; @@ -599,10 +661,9 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari /* LCOV_EXCL_START */ fprintf(stdlog, "error:%u:%s:%s: Open error. %s\n", i, disk->name, file->sub, strerror(errno)); - fprintf(stderr, "DANGER! Unexpected open error in a data disk, it isn't possible to sync.\n"); - fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be accessed.\n", disk->dir, handle[j].path); + fprintf(stderr, "WARNING! Unexpected open error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that file '%s' can be accessed.\n", handle[j].path); printf("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", file->sub); - ++error; goto bail; /* LCOV_EXCL_STOP */ @@ -627,9 +688,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari } fprintf(stderr, "WARNING! You cannot modify files during a sync.\n"); fprintf(stderr, "Rerun the sync command when finished.\n"); - ++error; - /* if the file is changed, it means that it was modified during sync */ /* this isn't a serious error, so we skip this block, and continue with others */ error_on_this_block = 1; @@ -641,9 +700,18 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari /* LCOV_EXCL_START */ /* file we are processing for error reporting */ struct snapraid_file* file = block_file_get(block); - fprintf(stdlog, "error:%u:%s:%s: Read error at position %u\n", i, disk->name, file->sub, block_file_pos(block)); - fprintf(stderr, "DANGER! Unexpected read error in a data disk, it isn't possible to sync.\n"); - fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be read.\n", disk->dir, handle[j].path); + if (errno == EIO) { + fprintf(stdlog, "error:%u:%s:%s: Read EIO error at position %u. %s\n", i, disk->name, file->sub, block_file_pos(block), strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output read error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that disk '%s' is sane and that file '%s' can be read.\n", disk->dir, handle[j].path); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + } + + fprintf(stdlog, "error:%u:%s:%s: Read error at position %u. %s\n", i, disk->name, file->sub, block_file_pos(block), strerror(errno)); + fprintf(stderr, "WARNING! Unexpected read error in a data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Ensure that file '%s' can be read.\n", handle[j].path); printf("Stopping to allow recovery. Try with 'snapraid check -f %s'\n", file->sub); ++error; goto bail; @@ -793,9 +861,18 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari ret = parity_read(parity[l], i, buffer[diskmax + l], state->block_size, stdlog); if (ret == -1) { /* LCOV_EXCL_START */ - fprintf(stdlog, "parity_error:%u:%s: Read error\n", i, lev_config_name(l)); - fprintf(stderr, "DANGER! Read error in the %s disk, it isn't possible to sync.\n", lev_name(l)); - fprintf(stderr, "Ensure that disk '%s' is sane.\n", lev_config_name(l)); + if (errno == EIO) { + fprintf(stdlog, "parity_error:%u:%s: Read EIO error. %s\n", i, lev_config_name(l), strerror(errno)); + fprintf(stderr, "DANGER! input/output read error in the %s disk, it isn't possible to sync.\n", lev_name(l)); + fprintf(stderr, "Ensure that disk '%s' is sane and can be read.\n", lev_config_name(l)); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + } + + fprintf(stdlog, "parity_error:%u:%s: Read error. %s\n", i, lev_config_name(l), strerror(errno)); + fprintf(stderr, "WARNING! Read error in the %s disk, it isn't possible to sync.\n", lev_name(l)); + fprintf(stderr, "Ensure that disk '%s' can be read.\n", lev_config_name(l)); printf("Stopping at block %u\n", i); ++error; goto bail; @@ -866,9 +943,18 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari ret = parity_write(parity[l], i, buffer[diskmax + l], state->block_size); if (ret == -1) { /* LCOV_EXCL_START */ - fprintf(stdlog, "parity_error:%u:%s: Write error\n", i, lev_config_name(l)); - fprintf(stderr, "DANGER! Write error in the %s disk, it isn't possible to sync.\n", lev_name(l)); - fprintf(stderr, "Ensure that disk '%s' is sane and have some free space available.\n", lev_config_name(l)); + if (errno == EIO) { + fprintf(stdlog, "parity_error:%u:%s: Write EIO error. %s\n", i, lev_config_name(l), strerror(errno)); + fprintf(stderr, "DANGER! Unexpected input/output write error in the %s disk, it isn't possible to sync.\n", lev_name(l)); + fprintf(stderr, "Ensure that disk '%s' is sane and can be written.\n", lev_config_name(l)); + printf("Stopping at block %u\n", i); + ++io_error; + goto bail; + } + + fprintf(stdlog, "parity_error:%u:%s: Write error. %s\n", i, lev_config_name(l), strerror(errno)); + fprintf(stderr, "WARNING! Unexpected write error in the %s disk, it isn't possible to sync.\n", lev_name(l)); + fprintf(stderr, "Ensure that disk '%s' has some free space available.\n", lev_config_name(l)); printf("Stopping at block %u\n", i); ++error; goto bail; @@ -993,9 +1079,10 @@ end: state_usage_print(state); - if (error || silent_error) { + if (error || silent_error || io_error) { printf("\n"); - printf("%8u read/write errors\n", error); + printf("%8u file errors\n", error); + printf("%8u io errors\n", io_error); printf("%8u data errors\n", silent_error); printf("WARNING! There are errors!\n"); } else { @@ -1004,9 +1091,10 @@ end: printf("Everything OK\n"); } - fprintf(stdlog, "summary:error_readwrite:%u\n", error); + fprintf(stdlog, "summary:error_file:%u\n", error); + fprintf(stdlog, "summary:error_io:%u\n", io_error); fprintf(stdlog, "summary:error_data:%u\n", silent_error); - if (error + silent_error == 0) + if (error + silent_error + io_error == 0) fprintf(stdlog, "summary:exit:ok\n"); else fprintf(stdlog, "summary:exit:error\n"); @@ -1016,9 +1104,11 @@ bail: for (j = 0; j < diskmax; ++j) { ret = handle_close(&handle[j]); if (ret == -1) { + /* LCOV_EXCL_START */ fprintf(stderr, "DANGER! Unexpected close error in a data disk.\n"); ++error; /* continue, as we are already exiting */ + /* LCOV_EXCL_STOP */ } } @@ -1030,10 +1120,10 @@ bail: free(failed_map); if (state->opt.expect_recoverable) { - if (error + silent_error == 0) + if (error + silent_error + io_error == 0) return -1; } else { - if (error + silent_error != 0) + if (error + silent_error + io_error != 0) return -1; } return 0; @@ -1118,7 +1208,13 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t if (state->opt.prehash) { printf("Hashing...\n"); - skip_sync = state_hash_process(state, blockstart, blockmax); + ret = state_hash_process(state, blockstart, blockmax, &skip_sync); + if (ret == -1) { + /* LCOV_EXCL_START */ + ++unrecoverable_error; + /* continue, in case also doing the sync */ + /* LCOV_EXCL_STOP */ + } if (state->need_write) state_write(state);