Better error management

This commit is contained in:
Andrea Mazzoleni 2011-03-18 22:38:11 +01:00
parent a30c93024a
commit f443a7f089
13 changed files with 272 additions and 138 deletions

View file

@ -5,6 +5,7 @@ SnapRAID HISTORY
==========
* Exclusion list of files and directories
* More automatic tests
* Better error management
* Better documentation

1
TODO
View file

@ -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.

112
check.c
View file

@ -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;j<diskmax;++j) {
ret = handle_close(&handle[j]);
if (ret == -1) {
if (fix) {
fprintf(stderr, "WARNING! A 'snapraid check' command is highly suggested.\n");
/* continue, as we are already exiting */
}
}
}
if (error || recovered_error || unrecoverable_error) {
if (error)
printf("%u read errors\n", error);
printf("%u read/data errors\n", error);
else
printf("No read errors\n");
printf("No read/data errors\n");
if (fix) {
if (recovered_error)
printf("%u recovered errors\n", recovered_error);
@ -264,15 +305,15 @@ static int state_check_process(int ret_on_error, struct snapraid_state* state, i
printf("No error\n");
}
for(j=0;j<diskmax;++j) {
handle_close(&handle[j]);
}
free(handle);
free(block_buffer);
free(xor_buffer);
return unrecoverable_error != 0 ? ret_on_error : 0;
/* signal if there are unrecoverable errors */
if (unrecoverable_error != 0)
return -1;
return 0;
}
void state_check(struct snapraid_state* state, int fix, block_off_t blockstart)
@ -292,33 +333,52 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart)
size = blockmax * (data_off_t)state->block_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);
}
}
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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

2
scan.c
View file

@ -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;

View file

@ -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

View file

@ -391,8 +391,8 @@ the file `/etc/snapraid.conf'.
-s, --start BLOCK
</strong></td></tr><tr><td>
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.
</td></tr>
</table>
<table width="100%" border="0" cellspacing="0" cellpadding="2">

View file

@ -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

View file

@ -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;
}

84
sync.c
View file

@ -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;i<blockmax;++i) {
int unhashed;
int ret;
/* for each disk, search for an unhashed block */
unhashed = 0;
@ -84,9 +86,26 @@ static void state_sync_process(struct snapraid_state* state, int parity_f, block
if (!block)
continue;
handle_open(0, &handle[j], block->file);
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;j<diskmax;++j) {
struct snapraid_block* block;
block = disk_block_get(handle[j].disk, i);
if (!block)
continue;
block->is_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;j<diskmax;++j) {
handle_close(&handle[j]);
ret = handle_close(&handle[j]);
if (ret == -1) {
fprintf(stderr, "WARNING! A 'snapraid check' command is highly suggested.\n");
/* continue, as we are already exiting */
}
}
free(handle);
@ -141,6 +182,7 @@ void state_sync(struct snapraid_state* state, block_off_t blockstart)
char path[PATH_MAX];
block_off_t blockmax;
data_off_t size;
int ret;
int f;
printf("Syncing...\n");
@ -150,22 +192,32 @@ void state_sync(struct snapraid_state* state, block_off_t blockstart)
size = blockmax * (data_off_t)state->block_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);
}
}