// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2013 Andrea Mazzoleni #include "os/portable.h" #include "util.h" #include "elem.h" #include "import.h" #include "state.h" #include "parity.h" #include "handle.h" #include "raid/raid.h" /****************************************************************************/ /* rehash */ void state_rehash(struct snapraid_state* state) { block_off_t blockmax; block_off_t i; int has_pending_dealloc = 0; blockmax = parity_allocated_size(state); /* check if a rehash is already in progress */ if (state->prevhash != HASH_UNDEFINED) { /* LCOV_EXCL_START */ log_tag("summary:exit:already_in_progress\n"); log_fatal(EUSER, "You already have a rehash in progress.\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } if (state->hash == state->besthash) { /* LCOV_EXCL_START */ log_tag("summary:exit:not_required\n"); log_fatal(EUSER, "You are already using the best hash for your platform.\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } /* deleted-only positions are not counted in unsynced_blocks, but their hashes still need the current generation */ for (tommy_node* node = state->disklist; node != 0; node = node->next) { struct snapraid_disk* disk = node->data; if (!tommy_list_empty(&disk->dealloclist)) { has_pending_dealloc = 1; break; } } /* a rehash can start only from a fully synchronized state */ if (state->unsynced_blocks != 0 || has_pending_dealloc) { /* LCOV_EXCL_START */ log_tag("summary:exit:sync_required\n"); log_fatal(EUSER, "You cannot start a rehash with an incomplete sync.\n"); log_fatal(EUSER, "Run 'snapraid sync' first.\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } /* copy the present hash as previous one */ state->prevhash = state->hash; memcpy(state->prevhashseed, state->hashseed, HASH_MAX); /* set the new hash and seed */ state->hash = state->besthash; if (os_randomize(state->hashseed, HASH_MAX) != 0) { /* LCOV_EXCL_START */ log_fatal(errno, "Failed to get random values.\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } /* mark all the block for rehashing */ for (i = 0; i < blockmax; ++i) { snapraid_info info; /* if it's unused */ info = info_get(&state->infoarr, i); if (info == 0) { /* skip it */ continue; } if (info_get_rehash(info)) { /* LCOV_EXCL_START */ log_fatal(EINTERNAL, "Internal inconsistency for a rehash already in progress\n"); os_abort(); /* LCOV_EXCL_STOP */ } /* enable the rehash */ info = info_set_rehash(info); /* save it */ info_set(&state->infoarr, i, info); } /* save the new content file */ state->need_write = 1; msg_status("A rehash is now scheduled. It will take place progressively in the next\n"); msg_status("'sync' and 'scrub' commands. You can check the rehash progress using the\n"); msg_status("'status' command.\n"); log_tag("summary:exit:scheduled\n"); }