diff --git a/cmdline/check.c b/cmdline/check.c index e39e9d96..de2a318c 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -280,7 +280,7 @@ struct failed_struct { * Check if a block hash matches the specified buffer. * Return ==0 if equal */ -static int blockcmp(struct snapraid_state* state, int rehash, struct snapraid_block* block, size_t pos_size, unsigned char* buffer, unsigned char* buffer_zero) +static int blockcmp(struct snapraid_state* state, int rehash, struct snapraid_block* block, size_t pos_size, unsigned char* buffer) { unsigned char hash[HASH_MAX]; @@ -304,7 +304,7 @@ static int blockcmp(struct snapraid_state* state, int rehash, struct snapraid_bl * but also makes the canonical-block invariant explicit. */ if (pos_size < state->block_size) { - if (memcmp(buffer + pos_size, buffer_zero + pos_size, state->block_size - pos_size) != 0) { + if (!mem_is_zero(buffer + pos_size, state->block_size - pos_size)) { return -1; } } @@ -315,7 +315,7 @@ static int blockcmp(struct snapraid_state* state, int rehash, struct snapraid_bl /** * Check if the hash of all the failed blocks we are expecting to recover are now matching. */ -static int is_hash_matching(struct snapraid_state* state, int rehash, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void* buffer_zero) +static int is_hash_matching(struct snapraid_state* state, int rehash, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer) { unsigned j; int hash_checked; @@ -331,7 +331,7 @@ static int is_hash_matching(struct snapraid_state* state, int rehash, unsigned d ) { /* if a hash doesn't match, fail the check */ size_t pos_size = file_block_size(failed[failed_map[j]].file, failed[failed_map[j]].file_pos, state->block_size); - if (blockcmp(state, rehash, failed[failed_map[j]].block, pos_size, buffer[failed[failed_map[j]].index], buffer_zero) != 0) { + if (blockcmp(state, rehash, failed[failed_map[j]].block, pos_size, buffer[failed[failed_map[j]].index]) != 0) { log_tag("repair_hash_error:%u: Hash mismatch\n", failed_map[j]); return 0; } @@ -389,7 +389,7 @@ static int is_parity_matching(struct snapraid_state* state, unsigned diskmax, un * * On success all parity levels are recomputed in buffer. */ -static int repair_step(struct snapraid_state* state, int rehash, block_off_t pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void** buffer_recov, void* buffer_zero) +static int repair_step(struct snapraid_state* state, int rehash, block_off_t pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void** buffer_recov) { unsigned i, n; int error; @@ -515,7 +515,7 @@ static int repair_step(struct snapraid_state* state, int rehash, block_off_t pos raid_data(r, id, ip, diskmax, state->block_size, buffer); /* use the hash to check the result */ - if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer, buffer_zero)) + if (is_hash_matching(state, rehash, diskmax, failed, failed_map, failed_count, buffer)) return 0; /* log */ @@ -647,9 +647,6 @@ static int repair_step(struct snapraid_state* state, int rehash, block_off_t pos * the corresponding parity level is unavailable or cannot be * trusted for recovery. * - * buffer_zero A full block containing zeroes, used both for ZERO-state CHGs - * and for validating zero padding. - * * Return value: * * 0 A RAID solution was successfully validated under one of the two history @@ -667,7 +664,7 @@ static int repair_step(struct snapraid_state* state, int rehash, block_off_t pos * On successful return buffer[] contains the recovered data and parity * recomputed from that data. */ -static int repair(struct snapraid_state* state, int rehash, block_off_t pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void** buffer_recov, void* buffer_zero) +static int repair(struct snapraid_state* state, int rehash, block_off_t pos, unsigned diskmax, struct failed_struct* failed, unsigned* failed_map, unsigned failed_count, void** buffer, void** buffer_recov) { int ret; int error; @@ -848,7 +845,7 @@ static int repair(struct snapraid_state* state, int rehash, block_off_t pos, uns * only OLD and CURRENT generations, allowing their generation to be inferred * after the RAID solution itself has been validated. */ - ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov, buffer_zero); + ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov); if (ret == 0) { int has_recovered_chg; @@ -958,7 +955,7 @@ static int repair(struct snapraid_state* state, int rehash, block_off_t pos, uns * A zero candidate is ambiguous because OLD and CURRENT * may legitimately contain the same zero block. */ - if (memcmp(buffer[failed[j].index], buffer_zero, state->block_size) != 0) + if (!mem_is_zero(buffer[failed[j].index], state->block_size)) current_generation_proven = 1; } else { size_t pos_size; @@ -973,7 +970,7 @@ static int repair(struct snapraid_state* state, int rehash, block_off_t pos, uns * candidate != OLD and therefore identifies this validated RAID * solution as CURRENT. */ - if (blockcmp(state, rehash, failed[j].block, pos_size, buffer[failed[j].index], buffer_zero) != 0) + if (blockcmp(state, rehash, failed[j].block, pos_size, buffer[failed[j].index]) != 0) current_generation_proven = 1; } } @@ -1186,7 +1183,7 @@ static int repair(struct snapraid_state* state, int rehash, block_off_t pos, uns * or would just repeat the same recovery equations already attempted. */ if (something_to_recover && something_unsynced) { - ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov, buffer_zero); + ret = repair_step(state, rehash, pos, diskmax, failed, failed_map, n, buffer, buffer_recov); if (ret == 0) { /* @@ -1593,17 +1590,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna if (parity[j]) parity[j]->bw = &bw; - /* we need 1 * data + 2 * parity + 1 * zero */ - buffermax = diskmax + 2 * state->level + 1; + /* we need 1 * data + 2 * parity */ + buffermax = diskmax + 2 * state->level; buffer = malloc_nofail_vector_align(buffermax, state->block_size, &buffer_alloc); if (!state->opt.skip_self) mtest_vector(buffermax, state->block_size, buffer); - /* fill up the zero buffer */ - memset(buffer[buffermax - 1], 0, state->block_size); - raid_zero(buffer[buffermax - 1]); - failed = nalloc_nofail(diskmax, sizeof(struct failed_struct)); failed_map = nalloc_nofail(diskmax, sizeof(unsigned)); @@ -2016,7 +2009,6 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna /* now read and check the parity if requested */ if (!state->opt.auditonly) { void* buffer_recov[LEV_MAX]; - void* buffer_zero; /* buffers for parity read and not computed */ for (l = 0; l < state->level; ++l) @@ -2024,9 +2016,6 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna for (; l < LEV_MAX; ++l) buffer_recov[l] = 0; - /* the zero buffer is the last one */ - buffer_zero = buffer[buffermax - 1]; - /* read the parity */ for (l = 0; l < state->level; ++l) { if (parity[l]) { @@ -2056,7 +2045,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna } /* try all the recovering strategies */ - ret = repair(state, rehash, i, diskmax, failed, failed_map, failed_count, buffer, buffer_recov, buffer_zero); + ret = repair(state, rehash, i, diskmax, failed, failed_map, failed_count, buffer, buffer_recov); if (ret != 0) { /* increment the number of errors */ if (ret > 0) diff --git a/cmdline/selftest.c b/cmdline/selftest.c index 1f148d37..773f1e01 100644 --- a/cmdline/selftest.c +++ b/cmdline/selftest.c @@ -2038,6 +2038,26 @@ static void test_misc(int argc, char* argv[]) assert(strcmp(esc_tag(""), "") == 0); assert(strcmp(esc_tag("\n\r:\\\\"), "\\n\\r\\d\\\\\\\\") == 0); + { + unsigned char zbuf[64]; + unsigned zi, zj; + + memset(zbuf, 0, sizeof(zbuf)); + assert(mem_is_zero(zbuf, 0) != 0); + + for (zi = 0; zi < sizeof(zbuf); ++zi) { + for (zj = zi; zj <= sizeof(zbuf); ++zj) { + assert(mem_is_zero(zbuf + zi, zj - zi) != 0); + } + } + + for (zi = 0; zi < sizeof(zbuf); ++zi) { + zbuf[zi] = 1; + assert(mem_is_zero(zbuf, sizeof(zbuf)) == 0); + zbuf[zi] = 0; + } + } + for (i = 2; i < argc; ++i) { printf("argv[%d]\n", i); printf("\t#%s#\n", argv[i]); diff --git a/cmdline/speed.c b/cmdline/speed.c index 4ce4186c..91cb5290 100644 --- a/cmdline/speed.c +++ b/cmdline/speed.c @@ -2362,7 +2362,7 @@ void speed(int period, int nd, int size) delta = period >= 1000 ? 10 : 1; - nv = nd + RAID_PARITY_MAX + 1; + nv = nd + RAID_PARITY_MAX; v = malloc_nofail_vector_align(nv, size, &v_alloc); @@ -2370,10 +2370,6 @@ void speed(int period, int nd, int size) for (i = 0; i < nd; ++i) memset(v[i], i, size); - /* zero buffer */ - memset(v[nd + RAID_PARITY_MAX], 0, size); - raid_zero(v[nd + RAID_PARITY_MAX]); - printf(PACKAGE " v" VERSION " by Andrea Mazzoleni, " PACKAGE_URL "\n"); #ifdef __GNUC__ diff --git a/cmdline/sync.c b/cmdline/sync.c index 815e8979..c1f92bc3 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -940,8 +940,6 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari unsigned diskmax; block_off_t blockcur; unsigned j; - void* zero_alloc; - void** zero; void* copy_alloc; void** copy; unsigned buffermax; @@ -981,11 +979,6 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari /* allocate the copy buffer */ copy = malloc_nofail_vector_align(diskmax, state->block_size, ©_alloc); - /* allocate and fill the zero buffer */ - zero = malloc_nofail_align(state->block_size, &zero_alloc); - memset(zero, 0, state->block_size); - raid_zero(zero); - failed = nalloc_nofail(diskmax, sizeof(struct failed_struct)); failed_map = nalloc_nofail(diskmax, sizeof(unsigned)); @@ -1799,7 +1792,6 @@ bail: } free(handle); - free(zero_alloc); free(copy_alloc); free(copy); free(rehandle_alloc); diff --git a/cmdline/util.h b/cmdline/util.h index bc43fbeb..e5ff13a6 100644 --- a/cmdline/util.h +++ b/cmdline/util.h @@ -43,6 +43,37 @@ void* malloc_nofail_test(size_t size); */ void mtest_vector(int n, size_t size, void** vv); +/** + * Return !=0 if the memory region is completely filled with zeros. + */ +static inline int mem_is_zero(const void* ptr, size_t size) +{ + const unsigned char* p = ptr; + + while (size != 0 && ((uintptr_t)p % sizeof(size_t)) != 0) { + if (*p != 0) + return 0; + ++p; + --size; + } + + while (size >= sizeof(size_t)) { + if (*(const size_t*)p != 0) + return 0; + p += sizeof(size_t); + size -= sizeof(size_t); + } + + while (size != 0) { + if (*p != 0) + return 0; + ++p; + --size; + } + + return 1; +} + /****************************************************************************/ /* crc */ diff --git a/raid/raid.c b/raid/raid.c index b931ef07..db287608 100644 --- a/raid/raid.c +++ b/raid/raid.c @@ -215,15 +215,7 @@ * [5] Plank, "Screaming Fast Galois Field Arithmetic Using Intel SIMD Instructions", 2013 */ -/** - * Buffer filled with 0 used in recovering. - */ -static void *raid_zero_block; -void raid_zero(void *zero) -{ - raid_zero_block = zero; -} /** * Inverts the square matrix M of size nxn into V. diff --git a/raid/raid.h b/raid/raid.h index 36534b65..e3b0fe69 100644 --- a/raid/raid.h +++ b/raid/raid.h @@ -161,32 +161,10 @@ int raid_mode(int mode); * The test modifies global RAID state and must not be called concurrently * with any other RAID function. * - * The test resets the zero buffer to 0 via raid_zero(0) upon completion. - * A valid zero buffer must be set with raid_zero() afterwards before calling - * recovery functions (raid_rec(), raid_data()). - * * It returns 0 on success. */ int raid_selftest(void); -/** - * Sets the zero buffer to use during recovery. - * - * Before calling raid_rec() and raid_data() you must provide a memory - * buffer filled with zeros of the same size as the blocks to recover. - * - * The buffer pointed to by @zero must be aligned to a 64-byte boundary. - * - * This buffer is only read and never written. - * - * The selected zero buffer is global to the RAID library. raid_zero() must - * not be called concurrently with any other RAID function. - * - * Once set, the buffer must remain valid and unchanged while it is being - * used by recovery operations. - */ -void raid_zero(void *zero); - /** * Block aliasing *