From 902c19b6681d896d9a7746ec0ccce0e4add54ecd Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 9 Sep 2026 23:40:37 +0200 Subject: [PATCH] Specialize block hash copies for the full hash size --- cmdline/dup.c | 2 +- cmdline/elem.c | 6 +++--- cmdline/elem.h | 16 +++++++++++++++- cmdline/import.c | 4 ++-- cmdline/scan.c | 2 +- cmdline/scrub.c | 2 +- cmdline/state.c | 4 ++-- cmdline/sync.c | 8 ++++---- 8 files changed, 29 insertions(+), 15 deletions(-) diff --git a/cmdline/dup.c b/cmdline/dup.c index 4f239bc1..64e6352c 100644 --- a/cmdline/dup.c +++ b/cmdline/dup.c @@ -52,7 +52,7 @@ struct snapraid_hash* hash_alloc(struct snapraid_state* state, struct snapraid_d for (i = 0; i < file->blockmax; ++i) { struct snapraid_block* block = fs_file2block_get(file, i); - memcpy(buf + i * hash_size, block->hash, hash_size); + hash_copy(buf + i * hash_size, block->hash); if (!block_has_updated_hash(block)) { free(buf); diff --git a/cmdline/elem.c b/cmdline/elem.c index 494bab4b..c6d814c5 100644 --- a/cmdline/elem.c +++ b/cmdline/elem.c @@ -528,7 +528,7 @@ struct snapraid_file* file_dup(struct snapraid_file* copy) struct snapraid_block* block = file_block(file, i); struct snapraid_block* copy_block = file_block(copy, i); block->state = copy_block->state; - memcpy(block->hash, copy_block->hash, BLOCK_HASH_SIZE); + hash_copy(block->hash, copy_block->hash); } return file; @@ -581,7 +581,7 @@ void file_copy(struct snapraid_file* src_file, struct snapraid_file* dst_file) block_state_set(file_block(dst_file, i), BLOCK_STATE_REP); /* copy the hash */ - memcpy(file_block(dst_file, i)->hash, file_block(src_file, i)->hash, BLOCK_HASH_SIZE); + hash_copy(file_block(dst_file, i)->hash, file_block(src_file, i)->hash); } file_flag_set(dst_file, FILE_IS_COPY); @@ -898,7 +898,7 @@ void dealloc_import(struct snapraid_dealloc* dealloc, struct snapraid_file* file case BLOCK_STATE_BLK : case BLOCK_STATE_REP : case BLOCK_STATE_REBUILD : - memcpy(hash, block->hash, BLOCK_HASH_SIZE); + hash_copy(hash, block->hash); break; case BLOCK_STATE_CHG : hash_invalid_set(hash); diff --git a/cmdline/elem.h b/cmdline/elem.h index d93d212f..a49fc18b 100644 --- a/cmdline/elem.h +++ b/cmdline/elem.h @@ -692,6 +692,20 @@ int filter_content(tommy_list* contentlist, const char* mount_point, size_t moun */ int filter_snapshot(int enable, const char* sub, const char* name); +/** + * Copy a block hash using the configured hash size. + * + * Keep the common full-size case explicit so the compiler can inline a fixed + * 16-byte copy instead of emitting a call to memcpy() with a runtime size. + */ +static __always_inline void* hash_copy(void* dst, const void* src) +{ + if (BLOCK_HASH_SIZE == HASH_MAX) + return memcpy(dst, src, HASH_MAX); + else + return memcpy(dst, src, BLOCK_HASH_SIZE); +} + /** * Check if the specified hash is invalid. * @@ -707,7 +721,7 @@ static inline int hash_is_invalid(const unsigned char* hash) if (BLOCK_HASH_SIZE != HASH_MAX) return 0; - for (i = 0; i < BLOCK_HASH_SIZE; ++i) + for (i = 0; i < HASH_MAX; ++i) if (hash[i] != 0x00) return 0; diff --git a/cmdline/import.c b/cmdline/import.c index 79d641bf..e7c8a9e4 100644 --- a/cmdline/import.c +++ b/cmdline/import.c @@ -224,7 +224,7 @@ static void import_dealloc(struct snapraid_state* state, const char* dir, struct block->offset = offset; block->size = read_size; - memcpy(block->hash, dealloc->blockhash + i * BLOCK_HASH_SIZE, BLOCK_HASH_SIZE); + hash_copy(block->hash, dealloc->blockhash + i * BLOCK_HASH_SIZE); /* do not insert invalid hashes */ if (!hash_is_invalid(block->hash)) { @@ -244,7 +244,7 @@ static void import_dealloc(struct snapraid_state* state, const char* dir, struct * a new-hash block, or vice-versa) will miss in hash lookup and fall * back to parity reconstruction. Only same-generation matches will succeed. */ - memcpy(block->prevhash, block->hash, BLOCK_HASH_SIZE); + hash_copy(block->prevhash, block->hash); tommy_hashdyn_insert(&state->previmportset, &block->prevnodeset, block, import_block_hash(block->prevhash)); } else { hash_invalid_set(block->prevhash); diff --git a/cmdline/scan.c b/cmdline/scan.c index 5800b7a5..f3b854e4 100644 --- a/cmdline/scan.c +++ b/cmdline/scan.c @@ -341,7 +341,7 @@ static void scan_file_allocate(struct snapraid_scan* scan, struct snapraid_file* */ /* copy the past hash of the block */ - memcpy(block->hash, over_block->hash, BLOCK_HASH_SIZE); + hash_copy(block->hash, over_block->hash); } } diff --git a/cmdline/scrub.c b/cmdline/scrub.c index 892a7476..e2ec6a1a 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -909,7 +909,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par /* store all the new hashes already computed */ for (j = 0; j < diskmax; ++j) { if (rehandle[j].block) - memcpy(rehandle[j].block->hash, rehandle[j].hash, BLOCK_HASH_SIZE); + hash_copy(rehandle[j].block->hash, rehandle[j].hash); } /* complete the rehash */ diff --git a/cmdline/state.c b/cmdline/state.c index 892e6a7c..49f3e1a9 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -2311,7 +2311,7 @@ static int state_read_block_run(STREAM* f, struct snapraid_file* file, block_off if (hash_mode == STATE_BLOCK_HASH_DISCARD) hash_invalid_set(block->hash); else - memcpy(block->hash, input, BLOCK_HASH_SIZE); + hash_copy(block->hash, input); input += BLOCK_HASH_SIZE; block_ptr += block_stride; @@ -3887,7 +3887,7 @@ static int state_write_block_run(STREAM* f, struct snapraid_file* file, block_of struct snapraid_block* block = (struct snapraid_block*)block_ptr; crc = crc32c_plain(crc, block->hash, BLOCK_HASH_SIZE); - memcpy(output, block->hash, BLOCK_HASH_SIZE); + hash_copy(output, block->hash); output += BLOCK_HASH_SIZE; block_ptr += block_stride; diff --git a/cmdline/sync.c b/cmdline/sync.c index f4145827..cfb58f82 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -547,7 +547,7 @@ static int state_hash_process(struct snapraid_state* state, block_off_t blocksta */ /* copy the hash in the block */ - memcpy(block->hash, hash, BLOCK_HASH_SIZE); + hash_copy(block->hash, hash); /* and mark the block as hashed */ block_state_set(block, BLOCK_STATE_REP); @@ -1353,7 +1353,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari * During rehash this uses the previous hash algorithm and is * overwritten with the new hash below when rehash is committed. */ - memcpy(rehandle[diskcur].sync_hash, hash, BLOCK_HASH_SIZE); + hash_copy(rehandle[diskcur].sync_hash, hash); } } @@ -1574,7 +1574,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari * was handled above. Publish the staged hash atomically with CHG -> BLK. */ if (block_state_get(block) == BLOCK_STATE_CHG) - memcpy(block->hash, rehandle[j].sync_hash, BLOCK_HASH_SIZE); + hash_copy(block->hash, rehandle[j].sync_hash); /* now all the blocks have the hash and the parity computed */ block_state_set(block, BLOCK_STATE_BLK); @@ -1595,7 +1595,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari /* store all the new hash already computed */ for (j = 0; j < diskmax; ++j) { if (rehandle[j].block) - memcpy(rehandle[j].block->hash, rehandle[j].new_hash, BLOCK_HASH_SIZE); + hash_copy(rehandle[j].block->hash, rehandle[j].new_hash); } }