From e0afd0edf75da0b38f9901b8f1dd09413c9ea8bc Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 21 Aug 2013 22:24:12 +0200 Subject: [PATCH] Assumes also CHG blocks with a NULL hash without needing an info block. Some refactoring and renaming of other hash functions to avoid misunderstanding. --- check.c | 8 ++++---- dup.c | 2 +- elem.h | 45 +++++++++++++++++++++++++++++++++++++-------- scrub.c | 2 +- state.c | 25 ++++++------------------- sync.c | 2 +- 6 files changed, 50 insertions(+), 34 deletions(-) diff --git a/check.c b/check.c index 272c4402..33b86bc7 100644 --- a/check.c +++ b/check.c @@ -112,7 +112,7 @@ static int repair_step(struct snapraid_state* state, int rehash, unsigned pos, u /* if there isn't, we have to sacrifice a parity block to check that the result is correct */ has_hash = 0; for(j=0;jblockmax;++i) { memcpy(buf + i * HASH_SIZE, file->blockvec[i].hash, HASH_SIZE); - if (!block_has_hash(&file->blockvec[i])) { + if (!block_has_updated_hash(&file->blockvec[i])) { free(buf); return 0; } diff --git a/elem.h b/elem.h index 88212934..fc79c90c 100644 --- a/elem.h +++ b/elem.h @@ -89,10 +89,12 @@ struct snapraid_filter { * The block is new and not yet hashed, and it's using the space of a block not existing anymore. * This happens when a new block overwrite a just removed block. * - * The block hash field IS set, and it represents the hash of the previous data. + * The block hash field IS set, and it represents the hash of the previous data, + * but only if it's different by all 0. * The parity for this disk is not updated, but it contains the old data referenced by the hash. * - * If the hash is completely filled with 0, it means that its lost. + * If the hash is completely filled with 0, it means that the hash is lost. + * This could happen if a NEW block is converted to a CHG one in an interrupted sync. */ #define BLOCK_STATE_CHG 3 @@ -100,12 +102,12 @@ struct snapraid_filter { * This block is a deleted one. * This happens when a file is deleted. * - * The block hash field IS set, and it represents the hash of the previous data, but only - * if it's different by all 0. + * The block hash field IS set, and it represents the hash of the previous data, + * but only if it's different by all 0. * The parity for this disk is not updated, but it contains the old data referenced by the hash. * * If the hash is completely filled with 0, it means that the hash is lost. - * This could happen if a NEW block is deleted in an interrupted sync. + * This could happen if a NEW block is DELETED in an interrupted sync. */ #define BLOCK_STATE_DELETED 4 @@ -435,17 +437,44 @@ static inline void block_state_set(struct snapraid_block* block, unsigned state) } /** - * Checks if the specified block has a valid and updated hash. + * Checks if the specified block is valid and has an updated hash. * - * Note that EMPTY return 0. + * Note that EMPTY / CHG / NEW / DELETED return 0. */ -static inline int block_has_hash(const struct snapraid_block* block) +static inline int block_has_updated_hash(const struct snapraid_block* block) { unsigned state = block_state_get(block); return state == BLOCK_STATE_BLK; } +/** + * Checks if the specified block has any kind of hash. + * Even a not updated one. + * + * Note that for DELETED / CHG with a NULL hash returns 0, + * because in these cases the hash is lost. + */ +static inline int block_has_any_hash(const struct snapraid_block* block) +{ + unsigned block_state = block_state_get(block); + unsigned i; + + switch (block_state) { + case BLOCK_STATE_BLK : + return 1; + case BLOCK_STATE_CHG : + case BLOCK_STATE_DELETED : + /* the hash is valid only if different than 0 */ + for(i=0;ihash[i] != 0) + return 1; + break; + } + + return 0; +} + /** * Checks if the specified block is part of a file. * diff --git a/scrub.c b/scrub.c index 475ae2dd..3b8294e5 100644 --- a/scrub.c +++ b/scrub.c @@ -266,7 +266,7 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par memhash(state->hash, state->hashseed, hash, buffer[j], read_size); } - if (block_has_hash(block)) { + if (block_has_updated_hash(block)) { /* compare the hash */ if (memcmp(hash, block->hash, HASH_SIZE) != 0) { fprintf(stdlog, "error:%u:%s:%s: Data error at position %u\n", i, handle[j].disk->name, block_file_get(block)->sub, block_file_pos(block)); diff --git a/state.c b/state.c index 653c01a1..3c6c34a8 100644 --- a/state.c +++ b/state.c @@ -826,30 +826,17 @@ static void state_content_check(struct snapraid_state* state, const char* path) * and has a hash value. * Note that we include DELETED blocks, but only if they have a not NULL hash. */ -static int position_has_hash(struct snapraid_state* state, block_off_t pos) +static int position_has_any_hash(struct snapraid_state* state, block_off_t pos) { tommy_node* i; - unsigned j; /* check for each disk if block is really used */ for(i=state->disklist;i!=0;i=i->next) { struct snapraid_disk* disk = i->data; struct snapraid_block* block = disk_block_get(disk, pos); - unsigned block_state = block_state_get(block); - - switch (block_state) { - case BLOCK_STATE_BLK : - case BLOCK_STATE_CHG : + if (block_has_any_hash(block)) return 1; - case BLOCK_STATE_DELETED : - for(j=0;jhash[j] != 0) - break; - if (j != HASH_SIZE) - return 1; - break; - } } return 0; @@ -1660,7 +1647,7 @@ static void state_write_text(struct snapraid_state* state, STREAM* f) info_has_rehash = 0; /* if there is a rehash info */ for(b=0;binfoarr, b); /* only if there is some info to store */ @@ -1898,7 +1885,7 @@ static void state_write_text(struct snapraid_state* state, STREAM* f) /* write the info for each block */ for(b=0;binfoarr, b); /* save only stuffs different than 0 */ @@ -2280,7 +2267,7 @@ static void state_read_binary(struct snapraid_state* state, const char* path, ST info_set(&state->infoarr, v_pos, info); /* ensure that an info is present only for used positions */ - if (position_has_hash(state, v_pos)) { + if (position_has_any_hash(state, v_pos)) { if (!info) { decoding_error(path, f); fprintf(stderr, "Internal incosistency for missing info!\n"); @@ -2701,7 +2688,7 @@ static void state_write_binary(struct snapraid_state* state, STREAM* f) info_has_rehash = 0; /* if there is a rehash info */ for(b=0;binfoarr, b); /* only if there is some info to store */ diff --git a/sync.c b/sync.c index d53dd553..8157dd24 100644 --- a/sync.c +++ b/sync.c @@ -280,7 +280,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari memhash(state->hash, state->hashseed, hash, buffer[j], read_size); } - if (block_has_hash(block)) { + if (block_has_updated_hash(block)) { /* compare the hash */ if (memcmp(hash, block->hash, HASH_SIZE) != 0) { fprintf(stderr, "Data error in file '%s' at position '%u'\n", handle[j].path, block_file_pos(block));