diff --git a/HISTORY b/HISTORY index 57e33ec2..710e2414 100644 --- a/HISTORY +++ b/HISTORY @@ -1,8 +1,10 @@ SnapRAID HISTORY ================ -11.4 2018/12 +11.4 2019/05 ============ + * Avoid unnecessary parity read when fixing the parity itself. + This improves the 'fix' speed when a parity file is completely missing. * Removed a build warning about major/minor defined now in sys/sysmacros.h. 11.3 2018/11 diff --git a/cmdline/parity.c b/cmdline/parity.c index 6bfdbcd0..f585ba9b 100644 --- a/cmdline/parity.c +++ b/cmdline/parity.c @@ -184,6 +184,7 @@ int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_p handle->level = level; handle->split_mac = 0; + handle->has_write_access = 0; for (s = 0; s < parity->split_mac; ++s) { struct snapraid_split_handle* split = &handle->split_map[s]; @@ -217,6 +218,9 @@ int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_p /* LCOV_EXCL_STOP */ } + /* the initial valid size is the size on disk */ + split->valid_size = split->st.st_size; + /** * If the parity size is not yet set, set it now. * This happens when expanding the number of parities, @@ -528,6 +532,10 @@ static int parity_handle_chsize(struct snapraid_split_handle* split, data_off_t /* LCOV_EXCL_STOP */ } + /* if we shrink, update the valid size, but don't update when growing */ + if (split->valid_size > split->st.st_size) + split->valid_size = split->st.st_size; + return 0; } @@ -659,6 +667,7 @@ int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_par handle->level = level; handle->split_mac = 0; + handle->has_write_access = 0; /* mask of bits used by the block size */ block_mask = ((data_off_t)block_size) - 1; @@ -697,6 +706,9 @@ int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_par /* LCOV_EXCL_STOP */ } + /* the initial valid size is the size on disk */ + split->valid_size = split->st.st_size; + /** * If the parity size is not yet set, set it now. * This happens when expanding the number of parities, @@ -770,6 +782,19 @@ int parity_close(struct snapraid_parity_handle* handle) struct snapraid_split_handle* split = &handle->split_map[s]; int ret; + if (handle->has_write_access) { + /* truncate any data that we know it's not valid */ + ret = ftruncate(split->f, split->valid_size); + if (ret != 0) { + /* LCOV_EXCL_START */ + log_fatal("Error truncating the parity file '%s' to size %" PRIu64 ". %s.\n", split->path, split->valid_size, strerror(errno)); + f_ret = -1; + /* LCOV_EXCL_STOP */ + + /* continue to close the others */ + } + } + ret = close(split->f); if (ret != 0) { /* LCOV_EXCL_START */ @@ -826,6 +851,10 @@ int parity_write(struct snapraid_parity_handle* handle, block_off_t pos, unsigne /* LCOV_EXCL_STOP */ } + /* update the valid range */ + if (split->valid_size < offset + block_size) + split->valid_size = offset + block_size; + write_ret = pwrite(split->f, block_buffer, block_size, offset); if (write_ret != (ssize_t)block_size) { /* conversion is safe because block_size is always small */ /* LCOV_EXCL_START */ @@ -867,6 +896,14 @@ int parity_read(struct snapraid_parity_handle* handle, block_off_t pos, unsigned /* LCOV_EXCL_STOP */ } + /* if read is completely out of the valid range */ + if (offset >= split->valid_size) { + /* LCOV_EXCL_START */ + out("Missing data reading file '%s' at offset %" PRIu64 " for size %u.\n", split->path, offset, block_size); + return -1; + /* LCOV_EXCL_STOP */ + } + count = 0; do { read_ret = pread(split->f, block_buffer + count, block_size - count, offset + count); diff --git a/cmdline/parity.h b/cmdline/parity.h index 056362eb..3e52d3c1 100644 --- a/cmdline/parity.h +++ b/cmdline/parity.h @@ -36,6 +36,13 @@ struct snapraid_split_handle { */ data_off_t size; + /** + * Valid size of the parity split. + * This is the size effectively written, and not the reult of a chsize operation. + * It's used to make read operations failing if read over that size. + */ + data_off_t valid_size; + /** * Artificial size limit for testing. * 0 means unlimited. @@ -47,6 +54,7 @@ struct snapraid_parity_handle { struct snapraid_split_handle split_map[SPLIT_MAX]; unsigned split_mac; /**< Number of parity splits. */ unsigned level; /**< Level of the parity. */ + int has_write_access; /**< If the parity is open for writing. */ }; /** diff --git a/cmdline/support.h b/cmdline/support.h index 3b75b383..5bde967a 100644 --- a/cmdline/support.h +++ b/cmdline/support.h @@ -109,7 +109,7 @@ void log_flush(void); /** * Pointer to log function. */ -typedef void fptr(const char* format, ...); +typedef void fptr(const char* format, ...) __attribute__((format(attribute_printf, 1, 2))); /****************************************************************************/ /* message */