From f443a7f089e651c31a5892378d83024071a4ffd9 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Fri, 18 Mar 2011 22:38:11 +0100 Subject: [PATCH] Better error management --- HISTORY | 1 + TODO | 1 - check.c | 112 ++++++++++++++++++++++++++++++++++++++------------ handle.c | 97 ++++++++++++++++++++++++------------------- handle.h | 19 +++++---- parity.c | 70 ++++++++++++++++--------------- parity.h | 10 ++--- scan.c | 2 +- snapraid.d | 4 +- snapraid.html | 4 +- snapraid.txt | 4 +- state.c | 2 +- sync.c | 84 +++++++++++++++++++++++++++++-------- 13 files changed, 272 insertions(+), 138 deletions(-) diff --git a/HISTORY b/HISTORY index fe35845f..193c7f7b 100644 --- a/HISTORY +++ b/HISTORY @@ -5,6 +5,7 @@ SnapRAID HISTORY ========== * Exclusion list of files and directories * More automatic tests +* Better error management * Better documentation diff --git a/TODO b/TODO index cba0dfec..bf29d213 100644 --- a/TODO +++ b/TODO @@ -24,4 +24,3 @@ http://isthe.com/chongo/src/fnv/hash_64a.c (C implementation) * Use the O_NOATIME flag if run as 'root'. Anyway a better solution is to mount the disk with the "noatime" and "nodiratime" options. -* During a sync operation periodicallly save the state to do not lose the job done in case of a system crash. diff --git a/check.c b/check.c index 95afae1a..530cafc1 100644 --- a/check.c +++ b/check.c @@ -26,7 +26,7 @@ /****************************************************************************/ /* check */ -static int state_check_process(int ret_on_error, struct snapraid_state* state, int fix, int parity_f, block_off_t blockstart, block_off_t blockmax) +static int state_check_process(struct snapraid_state* state, int fix, int parity_f, block_off_t blockstart, block_off_t blockmax) { struct snapraid_handle* handle; unsigned diskmax = tommy_array_size(&state->diskarr); @@ -102,12 +102,24 @@ static int state_check_process(int ret_on_error, struct snapraid_state* state, i if (!block->is_hashed) continue; + ret = handle_close_if_different(&handle[j], block->file); + if (ret == -1) { + fprintf(stderr, "WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + fprintf(stderr, "Stopping at block %u\n", i); + goto bail; + } + if (fix) { /* if fixing, create the file and open for writing */ - handle_create(&handle[j], block->file); + ret = handle_create(&handle[j], block->file); + if (ret == -1) { + fprintf(stderr, "WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + fprintf(stderr, "Stopping at block %u\n", i); + goto bail; + } } else { /* if checking, open the file for reading */ - ret = handle_open(-1, &handle[j], block->file); + ret = handle_open(&handle[j], block->file); if (ret == -1) { /* save the failed block for the parity check */ ++failed; @@ -120,7 +132,7 @@ static int state_check_process(int ret_on_error, struct snapraid_state* state, i } } - read_size = handle_read(-1, &handle[j], block, block_buffer, state->block_size); + read_size = handle_read(&handle[j], block, block_buffer, state->block_size); if (read_size == -1) { /* save the failed block for the parity check */ ++failed; @@ -155,14 +167,20 @@ static int state_check_process(int ret_on_error, struct snapraid_state* state, i count_size += read_size; } - if (failed == 0) { + if (parity_f == -1) { + /* all the cases with no parity file */ + if (failed != 0) { + fprintf(stderr, "%u: UNRECOVERABLE errors for this block\n", i); + ++unrecoverable_error; + } + } else if (failed == 0) { int ret; int fixable; fixable = 0; /* read the parity */ - ret = parity_read(-1, state->parity, parity_f, i, block_buffer, state->block_size); + ret = parity_read(state->parity, parity_f, i, block_buffer, state->block_size); if (ret == -1) { fprintf(stderr, "%u: Parity read error\n", i); ++error; @@ -181,7 +199,12 @@ static int state_check_process(int ret_on_error, struct snapraid_state* state, i if (fix && fixable) { /* fix the parity */ /* if all the file hashes are matching, we can recompute the parity */ - parity_write(state->parity, parity_f, i, xor_buffer, state->block_size); + ret = parity_write(state->parity, parity_f, i, xor_buffer, state->block_size); + if (ret == -1) { + fprintf(stderr, "WARNING! Without a working parity disk, it isn't possible to fix errors on it.\n"); + fprintf(stderr, "Stopping at block %u\n", i); + goto bail; + } fprintf(stderr, "%u: Fixed\n", i); ++recovered_error; @@ -196,7 +219,7 @@ static int state_check_process(int ret_on_error, struct snapraid_state* state, i fixable = 0; /* read the parity */ - ret = parity_read(-1, state->parity, parity_f, i, block_buffer, state->block_size); + ret = parity_read(state->parity, parity_f, i, block_buffer, state->block_size); if (ret == -1) { fprintf(stderr, "%u: Parity read error\n", i); fprintf(stderr, "%u: UNRECOVERABLE errors for this block\n", i); @@ -225,7 +248,12 @@ static int state_check_process(int ret_on_error, struct snapraid_state* state, i if (fix && fixable) { /* fix the file */ /* if only one file is wrong, we already have recomputed it */ - handle_write(failed_handle, failed_block, block_buffer, state->block_size); + ret = handle_write(failed_handle, failed_block, block_buffer, state->block_size); + if (ret == -1) { + fprintf(stderr, "WARNING! Without a working data disk, it isn't possible to fix errors on it.\n"); + fprintf(stderr, "Stopping at block %u\n", i); + goto bail; + } fprintf(stderr, "%u: Fixed\n", i); ++recovered_error; @@ -239,17 +267,30 @@ static int state_check_process(int ret_on_error, struct snapraid_state* state, i ++count_block; /* progress */ - if (state_progress(&start, &last, i, blockmax, count_block, count_size)) + if (state_progress(&start, &last, i, blockmax, count_block, count_size)) { + printf("Stopping for interruption at block %u\n", i); break; + } } printf("%u%% completed, %u MB processed\n", i * 100 / blockmax, (unsigned)(count_size / (1024*1024))); +bail: + for(j=0;jblock_size; if (blockstart > blockmax) { - fprintf(stderr, "The specified starting block %u is bigger than the parity size %u.\n", blockstart, blockmax); + fprintf(stderr, "Error in the specified starting block %u. It's bigger than the parity size %u.\n", blockstart, blockmax); exit(EXIT_FAILURE); } pathcpy(path, sizeof(path), state->parity); if (fix) { /* if fixing, create the file and open for writing */ - /* it never fails */ + /* if it fails, we cannot continue */ f = parity_create(path, size); + if (f == -1) { + fprintf(stderr, "WARNING! Without an accessible parity file, it isn't possible to fix any error.\n"); + exit(EXIT_FAILURE); + } } else { /* if checking, open the file for reading */ - /* it may fail if the file doesn't exist */ - f = parity_open(-1, path); + /* it may fail if the file doesn't exist, in this case we continue to check the files */ + f = parity_open(path); + if (f == -1) { + printf("No accessible parity file, all the errors are going to be UNRECOVERABLE.\n"); + /* continue anyway */ + } } /* skip degenerated cases of empty parity, or skipping all */ if (blockstart < blockmax) { - ret = state_check_process(-1, state, fix, f, blockstart, blockmax); + ret = state_check_process(state, fix, f, blockstart, blockmax); if (ret == -1) { - /* no extra message */ + if (f != -1) { + ret = parity_close(path, f); + if (ret != -1) { + fprintf(stderr, "WARNING! A 'snapraid check' command is highly suggested.\n"); + /* continue, as we are already exiting */ + } + } + /* exit with a failure code */ exit(EXIT_FAILURE); } - } else { - printf("Nothing to do\n"); } + /* try to close only if opened */ if (f != -1) { - parity_close(path, f); + ret = parity_close(path, f); + if (ret == -1) { + fprintf(stderr, "WARNING! A 'snapraid check' command is highly suggested.\n"); + exit(EXIT_FAILURE); + } } } + diff --git a/handle.c b/handle.c index 3b3887d3..8af386a0 100644 --- a/handle.c +++ b/handle.c @@ -24,31 +24,56 @@ /****************************************************************************/ /* handle */ -int handle_create(struct snapraid_handle* handle, struct snapraid_file* file) +int handle_close_if_different(struct snapraid_handle* handle, struct snapraid_file* file) { - struct stat st; int ret; - - /* if already opened, nothing to do */ - if (handle->file == file && handle->f != -1) { + + /* if it's the same file, nothing to do */ + if (handle->file == file) { return 0; } + /* reset the file */ + handle->file = 0; + /* close if already open */ if (handle->f != -1) { ret = close(handle->f); if (ret != 0) { + /* invalidate for error */ + handle->f = -1; + fprintf(stderr, "Error closing file '%s'. %s.\n", handle->file->sub, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } } + /* reset the descriptor */ + handle->f = -1; + + return 0; +} + +int handle_create(struct snapraid_handle* handle, struct snapraid_file* file) +{ + struct stat st; + int ret; + + /* if it's the same file, and already opened, nothing to do */ + if (handle->file == file && handle->f != -1) { + return 0; + } + pathprint(handle->path, sizeof(handle->path), "%s%s", handle->disk->dir, file->sub); handle->f = open(handle->path, O_RDWR | O_CREAT | O_BINARY, 0600); if (handle->f == -1) { + /* invalidate for error */ + handle->file = 0; + handle->f = -1; + fprintf(stderr, "Error opening file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } /* just opened */ @@ -58,7 +83,7 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file) ret = fstat(handle->f, &st); if (ret != 0) { fprintf(stderr, "Error accessing file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } if (st.st_size < file->size) { @@ -75,13 +100,13 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file) } else { fprintf(stderr, "Error growing file '%s'. %s.\n", handle->path, strerror(errno)); } - exit(EXIT_FAILURE); + return -1; } } else if (st.st_size > file->size) { ret = ftruncate(handle->f, file->size); if (ret != 0) { fprintf(stderr, "Error truncating file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } } @@ -90,14 +115,14 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file) ret = posix_fadvise(handle->f, 0, 0, POSIX_FADV_SEQUENTIAL); if (ret != 0) { fprintf(stderr, "Error advising file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } #endif return 0; } -int handle_open(int ret_on_error, struct snapraid_handle* handle, struct snapraid_file* file) +int handle_open(struct snapraid_handle* handle, struct snapraid_file* file) { int ret; @@ -106,16 +131,6 @@ int handle_open(int ret_on_error, struct snapraid_handle* handle, struct snaprai return 0; } - /* close if already open */ - if (handle->f != -1) { - ret = close(handle->f); - if (ret != 0) { - /* here we always abort on error, as close is supposed to never fail */ - fprintf(stderr, "Error closing file '%s'. %s.\n", handle->file->sub, strerror(errno)); - exit(EXIT_FAILURE); - } - } - pathprint(handle->path, sizeof(handle->path), "%s%s", handle->disk->dir, file->sub); handle->f = open(handle->path, O_RDONLY | O_BINARY); @@ -124,11 +139,8 @@ int handle_open(int ret_on_error, struct snapraid_handle* handle, struct snaprai handle->file = 0; handle->f = -1; - if (ret_on_error) - return ret_on_error; - fprintf(stderr, "Error opening file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } /* just opened */ @@ -138,32 +150,37 @@ int handle_open(int ret_on_error, struct snapraid_handle* handle, struct snaprai /* advise sequential access */ ret = posix_fadvise(handle->f, 0, 0, POSIX_FADV_SEQUENTIAL); if (ret != 0) { - /* here we always abort on error, as advise is supposed to never fail */ fprintf(stderr, "Error advising file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } #endif return 0; } -void handle_close(struct snapraid_handle* handle) +int handle_close(struct snapraid_handle* handle) { int ret; if (handle->f != -1) { ret = close(handle->f); if (ret != 0) { + /* invalidate for error */ + handle->file = 0; + handle->f = -1; + fprintf(stderr, "Error closing file '%s'. %s.\n", handle->file->sub, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } } handle->file = 0; handle->f = -1; + + return 0; } -int handle_read(int ret_on_error, struct snapraid_handle* handle, struct snapraid_block* block, unsigned char* block_buffer, unsigned block_size) +int handle_read(struct snapraid_handle* handle, struct snapraid_block* block, unsigned char* block_buffer, unsigned block_size) { ssize_t read_ret; data_off_t offset; @@ -177,27 +194,21 @@ int handle_read(int ret_on_error, struct snapraid_handle* handle, struct snaprai read_ret = pread(handle->f, block_buffer, read_size, offset); #else if (lseek(handle->f, offset, SEEK_SET) != offset) { - if (ret_on_error) - return ret_on_error; - fprintf(stderr, "Error seeking file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } read_ret = read(handle->f, block_buffer, read_size); #endif if (read_ret != read_size) { - if (ret_on_error) - return ret_on_error; - fprintf(stderr, "Error reading file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } return read_size; } -void handle_write(struct snapraid_handle* handle, struct snapraid_block* block, unsigned char* block_buffer, unsigned block_size) +int handle_write(struct snapraid_handle* handle, struct snapraid_block* block, unsigned char* block_buffer, unsigned block_size) { ssize_t write_ret; data_off_t offset; @@ -212,14 +223,16 @@ void handle_write(struct snapraid_handle* handle, struct snapraid_block* block, #else if (lseek(handle->f, offset, SEEK_SET) != offset) { fprintf(stderr, "Error seeking file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } write_ret = write(handle->f, block_buffer, write_size); #endif if (write_ret != write_size) { fprintf(stderr, "Error writing file '%s'. %s.\n", handle->path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } + + return 0; } diff --git a/handle.h b/handle.h index fdb8c208..ef53915b 100644 --- a/handle.h +++ b/handle.h @@ -29,31 +29,36 @@ struct snapraid_handle { }; /** - * Create a file. + * Closes a file, if it's different from the specified one. + */ +int handle_close_if_different(struct snapraid_handle* handle, struct snapraid_file* file); + +/** + * Creates a file. * The file is created if missing, and opening with write access. */ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file); /** - * Open a file. + * Opens a file. * The file is opened for reading. */ -int handle_open(int ret_on_error, struct snapraid_handle* handle, struct snapraid_file* file); +int handle_open(struct snapraid_handle* handle, struct snapraid_file* file); /** - * Close a file. + * Closes a file. */ -void handle_close(struct snapraid_handle* handle); +int handle_close(struct snapraid_handle* handle); /** * Read a block from a file. */ -int handle_read(int ret_on_error, struct snapraid_handle* handle, struct snapraid_block* block, unsigned char* block_buffer, unsigned block_size); +int handle_read(struct snapraid_handle* handle, struct snapraid_block* block, unsigned char* block_buffer, unsigned block_size); /** * Writes a block to a file. */ -void handle_write(struct snapraid_handle* handle, struct snapraid_block* block, unsigned char* block_buffer, unsigned block_size); +int handle_write(struct snapraid_handle* handle, struct snapraid_block* block, unsigned char* block_buffer, unsigned block_size); #endif diff --git a/parity.c b/parity.c index b4b9ea36..a7615dc4 100644 --- a/parity.c +++ b/parity.c @@ -58,13 +58,13 @@ int parity_create(const char* path, data_off_t size) f = open(path, O_RDWR | O_CREAT | O_BINARY, 0600); if (f == -1) { fprintf(stderr, "Error opening parity file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } ret = fstat(f, &st); if (ret != 0) { fprintf(stderr, "Error accessing parity file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + goto bail; } if (st.st_size < size) { @@ -81,13 +81,13 @@ int parity_create(const char* path, data_off_t size) } else { fprintf(stderr, "Error growing parity file '%s'. %s.\n", path, strerror(errno)); } - exit(EXIT_FAILURE); + goto bail; } } else if (st.st_size > size) { ret = ftruncate(f, size); if (ret != 0) { fprintf(stderr, "Error truncating parity file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + goto bail; } } @@ -96,14 +96,18 @@ int parity_create(const char* path, data_off_t size) ret = posix_fadvise(f, 0, 0, POSIX_FADV_SEQUENTIAL); if (ret != 0) { fprintf(stderr, "Error advising parity file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + goto bail; } #endif return f; + +bail: + close(f); + return -1; } -int parity_open(int ret_on_error, const char* path) +int parity_open(const char* path) { #if HAVE_POSIX_FADVISE int ret; @@ -112,26 +116,27 @@ int parity_open(int ret_on_error, const char* path) f = open(path, O_RDONLY | O_BINARY); if (f == -1) { - if (ret_on_error) - return -1; fprintf(stderr, "Error opening parity file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } #if HAVE_POSIX_FADVISE /* advise sequential access */ ret = posix_fadvise(f, 0, 0, POSIX_FADV_SEQUENTIAL); if (ret != 0) { - /* here we always abort on error, as advise is supposed to never fail */ fprintf(stderr, "Error advising parity file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + goto bail; } #endif return f; + +bail: + close(f); + return -1; } -void parity_sync(const char* path, int f) +int parity_sync(const char* path, int f) { #if HAVE_FSYNC int ret; @@ -142,30 +147,37 @@ void parity_sync(const char* path, int f) ret = fsync(f); if (ret != 0) { fprintf(stderr, "Error synching parity file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } #endif + + return 0; } -void parity_close(const char* path, int f) +int parity_close(const char* path, int f) { int ret; ret = close(f); if (ret != 0) { + /* This is a serious error, as it may be the result of a failed write */ + /* identified at later time. */ + /* In a normal filesystem (not NFS) it should never happen */ fprintf(stderr, "Error closing parity file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } + + return 0; } -void parity_write(const char* path, int f, block_off_t pos, unsigned char* block_buffer, unsigned block_size) +int parity_write(const char* path, int f, block_off_t pos, unsigned char* block_buffer, unsigned block_size) { ssize_t write_ret; data_off_t offset; offset = pos * (data_off_t)block_size; -#if HAVE_PWRITE +#if HAVE_PWRITE write_ret = pwrite(f, block_buffer, block_size, offset); #else if (lseek(f, offset, SEEK_SET) != offset) { @@ -174,7 +186,7 @@ void parity_write(const char* path, int f, block_off_t pos, unsigned char* block } else { fprintf(stderr, "Error seeking file '%s'. %s.\n", path, strerror(errno)); } - exit(EXIT_FAILURE); + return -1; } write_ret = write(f, block_buffer, block_size); @@ -185,40 +197,32 @@ void parity_write(const char* path, int f, block_off_t pos, unsigned char* block } else { fprintf(stderr, "Error writing file '%s'. %s.\n", path, strerror(errno)); } - exit(EXIT_FAILURE); + return -1; } + + return 0; } -int parity_read(int ret_on_error, const char* path, int f, block_off_t pos, unsigned char* block_buffer, unsigned block_size) +int parity_read(const char* path, int f, block_off_t pos, unsigned char* block_buffer, unsigned block_size) { ssize_t read_ret; data_off_t offset; - /* if the file is not opened, return an error without trying */ - if (f == -1 && ret_on_error) - return -1; - offset = pos * (data_off_t)block_size; -#if HAVE_PREAD +#if HAVE_PREAD read_ret = pread(f, block_buffer, block_size, offset); #else if (lseek(f, offset, SEEK_SET) != offset) { - if (ret_on_error) - return ret_on_error; - fprintf(stderr, "Error seeking file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } read_ret = read(f, block_buffer, block_size); #endif if (read_ret != block_size) { - if (ret_on_error) - return ret_on_error; - fprintf(stderr, "Error reading file '%s'. %s.\n", path, strerror(errno)); - exit(EXIT_FAILURE); + return -1; } return block_size; diff --git a/parity.h b/parity.h index 3f05c1b9..2967050c 100644 --- a/parity.h +++ b/parity.h @@ -34,27 +34,27 @@ int parity_create(const char* path, data_off_t size); /** * Opens an already existing parity file. */ -int parity_open(int ret_on_error, const char* path); +int parity_open(const char* path); /** * Flushes the parity file in the disk. */ -void parity_sync(const char* path, int f); +int parity_sync(const char* path, int f); /** * Closes the parity file. */ -void parity_close(const char* path, int f); +int parity_close(const char* path, int f); /** * Read a block from the parity file. */ -int parity_read(int ret_on_error, const char* parity_path, int parity_f, block_off_t pos, unsigned char* block_buffer, unsigned block_size); +int parity_read(const char* parity_path, int parity_f, block_off_t pos, unsigned char* block_buffer, unsigned block_size); /** * Writes a block in the parity file. */ -void parity_write(const char* parity_path, int parity_f, block_off_t pos, unsigned char* block_buffer, unsigned block_size); +int parity_write(const char* parity_path, int parity_f, block_off_t pos, unsigned char* block_buffer, unsigned block_size); #endif diff --git a/scan.c b/scan.c index cfe3d8f1..e87a0c03 100644 --- a/scan.c +++ b/scan.c @@ -117,7 +117,7 @@ static void scan_file(struct snapraid_scan* scan, struct snapraid_state* state, exit(EXIT_FAILURE); } } - + /* remove and reinsert it */ ++scan->count_change; --scan->count_insert; diff --git a/snapraid.d b/snapraid.d index 4be24e32..a5827b67 100644 --- a/snapraid.d +++ b/snapraid.d @@ -252,8 +252,8 @@ Options -s, --start BLOCK Starts the processing from the specified - block number. It could be useful to easy retry to fix - some specific block, in case of a damaged disk. + block number. It could be useful to easy retry to check or + fix some specific block, in case of a damaged disk. -Z, --force-zero Forces the insecure operation of synching a file with zero diff --git a/snapraid.html b/snapraid.html index 444e4bd0..7368b74a 100644 --- a/snapraid.html +++ b/snapraid.html @@ -391,8 +391,8 @@ the file `/etc/snapraid.conf'. -s, --start BLOCK Starts the processing from the specified -block number. It could be useful to easy retry to fix -some specific block, in case of a damaged disk. +block number. It could be useful to easy retry to check or +fix some specific block, in case of a damaged disk. diff --git a/snapraid.txt b/snapraid.txt index fb8f1227..62b06a80 100644 --- a/snapraid.txt +++ b/snapraid.txt @@ -277,8 +277,8 @@ For example: -s, --start BLOCK Starts the processing from the specified - block number. It could be useful to easy retry to fix - some specific block, in case of a damaged disk. + block number. It could be useful to easy retry to check or + fix some specific block, in case of a damaged disk. -Z, --force-zero Forces the insecure operation of synching a file with zero diff --git a/state.c b/state.c index ac3fe13a..f0c7370c 100644 --- a/state.c +++ b/state.c @@ -513,7 +513,7 @@ int state_progress(time_t* start, time_t* last, block_off_t blockpos, block_off_ /* stop if requested */ if (global_interrupt) { - printf("\rStopping for interruption%s\n", PROGRESS_CLEAR); + printf("\n"); return 1; } diff --git a/sync.c b/sync.c index 2cb09012..d9c0a4ec 100644 --- a/sync.c +++ b/sync.c @@ -38,6 +38,7 @@ static void state_sync_process(struct snapraid_state* state, int parity_f, block data_off_t count_block; time_t start; time_t last; + int ret; block_buffer = malloc_nofail(state->block_size); xor_buffer = malloc_nofail(state->block_size); @@ -56,6 +57,7 @@ static void state_sync_process(struct snapraid_state* state, int parity_f, block for(i=blockstart;ifile); + ret = handle_close_if_different(&handle[j], block->file); + if (ret == -1) { + fprintf(stderr, "WARNING! Without an accessible data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Stopping at block %u\n", i); + goto bail; + } - read_size = handle_read(0, &handle[j], block, block_buffer, state->block_size); + ret = handle_open(&handle[j], block->file); + if (ret == -1) { + fprintf(stderr, "WARNING! Without an accessible data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Stopping at block %u\n", i); + goto bail; + } + + read_size = handle_read(&handle[j], block, block_buffer, state->block_size); + if (read_size == -1) { + fprintf(stderr, "WARNING! Without an accessible data disk, it isn't possible to sync.\n"); + fprintf(stderr, "Stopping at block %u\n", i); + goto bail; + } /* now compute the hash */ md5_init(&md5); @@ -97,15 +116,14 @@ static void state_sync_process(struct snapraid_state* state, int parity_f, block /* compare the hash */ if (memcmp(hash, block->hash, HASH_MAX) != 0) { fprintf(stderr, "%u: Data error for file %s at position %u\n", i, block->file->sub, block_file_pos(block)); + fprintf(stderr, "WARNING! With errors in the data disk it isn't possible to sync.\n"); fprintf(stderr, "Stopping to allow recovery. Try with 'snapraid -s %u fix'\n", i); - exit(EXIT_FAILURE); + goto bail; } } else { - /* copy the hash */ + /* copy the hash, but doesn't mark the block as hashed */ + /* this allow on error to do not save the failed computation */ memcpy(block->hash, hash, HASH_MAX); - - /* mark the block as hashed */ - block->is_hashed = 1; } /* compute the parity */ @@ -115,20 +133,43 @@ static void state_sync_process(struct snapraid_state* state, int parity_f, block } /* write the parity */ - parity_write(state->parity, parity_f, i, xor_buffer, state->block_size); + ret = parity_write(state->parity, parity_f, i, xor_buffer, state->block_size); + if (ret == -1) { + fprintf(stderr, "WARNING! Without an accessible parity file, it isn't possible to sync.\n"); + fprintf(stderr, "Stopping at block %u\n", i); + goto bail; + } + + /* for each disk, mark the blocks as processed */ + for(j=0;jis_hashed = 1; + } /* count the number of processed block */ ++count_block; /* progress */ - if (state_progress(&start, &last, i, blockmax, count_block, count_size)) + if (state_progress(&start, &last, i, blockmax, count_block, count_size)) { + printf("Stopping for interruption at block %u\n", i); break; + } } printf("%u%% completed, %u MB processed\n", i * 100 / blockmax, (unsigned)(count_size / (1024*1024))); +bail: for(j=0;jblock_size; if (blockstart > blockmax) { - fprintf(stderr, "The specified starting block %u is bigger than the parity size %u.\n", blockstart, blockmax); + fprintf(stderr, "Error in the starting block %u. It's bigger than the parity size %u.\n", blockstart, blockmax); exit(EXIT_FAILURE); } pathcpy(path, sizeof(path), state->parity); f = parity_create(path, size); + if (f == -1) { + fprintf(stderr, "WARNING! Without an accessible parity file, it isn't possible to sync.\n"); + exit(EXIT_FAILURE); + } /* skip degenerated cases of empty parity, or skipping all */ if (blockstart < blockmax) { state_sync_process(state, f, blockstart, blockmax); - } else { - printf("Nothing to do\n"); } - parity_sync(path, f); - - parity_close(path, f); + ret = parity_sync(path, f); + if (ret == -1) { + fprintf(stderr, "WARNING! A 'snapraid check' command is highly suggested.\n"); + exit(EXIT_FAILURE); + } + + ret = parity_close(path, f); + if (ret == -1) { + fprintf(stderr, "WARNING! A 'snapraid check' command is highly suggested.\n"); + exit(EXIT_FAILURE); + } }