/*
* Copyright (C) 2013 Andrea Mazzoleni
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "portable.h"
#include "util.h"
#include "elem.h"
#include "import.h"
#include "state.h"
#include "parity.h"
#include "handle.h"
#include "raid.h"
/****************************************************************************/
/* rehash */
static int state_rehash_process(struct snapraid_state* state, block_off_t blockstart, block_off_t blockmax)
{
struct snapraid_handle* handle;
unsigned diskmax;
block_off_t i;
unsigned j;
void* buffer_alloc;
unsigned char* buffer_aligned;
int ret;
data_off_t countsize;
block_off_t countpos;
block_off_t countmax;
unsigned error;
unsigned char seed[HASH_SIZE];
handle = handle_map(state, &diskmax);
buffer_aligned = malloc_nofail_align(state->block_size, &buffer_alloc);
error = 0;
/* set a random seed */
randomize(seed, HASH_SIZE);
/* check that we are in a sync complete state */
for(i=blockstart;iskip_sequential);
if (ret == -1) {
fprintf(stderr, "DANGER! Unexpected open error in a data disk, it isn't possible to rehash.\n");
printf("Stopping at block %u\n", i);
++error;
goto bail;
}
}
/* read from the file */
read_size = handle_read(&handle[j], block, buffer_aligned, state->block_size, stdlog);
if (read_size == -1) {
fprintf(stderr, "DANGER! Unexpected read error in a data disk, it isn't possible to rehash.\n");
printf("Stopping at block %u\n", i);
++error;
goto bail;
}
countsize += read_size;
/* compute the new hash */
memhash(state->besthash, seed, hash_new, buffer_aligned, read_size);
/* compute the old hash */
/* note that we intentionally compute the new one before the old */
/* to ensure to detect any random bit flip in the memory */
memhash(state->hash, state->hashseed, hash, buffer_aligned, read_size);
/* compare the hash */
if (memcmp(hash, block->hash, HASH_SIZE) != 0) {
fprintf(stderr, "DANGER! Unexpected data error in a data disk, it isn't possible to rehash.\n");
printf("Stopping at block %u\n", i);
++error;
}
/* store the new hash */
memcpy(block->hash, hash_new, HASH_SIZE);
}
/* count the number of processed block */
++countpos;
/* progress */
if (state_progress(state, i, countpos, countmax, countsize)) {
break;
}
}
state_progress_end(state, countpos, countmax, countsize);
/* set the new hash and seed */
state->hash = state->besthash;
memcpy(state->hashseed, seed, HASH_SIZE);
/* mark the state as needing write */
state->need_write = 1;
bail:
/* close all the files left open */
for(j=0;jhash == state->besthash) {
fprintf(stderr, "You don't need to rehash because you are already using the best hash.\n");
exit(EXIT_FAILURE);
}
printf("Initializing...\n");
blockmax = parity_size(state);
printf("Rehashing...\n");
error = 0;
ret = state_rehash_process(state, 0, blockmax);
if (ret == -1) {
++error;
/* continue, as we are already exiting */
}
/* abort if errors are present */
if (error != 0)
exit(EXIT_FAILURE);
}