mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 10:51:54 -04:00
Better performance in fix keeping track of which part of the files is not initialized.
This commit is contained in:
parent
59c7c7380c
commit
1dbd801dcb
8 changed files with 219 additions and 152 deletions
7
HISTORY
7
HISTORY
|
|
@ -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
67
check.c
|
|
@ -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
45
dry.c
|
|
@ -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 */
|
||||
|
|
|
|||
48
handle.c
48
handle.c
|
|
@ -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 */
|
||||
|
|
|
|||
1
handle.h
1
handle.h
|
|
@ -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
145
parity.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
19
parity.h
19
parity.h
|
|
@ -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
39
sync.c
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue