Better performance in fix keeping track of which part of the files is not initialized.

This commit is contained in:
Andrea Mazzoleni 2011-10-09 07:51:25 +02:00
parent 59c7c7380c
commit 1dbd801dcb
8 changed files with 219 additions and 152 deletions

View file

@ -9,13 +9,18 @@ SnapRAID HISTORY
* If the content file is placed in a data disk, it's automatically excluded
from the sync process.
* Increased by one the minimum number of content files. Before it was only
a suggestion, but now it's a requirement in case you put them in data disks.
a suggestion, but now it's a requirement because you are allowed to put
content files in data disks.
* Added checks to ensure that data and parity disks are diffent, and to
correctly count the number of copies of "content" files in different disks.
* Removed the dependency of the 'disk' order specification in the configuration
file. The used order is now saved in the content file to avoid to damage the
dual parity in case the order is changed by the user.
It also allows to remove or add disks from the array when using a dual parity.
* Improved the 'fix' performance when a lot of files or the parity have to be
recreated from scratch.
* When getting unrecoverable errors, the printed log line now starts with
'unrecoverable:' instead of 'error:' to allow an easier identification.
1.6 2011/9 - THIS UPDATE IS HIGHLY RECOMMENDED!
===============================================

67
check.c
View file

@ -154,7 +154,7 @@ static int repair(struct snapraid_state* state, unsigned i, unsigned diskmax, st
return -1;
}
static int state_check_process(struct snapraid_state* state, int fix, int parity_f, int qarity_f, block_off_t blockstart, block_off_t blockmax)
static int state_check_process(struct snapraid_state* state, int fix, struct snapraid_parity* parity, struct snapraid_parity* qarity, block_off_t blockstart, block_off_t blockmax)
{
struct snapraid_handle* handle;
unsigned diskmax;
@ -396,8 +396,8 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
buffer_zero = buffer[buffermax-1];
/* read the parity */
if (parity_f != -1) {
ret = parity_read(state->parity, parity_f, i, buffer_parity, state->block_size);
if (parity) {
ret = parity_read(parity, i, buffer_parity, state->block_size);
if (ret == -1) {
buffer_parity = 0; /* no parity to use */
@ -410,8 +410,8 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
/* read the qarity */
if (state->level >= 2) {
if (qarity_f != -1) {
ret = parity_read(state->qarity, qarity_f, i, buffer_qarity, state->block_size);
if (qarity) {
ret = parity_read(qarity, i, buffer_qarity, state->block_size);
if (ret == -1) {
buffer_qarity = 0; /* no qarity to use */
@ -439,7 +439,7 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
/* print a list of all the errors in files */
for(j=0;j<failed_count;++j) {
fprintf(stderr, "error:%u:%s:%s: Unrecoverable error at position %u\n", i, failed[j].handle->disk->name, block_file_get(failed[j].block)->sub, block_file_pos(failed[j].block));
fprintf(stderr, "unrecoverable:%u:%s:%s: Unrecoverable error at position %u\n", i, failed[j].handle->disk->name, block_file_get(failed[j].block)->sub, block_file_pos(failed[j].block));
}
} else {
/* check parity and q-parity only if all the blocks have it computed */
@ -499,8 +499,8 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
/* for blocks that are going to have it computed in the sync completion */
if (all_parity) {
/* update the parity */
if (buffer_parity == 0 && parity_f != -1) {
ret = parity_write(state->parity, parity_f, i, buffer[diskmax], state->block_size);
if (buffer_parity == 0 && parity) {
ret = parity_write(parity, i, buffer[diskmax], state->block_size);
if (ret == -1) {
/* we do not use DANGER because it could be ENOSPC which is not always correctly reported */
fprintf(stderr, "WARNING! Without a working Parity disk, it isn't possible to fix errors on it.\n");
@ -515,8 +515,8 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
/* update the qarity */
if (state->level >= 2) {
if (buffer_qarity == 0 && qarity_f != -1) {
ret = parity_write(state->qarity, qarity_f, i, buffer[diskmax + 1], state->block_size);
if (buffer_qarity == 0 && qarity) {
ret = parity_write(qarity, i, buffer[diskmax + 1], state->block_size);
if (ret == -1) {
/* we do not use DANGER because it could be ENOSPC which is not always correctly reported */
fprintf(stderr, "WARNING! Without a working Q-Parity disk, it isn't possible to fix errors on it.\n");
@ -758,13 +758,13 @@ bail:
void state_check(struct snapraid_state* state, int fix, block_off_t blockstart, block_off_t blockcount)
{
char parity_path[PATH_MAX];
char qarity_path[PATH_MAX];
block_off_t blockmax;
data_off_t size;
int ret;
int parity_f;
int qarity_f;
struct snapraid_parity parity;
struct snapraid_parity qarity;
struct snapraid_parity* parity_ptr;
struct snapraid_parity* qarity_ptr;
unsigned error;
if (fix)
@ -785,44 +785,47 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart,
blockmax = blockstart + blockcount;
}
pathcpy(parity_path, sizeof(parity_path), state->parity);
pathcpy(qarity_path, sizeof(qarity_path), state->qarity);
if (fix) {
/* if fixing, create the file and open for writing */
/* if it fails, we cannot continue */
parity_f = parity_create(parity_path, size);
if (parity_f == -1) {
parity_ptr = &parity;
ret = parity_create(parity_ptr, state->parity, size);
if (ret == -1) {
fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to fix any error.\n");
exit(EXIT_FAILURE);
}
if (state->level >= 2) {
qarity_f = parity_create(qarity_path, size);
if (qarity_f == -1) {
qarity_ptr = &qarity;
ret = parity_create(qarity_ptr, state->qarity, size);
if (ret == -1) {
fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to fix any error.\n");
exit(EXIT_FAILURE);
}
} else {
qarity_f = -1;
qarity_ptr = 0;
}
} else {
/* if checking, open the file for reading */
/* it may fail if the file doesn't exist, in this case we continue to check the files */
parity_f = parity_open(parity_path);
if (parity_f == -1) {
parity_ptr = &parity;
ret = parity_open(parity_ptr, state->parity);
if (ret == -1) {
printf("No accessible Parity file, only files will be checked.\n");
/* continue anyway */
parity_ptr = 0;
}
if (state->level >= 2) {
qarity_f = parity_open(qarity_path);
if (qarity_f == -1) {
qarity_ptr = &qarity;
ret = parity_open(qarity_ptr, state->qarity);
if (ret == -1) {
printf("No accessible Q-Parity file, only files will be checked.\n");
/* continue anyway */
qarity_ptr = 0;
}
} else {
qarity_f = -1;
qarity_ptr = 0;
}
}
@ -830,7 +833,7 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart,
/* skip degenerated cases of empty parity, or skipping all */
if (blockstart < blockmax) {
ret = state_check_process(state, fix, parity_f, qarity_f, blockstart, blockmax);
ret = state_check_process(state, fix, parity_ptr, qarity_ptr, blockstart, blockmax);
if (ret == -1) {
++error;
/* continue, as we are already exiting */
@ -838,8 +841,8 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart,
}
/* try to close only if opened */
if (parity_f != -1) {
ret = parity_close(parity_path, parity_f);
if (parity_ptr) {
ret = parity_close(parity_ptr);
if (ret == -1) {
fprintf(stderr, "DANGER! Unexpected close error in Parity disk.\n");
++error;
@ -848,8 +851,8 @@ void state_check(struct snapraid_state* state, int fix, block_off_t blockstart,
}
if (state->level >= 2) {
if (qarity_f != -1) {
ret = parity_close(qarity_path, qarity_f);
if (qarity_ptr) {
ret = parity_close(qarity_ptr);
if (ret == -1) {
fprintf(stderr, "DANGER! Unexpected close error in Q-Parity disk.\n");
++error;

45
dry.c
View file

@ -26,7 +26,7 @@
/****************************************************************************/
/* dry */
static int state_dry_process(struct snapraid_state* state, int parity_f, int qarity_f, block_off_t blockstart, block_off_t blockmax)
static int state_dry_process(struct snapraid_state* state, struct snapraid_parity* parity, struct snapraid_parity* qarity, block_off_t blockstart, block_off_t blockmax)
{
struct snapraid_handle* handle;
unsigned diskmax;
@ -89,8 +89,8 @@ static int state_dry_process(struct snapraid_state* state, int parity_f, int qar
}
/* read the parity */
if (parity_f != -1) {
ret = parity_read(state->parity, parity_f, i, buffer, state->block_size);
if (parity) {
ret = parity_read(parity, i, buffer, state->block_size);
if (ret == -1) {
fprintf(stderr, "error:%u:parity: Read error\n", i);
++error;
@ -99,8 +99,8 @@ static int state_dry_process(struct snapraid_state* state, int parity_f, int qar
/* read the qarity */
if (state->level >= 2) {
if (qarity_f != -1) {
ret = parity_read(state->qarity, qarity_f, i, buffer, state->block_size);
if (qarity) {
ret = parity_read(qarity, i, buffer, state->block_size);
if (ret == -1) {
fprintf(stderr, "error:%u:qarity: Read error\n", i);
++error;
@ -146,12 +146,12 @@ bail:
void state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t blockcount)
{
char parity_path[PATH_MAX];
char qarity_path[PATH_MAX];
block_off_t blockmax;
int ret;
int parity_f;
int qarity_f;
struct snapraid_parity parity;
struct snapraid_parity qarity;
struct snapraid_parity* parity_ptr;
struct snapraid_parity* qarity_ptr;
unsigned error;
printf("Drying...\n");
@ -168,32 +168,33 @@ void state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t
blockmax = blockstart + blockcount;
}
pathcpy(parity_path, sizeof(parity_path), state->parity);
pathcpy(qarity_path, sizeof(qarity_path), state->qarity);
/* open the file for reading */
/* it may fail if the file doesn't exist, in this case we continue to dry the files */
parity_f = parity_open(parity_path);
if (parity_f == -1) {
parity_ptr = &parity;
ret = parity_open(parity_ptr, state->parity);
if (ret == -1) {
printf("No accessible Parity file.\n");
/* continue anyway */
parity_ptr = 0;
}
if (state->level >= 2) {
qarity_f = parity_open(qarity_path);
if (qarity_f == -1) {
qarity_ptr = &qarity;
ret = parity_open(qarity_ptr, state->qarity);
if (ret == -1) {
printf("No accessible Q-Parity file.\n");
/* continue anyway */
qarity_ptr = 0;
}
} else {
qarity_f = -1;
qarity_ptr = 0;
}
error = 0;
/* skip degenerated cases of empty parity, or skipping all */
if (blockstart < blockmax) {
ret = state_dry_process(state, parity_f, qarity_f, blockstart, blockmax);
ret = state_dry_process(state, parity_ptr, qarity_ptr, blockstart, blockmax);
if (ret == -1) {
++error;
/* continue, as we are already exiting */
@ -201,8 +202,8 @@ void state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t
}
/* try to close only if opened */
if (parity_f != -1) {
ret = parity_close(parity_path, parity_f);
if (parity_ptr) {
ret = parity_close(parity_ptr);
if (ret == -1) {
++error;
/* continue, as we are already exiting */
@ -210,8 +211,8 @@ void state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t
}
if (state->level >= 2) {
if (qarity_f != -1) {
ret = parity_close(qarity_path, qarity_f);
if (qarity_ptr) {
ret = parity_close(qarity_ptr);
if (ret == -1) {
++error;
/* continue, as we are already exiting */

View file

@ -94,6 +94,7 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file)
/* invalidate for error */
handle->file = 0;
handle->f = -1;
handle->valid_size = 0;
fprintf(stderr, "Error opening file '%s'. %s.\n", handle->path, strerror(errno));
return -1;
@ -109,25 +110,13 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file)
return -1;
}
if (handle->st.st_size < file->size) {
#if HAVE_POSIX_FALLOCATE
/* allocate real space */
ret = posix_fallocate(handle->f, 0, file->size);
#else
/* allocate using a sparse file */
ret = ftruncate(handle->f, file->size);
#endif
if (ret != 0) {
if (errno == ENOSPC) {
fprintf(stderr, "Failed to grow file '%s' due lack of space.\n", handle->path);
} else if (errno == EACCES) {
fprintf(stderr, "Failed to grow file '%s' for missing write permission.\n", handle->path);
} else {
fprintf(stderr, "Error growing file '%s'. %s.\n", handle->path, strerror(errno));
}
return -1;
}
} else if (handle->st.st_size > file->size) {
/* get the size of the exising data */
handle->valid_size = handle->st.st_size;
/* Here we only truncate the file and we don't grow it */
/* as allocating real space for it would imply a too big performance drop, */
/* and allocating sparse space wouldn't improve the safety of subsequent writes. */
if (handle->st.st_size > file->size) {
ret = ftruncate(handle->f, file->size);
if (ret != 0) {
if (errno == EACCES) {
@ -137,6 +126,9 @@ int handle_create(struct snapraid_handle* handle, struct snapraid_file* file)
}
return -1;
}
/* adjust the size to the truncated size */
handle->valid_size = file->size;
}
#if HAVE_POSIX_FADVISE
@ -175,6 +167,7 @@ int handle_open(struct snapraid_handle* handle, struct snapraid_file* file)
/* invalidate for error */
handle->file = 0;
handle->f = -1;
handle->valid_size = 0;
fprintf(stderr, "Error opening file '%s'. %s.\n", handle->path, strerror(errno));
return -1;
@ -190,6 +183,9 @@ int handle_open(struct snapraid_handle* handle, struct snapraid_file* file)
return -1;
}
/* get the size of the exising data */
handle->valid_size = handle->st.st_size;
#if HAVE_POSIX_FADVISE
/* advise sequential access */
ret = posix_fadvise(handle->f, 0, 0, POSIX_FADV_SEQUENTIAL);
@ -213,6 +209,7 @@ int handle_close(struct snapraid_handle* handle)
/* invalidate for error */
handle->file = 0;
handle->f = -1;
handle->valid_size = 0;
fprintf(stderr, "Error closing file '%s'. %s.\n", handle->file->sub, strerror(errno));
return -1;
@ -222,6 +219,7 @@ int handle_close(struct snapraid_handle* handle)
/* reset the descriptor */
handle->file = 0;
handle->f = -1;
handle->valid_size = 0;
return 0;
}
@ -234,6 +232,12 @@ int handle_read(struct snapraid_handle* handle, struct snapraid_block* block, un
offset = block_file_pos(block) * (data_off_t)block_size;
/* check if we are going to read only not initialized data */
if (offset >= handle->valid_size) {
fprintf(stderr, "Reading missing data from file '%s' at offset %"PRIu64".\n", handle->path, offset);
return -1;
}
read_size = block_file_size(block, block_size);
#if HAVE_PREAD
@ -293,6 +297,11 @@ int handle_write(struct snapraid_handle* handle, struct snapraid_block* block, u
return -1;
}
/* adjust the size of the valid data */
if (handle->valid_size < offset + write_size) {
handle->valid_size = offset + write_size;
}
/* Here doesn't make sense to call posix_fadvise(..., POSIX_FADV_DONTNEED) because */
/* at this time the data is still in not yet written and it cannot be discharged. */
@ -346,6 +355,7 @@ struct snapraid_handle* handle_map(struct snapraid_state* state, unsigned* handl
handle[j].disk = 0;
handle[j].file = 0;
handle[j].f = -1;
handle[j].valid_size = 0;
}
/* set the vector */

View file

@ -29,6 +29,7 @@ struct snapraid_handle {
struct snapraid_file* file; /**< File opened. */
int f; /**< Handle of the file. */
struct stat st; /**< Stat info of the opened file. */
data_off_t valid_size; /**< Size of the valid data. */
};
/**

145
parity.c
View file

@ -49,98 +49,120 @@ block_off_t parity_resize(struct snapraid_state* state)
return parity_block;
}
int parity_create(const char* path, data_off_t size)
int parity_create(struct snapraid_parity* parity, const char* path, data_off_t size)
{
struct stat st;
int ret;
int f;
pathcpy(parity->path, sizeof(parity->path), path);
/* opening in sequential mode in Windows */
f = open(path, O_RDWR | O_CREAT | O_BINARY | O_SEQUENTIAL, 0600);
if (f == -1) {
fprintf(stderr, "Error opening parity file '%s'. %s.\n", path, strerror(errno));
parity->f = open(parity->path, O_RDWR | O_CREAT | O_BINARY | O_SEQUENTIAL, 0600);
if (parity->f == -1) {
fprintf(stderr, "Error opening parity file '%s'. %s.\n", parity->path, strerror(errno));
return -1;
}
ret = fstat(f, &st);
/* get the stat info */
ret = fstat(parity->f, &parity->st);
if (ret != 0) {
fprintf(stderr, "Error accessing parity file '%s'. %s.\n", path, strerror(errno));
fprintf(stderr, "Error accessing parity file '%s'. %s.\n", parity->path, strerror(errno));
goto bail;
}
if (st.st_size < size) {
/* get the size of the exising data */
parity->valid_size = parity->st.st_size;
if (parity->st.st_size < size) {
#if HAVE_POSIX_FALLOCATE
/* allocate real space */
ret = posix_fallocate(f, 0, size);
ret = posix_fallocate(parity->f, 0, size);
#else
/* allocate using a sparse file */
ret = ftruncate(f, size);
ret = ftruncate(parity->f, size);
#endif
if (ret != 0) {
if (errno == ENOSPC) {
fprintf(stderr, "Failed to grow parity file '%s' to size %"PRIu64" due lack of space.\n", path, size);
fprintf(stderr, "Failed to grow parity file '%s' to size %"PRIu64" due lack of space.\n", parity->path, size);
} else {
fprintf(stderr, "Error growing parity file '%s' to size %"PRIu64". Do you have enough space? %s.\n", path, size, strerror(errno));
fprintf(stderr, "Error growing parity file '%s' to size %"PRIu64". Do you have enough space? %s.\n", parity->path, size, strerror(errno));
}
goto bail;
}
} else if (st.st_size > size) {
ret = ftruncate(f, size);
} else if (parity->st.st_size > size) {
ret = ftruncate(parity->f, size);
if (ret != 0) {
fprintf(stderr, "Error truncating parity file '%s' to size %"PRIu64". %s.\n", path, size, strerror(errno));
fprintf(stderr, "Error truncating parity file '%s' to size %"PRIu64". %s.\n", parity->path, size, strerror(errno));
goto bail;
}
/* adjust the size to the truncated size */
parity->valid_size = size;
}
#if HAVE_POSIX_FADVISE
/* advise sequential access */
ret = posix_fadvise(f, 0, 0, POSIX_FADV_SEQUENTIAL);
ret = posix_fadvise(parity->f, 0, 0, POSIX_FADV_SEQUENTIAL);
if (ret != 0) {
fprintf(stderr, "Error advising parity file '%s'. %s.\n", path, strerror(errno));
fprintf(stderr, "Error advising parity file '%s'. %s.\n", parity->path, strerror(errno));
goto bail;
}
#endif
return f;
return 0;
bail:
close(f);
close(parity->f);
parity->f = -1;
parity->valid_size = 0;
return -1;
}
int parity_open(const char* path)
int parity_open(struct snapraid_parity* parity, const char* path)
{
#if HAVE_POSIX_FADVISE
int ret;
#endif
int f;
pathcpy(parity->path, sizeof(parity->path), path);
/* opening in sequential mode in Windows */
f = open(path, O_RDONLY | O_BINARY | O_SEQUENTIAL);
if (f == -1) {
fprintf(stderr, "Error opening parity file '%s'. %s.\n", path, strerror(errno));
parity->f = open(parity->path, O_RDONLY | O_BINARY | O_SEQUENTIAL);
if (parity->f == -1) {
fprintf(stderr, "Error opening parity file '%s'. %s.\n", parity->path, strerror(errno));
return -1;
}
/* get the stat info */
ret = fstat(parity->f, &parity->st);
if (ret != 0) {
fprintf(stderr, "Error accessing parity file '%s'. %s.\n", parity->path, strerror(errno));
goto bail;
}
/* get the size of the exising data */
parity->valid_size = parity->st.st_size;
#if HAVE_POSIX_FADVISE
/* advise sequential access */
ret = posix_fadvise(f, 0, 0, POSIX_FADV_SEQUENTIAL);
ret = posix_fadvise(parity->f, 0, 0, POSIX_FADV_SEQUENTIAL);
if (ret != 0) {
fprintf(stderr, "Error advising parity file '%s'. %s.\n", path, strerror(errno));
fprintf(stderr, "Error advising parity file '%s'. %s.\n", parity->path, strerror(errno));
goto bail;
}
#endif
return f;
return 0;
#if HAVE_POSIX_FADVISE
bail:
close(f);
close(parity->f);
parity->f = -1;
parity->valid_size = 0;
return -1;
#endif
}
int parity_sync(const char* path, int f)
int parity_sync(struct snapraid_parity* parity)
{
#if HAVE_FSYNC
int ret;
@ -148,9 +170,9 @@ int parity_sync(const char* path, int f)
/* Ensure that data changes are written to disk. */
/* This is required to ensure that parity is more updated than content */
/* in case of a system crash. */
ret = fsync(f);
ret = fsync(parity->f);
if (ret != 0) {
fprintf(stderr, "Error synching parity file '%s'. %s.\n", path, strerror(errno));
fprintf(stderr, "Error synching parity file '%s'. %s.\n", parity->path, strerror(errno));
return -1;
}
#endif
@ -158,23 +180,31 @@ int parity_sync(const char* path, int f)
return 0;
}
int parity_close(const char* path, int f)
int parity_close(struct snapraid_parity* parity)
{
int ret;
ret = close(f);
ret = close(parity->f);
if (ret != 0) {
/* invalidate for error */
parity->f = -1;
parity->valid_size = 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));
fprintf(stderr, "Error closing parity file '%s'. %s.\n", parity->path, strerror(errno));
return -1;
}
/* reset the descriptor */
parity->f = -1;
parity->valid_size = 0;
return 0;
}
int parity_write(const char* path, int f, block_off_t pos, unsigned char* block_buffer, unsigned block_size)
int parity_write(struct snapraid_parity* parity, block_off_t pos, unsigned char* block_buffer, unsigned block_size)
{
ssize_t write_ret;
data_off_t offset;
@ -182,57 +212,68 @@ int parity_write(const char* path, int f, block_off_t pos, unsigned char* block_
offset = pos * (data_off_t)block_size;
#if HAVE_PWRITE
write_ret = pwrite(f, block_buffer, block_size, offset);
write_ret = pwrite(parity->f, block_buffer, block_size, offset);
#else
if (lseek(f, offset, SEEK_SET) != offset) {
if (lseek(parity->f, offset, SEEK_SET) != offset) {
if (errno == ENOSPC) {
fprintf(stderr, "Failed to grow parity file '%s' due lack of space.\n", path);
fprintf(stderr, "Failed to grow parity file '%s' due lack of space.\n", parity->path);
} else {
fprintf(stderr, "Error seeking file '%s'. %s.\n", path, strerror(errno));
fprintf(stderr, "Error seeking file '%s'. %s.\n", parity->path, strerror(errno));
}
return -1;
}
write_ret = write(f, block_buffer, block_size);
write_ret = write(parity->f, block_buffer, block_size);
#endif
if (write_ret != (ssize_t)block_size) { /* conversion is safe because block_size is always small */
if (errno == ENOSPC) {
fprintf(stderr, "Failed to grow parity file '%s' due lack of space.\n", path);
fprintf(stderr, "Failed to grow parity file '%s' due lack of space.\n", parity->path);
} else {
fprintf(stderr, "Error writing file '%s'. %s.\n", path, strerror(errno));
fprintf(stderr, "Error writing file '%s'. %s.\n", parity->path, strerror(errno));
}
return -1;
}
/* adjust the size of the valid data */
if (parity->valid_size < offset + block_size) {
parity->valid_size = offset + block_size;
}
/* Here doesn't make sense to call posix_fadvise(..., POSIX_FADV_DONTNEED) because */
/* at this time the data is still in not yet written and it cannot be discharged. */
return 0;
}
int parity_read(const char* path, int f, block_off_t pos, unsigned char* block_buffer, unsigned block_size)
int parity_read(struct snapraid_parity* parity, block_off_t pos, unsigned char* block_buffer, unsigned block_size)
{
ssize_t read_ret;
data_off_t offset;
offset = pos * (data_off_t)block_size;
#if HAVE_PREAD
read_ret = pread(f, block_buffer, block_size, offset);
#else
if (lseek(f, offset, SEEK_SET) != offset) {
fprintf(stderr, "Error seeking file '%s' at offset %"PRIu64". %s.\n", path, offset, strerror(errno));
/* check if we are going to read only not initialized data */
if (offset >= parity->valid_size) {
fprintf(stderr, "Reading missing data from file '%s' at offset %"PRIu64".\n", parity->path, offset);
return -1;
}
read_ret = read(f, block_buffer, block_size);
#if HAVE_PREAD
read_ret = pread(parity->f, block_buffer, block_size, offset);
#else
if (lseek(parity->f, offset, SEEK_SET) != offset) {
fprintf(stderr, "Error seeking file '%s' at offset %"PRIu64". %s.\n", parity->path, offset, strerror(errno));
return -1;
}
read_ret = read(parity->f, block_buffer, block_size);
#endif
if (read_ret < 0) {
fprintf(stderr, "Error reading file '%s' at offset %"PRIu64". %s.\n", path, offset, strerror(errno));
fprintf(stderr, "Error reading file '%s' at offset %"PRIu64". %s.\n", parity->path, offset, strerror(errno));
return -1;
}
if (read_ret != (ssize_t)block_size) { /* signed conversion is safe because block_size is always small */
fprintf(stderr, "File '%s' is smaller than expected. Read %d bytes instead of %d at offset %"PRIu64".\n", path, (int)read_ret, block_size, offset);
fprintf(stderr, "File '%s' is smaller than expected. Read %d bytes instead of %d at offset %"PRIu64".\n", parity->path, (int)read_ret, block_size, offset);
return -1;
}

View file

@ -21,6 +21,13 @@
/****************************************************************************/
/* parity */
struct snapraid_parity {
char path[PATH_MAX]; /**< Path of the file. */
int f; /**< Handle of the file. */
struct stat st; /**< Stat info of the opened file. */
data_off_t valid_size; /**< Size of the valid data. */
};
/**
* Computes the size of the parity data in number of blocks.
*/
@ -29,32 +36,32 @@ block_off_t parity_resize(struct snapraid_state* state);
/**
* Creates the parity file.
*/
int parity_create(const char* path, data_off_t size);
int parity_create(struct snapraid_parity* parity, const char* path, data_off_t size);
/**
* Opens an already existing parity file.
*/
int parity_open(const char* path);
int parity_open(struct snapraid_parity* parity, const char* path);
/**
* Flushes the parity file in the disk.
*/
int parity_sync(const char* path, int f);
int parity_sync(struct snapraid_parity* parity);
/**
* Closes the parity file.
*/
int parity_close(const char* path, int f);
int parity_close(struct snapraid_parity* parity);
/**
* Read a block from the parity file.
*/
int parity_read(const char* parity_path, int parity_f, block_off_t pos, unsigned char* block_buffer, unsigned block_size);
int parity_read(struct snapraid_parity* parity, block_off_t pos, unsigned char* block_buffer, unsigned block_size);
/**
* Writes a block in the parity file.
*/
int parity_write(const char* parity_path, int parity_f, block_off_t pos, unsigned char* block_buffer, unsigned block_size);
int parity_write(struct snapraid_parity* parity, block_off_t pos, unsigned char* block_buffer, unsigned block_size);
#endif

39
sync.c
View file

@ -27,7 +27,7 @@
/****************************************************************************/
/* sync */
static int state_sync_process(struct snapraid_state* state, int parity_f, int qarity_f, block_off_t blockstart, block_off_t blockmax)
static int state_sync_process(struct snapraid_state* state, struct snapraid_parity* parity, struct snapraid_parity* qarity, block_off_t blockstart, block_off_t blockmax)
{
struct snapraid_handle* handle;
unsigned diskmax;
@ -224,7 +224,7 @@ static int state_sync_process(struct snapraid_state* state, int parity_f, int qa
raid_gen(state->level, buffer, diskmax, state->block_size);
/* write the parity */
ret = parity_write(state->parity, parity_f, i, buffer[diskmax], state->block_size);
ret = parity_write(parity, i, buffer[diskmax], state->block_size);
if (ret == -1) {
fprintf(stderr, "DANGER! Write error in the Parity disk, it isn't possible to sync.\n");
printf("Stopping at block %u\n", i);
@ -234,7 +234,7 @@ static int state_sync_process(struct snapraid_state* state, int parity_f, int qa
/* write the qarity */
if (state->level >= 2) {
ret = parity_write(state->qarity, qarity_f, i, buffer[diskmax+1], state->block_size);
ret = parity_write(qarity, i, buffer[diskmax+1], state->block_size);
if (ret == -1) {
fprintf(stderr, "DANGER! Write error in the Q-Parity disk, it isn't possible to sync.\n");
printf("Stopping at block %u\n", i);
@ -291,13 +291,13 @@ bail:
int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t blockcount)
{
char parity_path[PATH_MAX];
char qarity_path[PATH_MAX];
block_off_t blockmax;
data_off_t size;
int ret;
int parity_f;
int qarity_f;
struct snapraid_parity parity;
struct snapraid_parity qarity;
struct snapraid_parity* parity_ptr;
struct snapraid_parity* qarity_ptr;
unsigned unrecoverable_error;
printf("Syncing...\n");
@ -315,45 +315,44 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
blockmax = blockstart + blockcount;
}
pathcpy(parity_path, sizeof(parity_path), state->parity);
pathcpy(qarity_path, sizeof(qarity_path), state->qarity);
/* create the file and open for writing */
parity_f = parity_create(parity_path, size);
if (parity_f == -1) {
parity_ptr = &parity;
ret = parity_create(parity_ptr, state->parity, size);
if (ret == -1) {
fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to sync.\n");
exit(EXIT_FAILURE);
}
if (state->level >= 2) {
qarity_f = parity_create(qarity_path, size);
if (qarity_f == -1) {
qarity_ptr = &qarity;
ret = parity_create(qarity_ptr, state->qarity, size);
if (ret == -1) {
fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to sync.\n");
exit(EXIT_FAILURE);
}
} else {
qarity_f = -1;
qarity_ptr = 0;
}
unrecoverable_error = 0;
/* skip degenerated cases of empty parity, or skipping all */
if (blockstart < blockmax) {
ret = state_sync_process(state, parity_f, qarity_f, blockstart, blockmax);
ret = state_sync_process(state, parity_ptr, qarity_ptr, blockstart, blockmax);
if (ret == -1) {
++unrecoverable_error;
/* continue, as we are already exiting */
}
}
ret = parity_sync(parity_path, parity_f);
ret = parity_sync(parity_ptr);
if (ret == -1) {
fprintf(stderr, "DANGER! Unexpected sync error in Parity disk.\n");
++unrecoverable_error;
/* continue, as we are already exiting */
}
ret = parity_close(parity_path, parity_f);
ret = parity_close(parity_ptr);
if (ret == -1) {
fprintf(stderr, "DANGER! Unexpected close error in Parity disk.\n");
++unrecoverable_error;
@ -361,14 +360,14 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
}
if (state->level >= 2) {
ret = parity_sync(qarity_path, qarity_f);
ret = parity_sync(qarity_ptr);
if (ret == -1) {
fprintf(stderr, "DANGER! Unexpected sync error in Q-Parity disk.\n");
++unrecoverable_error;
/* continue, as we are already exiting */
}
ret = parity_close(qarity_path, qarity_f);
ret = parity_close(qarity_ptr);
if (ret == -1) {
fprintf(stderr, "DANGER! Unexpected close error in Q-Parity disk.\n");
++unrecoverable_error;