Add additional checks on parity size

Ensures that it's always aligned at the block size.
Also adds more comments about resizing process.
This commit is contained in:
Andrea Mazzoleni 2016-09-28 20:32:50 +02:00
parent 422d642591
commit 3bdc9b93ad
6 changed files with 61 additions and 33 deletions

View file

@ -1947,7 +1947,7 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
}
parity_ptr[l] = &parity[l];
ret = parity_create(parity_ptr[l], &state->parity[l], l, state->file_mode, state->opt.parity_limit_size);
ret = parity_create(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
/* LCOV_EXCL_START */
log_fatal("WARNING! Without an accessible %s file, it isn't possible to fix any error.\n", lev_name(l));
@ -1968,7 +1968,7 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
/* it may fail if the file doesn't exist, in this case we continue to check the files */
for (l = 0; l < state->level; ++l) {
parity_ptr[l] = &parity[l];
ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->opt.parity_limit_size);
ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
msg_status("No accessible %s file, only files will be checked.\n", lev_name(l));
/* continue anyway */

View file

@ -417,7 +417,7 @@ void state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t
/* open the file for reading */
/* it may fail if the file doesn't exist, in this case we continue to dry the files */
for (l = 0; l < state->level; ++l) {
ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->opt.parity_limit_size);
ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
/* LCOV_EXCL_START */
log_fatal("WARNING! Without an accessible %s file, it isn't possible to dry.\n", lev_name(l));

View file

@ -161,32 +161,25 @@ void parity_size(struct snapraid_parity_handle* handle, data_off_t* out_size)
unsigned s;
data_off_t size;
/* now compute the size */
/* now compute the size summing all the parity splits */
size = 0;
for (s = 0;s < handle->split_mac;++s) {
struct snapraid_split_handle* split = &handle->split_map[s];
/* check for validity */
if (split->st.st_size < 0)
break;
if (split->st.st_size < split->size) {
/* this is a size error, so report only up to this size */
/* but don't fail the function */
size += split->st.st_size;
break;
}
/* ignore instead size bigger than expected */
size += split->size;
}
*out_size = size;
}
int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, data_off_t limit_size)
int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, uint32_t block_size, data_off_t limit_size)
{
unsigned s;
data_off_t block_mask;
/* mask of bits used by the block size */
block_mask = ((data_off_t)block_size) - 1;
handle->level = level;
handle->split_mac = 0;
@ -225,11 +218,21 @@ int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_p
/**
* If the parity size is not yet set, set it now.
* This happens when expanding the number of parities.
* This happens when expanding the number of parities,
* or when upgrading from a content file that has not split->size data.
*/
if (split->size == PARITY_SIZE_INVALID)
if (split->size == PARITY_SIZE_INVALID) {
split->size = split->st.st_size;
/* ensure that the resulting size if block aligned */
if ((split->size & block_mask) != 0) {
/* LCOV_EXCL_START */
log_fatal("Error in preallocated size of parity file '%s' with size %llu and block %u .\n", split->path, split->size, block_size);
goto bail;
/* LCOV_EXCL_STOP */
}
}
ret = advise_open(&split->advise, split->f);
if (ret != 0) {
/* LCOV_EXCL_START */
@ -530,21 +533,26 @@ int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity*
data_off_t run;
if (is_fixed) {
/* if the required size is smaller, we have to reduce also the file */
/* ignoring the previous size */
if (size <= split->size) {
is_fixed = 0; /* not fixed anymore */
run = size;
/* mark it as not fixed anymore for the later check */
is_fixed = 0;
run = size; /* allocate only the needed size */
} else {
/* if the size cannot be changed, use the fixed one */
run = split->size;
/* in the < 11.0-38 BETA it was possible to get wrong split size */
if ((run & block_mask) != 0) {
/* LCOV_EXCL_START */
log_fatal("Invalid split '%s' size with extra '%llu' bytes.\n", split->path, run & block_mask);
log_fatal("Internal inconsistency in split '%s' size with extra '%llu' bytes.\n", split->path, run & block_mask);
return -1;
/* LCOV_EXCL_STOP */
}
}
} else {
/* otherwise tries to allocate all the needed remaining size */
run = size;
}
@ -563,6 +571,7 @@ int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity*
return -1;
/* LCOV_EXCL_STOP */
} else {
/* here it's possible to get less than the requested size */
run = split->st.st_size;
if ((run & block_mask) != 0) {
@ -572,8 +581,11 @@ int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity*
/* LCOV_EXCL_STOP */
}
size -= run;
/* store what we have allocated */
split->size = run;
/* decrease the remaining size */
size -= run;
}
}
@ -600,13 +612,17 @@ int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity*
return 0;
}
int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, data_off_t limit_size)
int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, uint32_t block_size, data_off_t limit_size)
{
unsigned s;
data_off_t block_mask;
handle->level = level;
handle->split_mac = 0;
/* mask of bits used by the block size */
block_mask = ((data_off_t)block_size) - 1;
for (s = 0;s < parity->split_mac;++s) {
struct snapraid_split_handle* split = &handle->split_map[s];
int ret;
@ -623,8 +639,10 @@ int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_par
split->f = open_noatime(split->path, flags);
if (split->f == -1) {
/* LCOV_EXCL_START */
log_fatal("Error opening parity file '%s'. %s.\n", split->path, strerror(errno));
goto bail;
/* LCOV_EXCL_STOP */
}
/* we have a valid file handle */
@ -641,11 +659,21 @@ int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_par
/**
* If the parity size is not yet set, set it now.
* This happens when expanding the number of parities.
* This happens when expanding the number of parities,
* or when upgrading from a content file that has not split->size data.
*/
if (split->size == PARITY_SIZE_INVALID)
if (split->size == PARITY_SIZE_INVALID) {
split->size = split->st.st_size;
/* ensure that the resulting size if block aligned */
if ((split->size & block_mask) != 0) {
/* LCOV_EXCL_START */
log_fatal("Error in preallocated size of parity file '%s' with size %llu and block %u .\n", split->path, split->size, block_size);
goto bail;
/* LCOV_EXCL_STOP */
}
}
ret = advise_open(&split->advise, split->f);
if (ret != 0) {
/* LCOV_EXCL_START */

View file

@ -88,7 +88,7 @@ void parity_overflow(struct snapraid_state* state, data_off_t size);
* Create the parity file.
* \param out_size Return the size of the parity file.
*/
int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, data_off_t limit_size);
int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, uint32_t block_size, data_off_t limit_size);
/**
* Change the parity size.
@ -97,16 +97,16 @@ int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_p
int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity* parity, int* is_modified, data_off_t size, uint32_t block_size, int skip_fallocate);
/**
* Get the size of opened parity file.
* Get the size of the parity.
*
* This function never fails as it returns the cached size.
* This returns the cached/expected version of the split sizes, and not the real file size.
*/
void parity_size(struct snapraid_parity_handle* handle, data_off_t* out_size);
/**
* Open an already existing parity file.
*/
int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, data_off_t limit_size);
int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, uint32_t block_size, data_off_t limit_size);
/**
* Flush the parity file in the disk.

View file

@ -854,7 +854,7 @@ int state_scrub(struct snapraid_state* state, int plan, int olderthan)
/* open the file for reading */
for (l = 0; l < state->level; ++l) {
ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->opt.parity_limit_size);
ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
/* LCOV_EXCL_START */
log_fatal("WARNING! Without an accessible %s file, it isn't possible to scrub.\n", lev_name(l));

View file

@ -1446,7 +1446,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
block_off_t parityblocks;
/* create the file and open for writing */
ret = parity_create(&parity_handle[l], &state->parity[l], l, state->file_mode, state->opt.parity_limit_size);
ret = parity_create(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
/* LCOV_EXCL_START */
log_fatal("WARNING! Without an accessible %s file, it isn't possible to sync.\n", lev_name(l));