Eliminate obsolete raid_zero API and dedicated zero buffers
Some checks are pending
Build / build-mac (push) Waiting to run
Build / build-linux (push) Waiting to run
Build / build-arm32 (push) Waiting to run
Build / build-win (push) Waiting to run
Build / build-freebsd (push) Waiting to run
Build / build-musl (push) Waiting to run
CodeQL Advanced / Analyze (c-cpp) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run

This commit is contained in:
Andrea Mazzoleni 2026-09-02 20:49:06 +02:00
parent 8f27c393d6
commit 0b64fb2eae
7 changed files with 66 additions and 68 deletions

View file

@ -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)

View file

@ -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]);

View file

@ -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__

View file

@ -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, &copy_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);

View file

@ -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 */

View file

@ -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.

View file

@ -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
*