|
Packit Service |
d40955 |
/*
|
|
Packit Service |
d40955 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
d40955 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
d40955 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
d40955 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
d40955 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
d40955 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
d40955 |
* GNU General Public License for more details.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
d40955 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
d40955 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
d40955 |
* 02110-1301, USA.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/readOnlyRebuild.c#9 $
|
|
Packit Service |
d40955 |
*/
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "readOnlyRebuild.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "logger.h"
|
|
Packit Service |
d40955 |
#include "memoryAlloc.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
#include "blockMapInternals.h"
|
|
Packit Service |
d40955 |
#include "blockMapRecovery.h"
|
|
Packit Service |
d40955 |
#include "completion.h"
|
|
Packit Service |
d40955 |
#include "numUtils.h"
|
|
Packit Service |
d40955 |
#include "packedRecoveryJournalBlock.h"
|
|
Packit Service |
d40955 |
#include "recoveryJournalInternals.h"
|
|
Packit Service |
d40955 |
#include "recoveryUtils.h"
|
|
Packit Service |
d40955 |
#include "referenceCountRebuild.h"
|
|
Packit Service |
d40955 |
#include "slabDepot.h"
|
|
Packit Service |
d40955 |
#include "vdoInternal.h"
|
|
Packit Service |
d40955 |
#include "vdoPageCache.h"
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
typedef struct {
|
|
Packit Service |
d40955 |
/** The completion header */
|
|
Packit Service |
d40955 |
VDOCompletion completion;
|
|
Packit Service |
d40955 |
/** A sub task completion */
|
|
Packit Service |
d40955 |
VDOCompletion subTaskCompletion;
|
|
Packit Service |
d40955 |
/** The VDO in question */
|
|
Packit Service |
d40955 |
VDO *vdo;
|
|
Packit Service |
d40955 |
/** A buffer to hold the data read off disk */
|
|
Packit Service |
d40955 |
char *journalData;
|
|
Packit Service |
d40955 |
/** The entry data for the block map rebuild */
|
|
Packit Service |
d40955 |
NumberedBlockMapping *entries;
|
|
Packit Service |
d40955 |
/** The number of entries in the entry array */
|
|
Packit Service |
d40955 |
size_t entryCount;
|
|
Packit Service |
d40955 |
/** The sequence number of the first valid block of the journal (if known) */
|
|
Packit Service |
d40955 |
SequenceNumber head;
|
|
Packit Service |
d40955 |
/** The sequence number of the last valid block of the journal (if known) */
|
|
Packit Service |
d40955 |
SequenceNumber tail;
|
|
Packit Service |
d40955 |
/** The number of logical blocks in use */
|
|
Packit Service |
d40955 |
BlockCount logicalBlocksUsed;
|
|
Packit Service |
d40955 |
/** The number of allocated block map pages */
|
|
Packit Service |
d40955 |
BlockCount blockMapDataBlocks;
|
|
Packit Service |
d40955 |
} ReadOnlyRebuildCompletion;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Convert a generic completion to a ReadOnlyRebuildCompletion.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The completion to convert
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return the journal rebuild completion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result))
|
|
Packit Service |
d40955 |
static inline ReadOnlyRebuildCompletion *
|
|
Packit Service |
d40955 |
asReadOnlyRebuildCompletion(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
STATIC_ASSERT(offsetof(ReadOnlyRebuildCompletion, completion) == 0);
|
|
Packit Service |
d40955 |
assertCompletionType(completion->type, READ_ONLY_REBUILD_COMPLETION);
|
|
Packit Service |
d40955 |
return (ReadOnlyRebuildCompletion *) completion;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Free a rebuild completion and all underlying structures.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param rebuildPtr A pointer to the rebuild completion to free
|
|
Packit Service |
d40955 |
*/
|
|
Packit Service |
d40955 |
static void freeRebuildCompletion(ReadOnlyRebuildCompletion **rebuildPtr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild = *rebuildPtr;
|
|
Packit Service |
d40955 |
if (rebuild == NULL) {
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
destroyEnqueueable(&rebuild->subTaskCompletion);
|
|
Packit Service |
d40955 |
FREE(rebuild->journalData);
|
|
Packit Service |
d40955 |
FREE(rebuild->entries);
|
|
Packit Service |
d40955 |
FREE(rebuild);
|
|
Packit Service |
d40955 |
*rebuildPtr = NULL;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Allocate and initialize a read only rebuild completion.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param [in] vdo The VDO in question
|
|
Packit Service |
d40955 |
* @param [out] rebuildPtr A pointer to return the created rebuild completion
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return VDO_SUCCESS or an error code
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static int makeRebuildCompletion(VDO *vdo,
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion **rebuildPtr)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild;
|
|
Packit Service |
d40955 |
int result = ALLOCATE(1, ReadOnlyRebuildCompletion, __func__, &rebuild);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
initializeCompletion(&rebuild->completion, READ_ONLY_REBUILD_COMPLETION,
|
|
Packit Service |
d40955 |
vdo->layer);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
result = initializeEnqueueableCompletion(&rebuild->subTaskCompletion,
|
|
Packit Service |
d40955 |
SUB_TASK_COMPLETION, vdo->layer);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
freeRebuildCompletion(&rebuild);
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
rebuild->vdo = vdo;
|
|
Packit Service |
d40955 |
*rebuildPtr = rebuild;
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Clean up the rebuild process, whether or not it succeeded, by freeing the
|
|
Packit Service |
d40955 |
* rebuild completion and notifying the parent of the outcome.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The rebuild completion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void completeRebuild(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
VDOCompletion *parent = completion->parent;
|
|
Packit Service |
d40955 |
int result = completion->result;
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild = asReadOnlyRebuildCompletion(completion);
|
|
Packit Service |
d40955 |
VDO *vdo = rebuild->vdo;
|
|
Packit Service |
d40955 |
setVDOPageCacheRebuildMode(getBlockMap(vdo)->zones[0].pageCache, false);
|
|
Packit Service |
d40955 |
freeRebuildCompletion(&rebuild);
|
|
Packit Service |
d40955 |
finishCompletion(parent, result);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Finish rebuilding, free the rebuild completion and notify the parent.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The rebuild completion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void finishRebuild(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild = asReadOnlyRebuildCompletion(completion);
|
|
Packit Service |
d40955 |
initializeRecoveryJournalPostRebuild(rebuild->vdo->recoveryJournal,
|
|
Packit Service |
d40955 |
rebuild->vdo->completeRecoveries,
|
|
Packit Service |
d40955 |
rebuild->tail,
|
|
Packit Service |
d40955 |
rebuild->logicalBlocksUsed,
|
|
Packit Service |
d40955 |
rebuild->blockMapDataBlocks);
|
|
Packit Service |
d40955 |
logInfo("Read-only rebuild complete");
|
|
Packit Service |
d40955 |
completeRebuild(completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Handle a rebuild error.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The rebuild completion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void abortRebuild(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
logInfo("Read-only rebuild aborted");
|
|
Packit Service |
d40955 |
completeRebuild(completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Abort a rebuild if there is an error.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param result The result to check
|
|
Packit Service |
d40955 |
* @param rebuild The journal rebuild completion
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return true if the result was an error
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
__attribute__((warn_unused_result))
|
|
Packit Service |
d40955 |
static bool abortRebuildOnError(int result,
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
if (result == VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return false;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
finishCompletion(&rebuild->completion, result);
|
|
Packit Service |
d40955 |
return true;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Clean up after finishing the reference count rebuild. This callback is
|
|
Packit Service |
d40955 |
* registered in launchReferenceCountRebuild().
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The sub-task completion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void finishReferenceCountRebuild(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild = completion->parent;
|
|
Packit Service |
d40955 |
VDO *vdo = rebuild->vdo;
|
|
Packit Service |
d40955 |
assertOnAdminThread(vdo, __func__);
|
|
Packit Service |
d40955 |
if (vdo->loadState != VDO_REBUILD_FOR_UPGRADE) {
|
|
Packit Service |
d40955 |
// A "rebuild" for upgrade should not increment this count.
|
|
Packit Service |
d40955 |
vdo->completeRecoveries++;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
logInfo("Saving rebuilt state");
|
|
Packit Service |
d40955 |
prepareToFinishParent(completion, &rebuild->completion);
|
|
Packit Service |
d40955 |
drainSlabDepot(vdo->depot, ADMIN_STATE_REBUILDING, completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Rebuild the reference counts from the block map now that all journal entries
|
|
Packit Service |
d40955 |
* have been applied to the block map. This callback is registered in
|
|
Packit Service |
d40955 |
* applyJournalEntries().
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The sub-task completion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void launchReferenceCountRebuild(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild = completion->parent;
|
|
Packit Service |
d40955 |
VDO *vdo = rebuild->vdo;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// We must allocate RefCounts before we can rebuild them.
|
|
Packit Service |
d40955 |
int result = allocateSlabRefCounts(vdo->depot);
|
|
Packit Service |
d40955 |
if (abortRebuildOnError(result, rebuild)) {
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
prepareCompletion(completion, finishReferenceCountRebuild,
|
|
Packit Service |
d40955 |
finishParentCallback, getAdminThread(getThreadConfig(vdo)),
|
|
Packit Service |
d40955 |
completion->parent);
|
|
Packit Service |
d40955 |
rebuildReferenceCounts(vdo, completion, &rebuild->logicalBlocksUsed,
|
|
Packit Service |
d40955 |
&rebuild->blockMapDataBlocks);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Append an array of recovery journal entries from a journal block sector to
|
|
Packit Service |
d40955 |
* the array of numbered mappings in the rebuild completion, numbering each
|
|
Packit Service |
d40955 |
* entry in the order they are appended.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param rebuild The journal rebuild completion
|
|
Packit Service |
d40955 |
* @param sector The recovery journal sector with entries
|
|
Packit Service |
d40955 |
* @param entryCount The number of entries to append
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void appendSectorEntries(ReadOnlyRebuildCompletion *rebuild,
|
|
Packit Service |
d40955 |
PackedJournalSector *sector,
|
|
Packit Service |
d40955 |
JournalEntryCount entryCount)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
for (JournalEntryCount i = 0; i < entryCount; i++) {
|
|
Packit Service |
d40955 |
RecoveryJournalEntry entry
|
|
Packit Service |
d40955 |
= unpackRecoveryJournalEntry(§or->entries[i]);
|
|
Packit Service |
d40955 |
int result = validateRecoveryJournalEntry(rebuild->vdo, &entry);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
// When recovering from read-only mode, ignore damaged entries.
|
|
Packit Service |
d40955 |
continue;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
if (isIncrementOperation(entry.operation)) {
|
|
Packit Service |
d40955 |
rebuild->entries[rebuild->entryCount] = (NumberedBlockMapping) {
|
|
Packit Service |
d40955 |
.blockMapSlot = entry.slot,
|
|
Packit Service |
d40955 |
.blockMapEntry = packPBN(entry.mapping.pbn, entry.mapping.state),
|
|
Packit Service |
d40955 |
.number = rebuild->entryCount,
|
|
Packit Service |
d40955 |
};
|
|
Packit Service |
d40955 |
rebuild->entryCount++;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Create an array of all valid journal entries, in order, and store
|
|
Packit Service |
d40955 |
* it in the rebuild completion.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param rebuild The journal rebuild completion
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @return VDO_SUCCESS or an error code
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static int extractJournalEntries(ReadOnlyRebuildCompletion *rebuild)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
VDO *vdo = rebuild->vdo;
|
|
Packit Service |
d40955 |
RecoveryJournal *journal = vdo->recoveryJournal;
|
|
Packit Service |
d40955 |
SequenceNumber first = rebuild->head;
|
|
Packit Service |
d40955 |
SequenceNumber last = rebuild->tail;
|
|
Packit Service |
d40955 |
BlockCount maxCount = ((last - first + 1) * journal->entriesPerBlock);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Allocate a NumberedBlockMapping array large enough to transcribe every
|
|
Packit Service |
d40955 |
// PackedRecoveryJournalEntry from every valid journal block.
|
|
Packit Service |
d40955 |
int result = ALLOCATE(maxCount, NumberedBlockMapping, __func__,
|
|
Packit Service |
d40955 |
&rebuild->entries);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
return result;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
for (SequenceNumber i = first; i <= last; i++) {
|
|
Packit Service |
d40955 |
PackedJournalHeader *packedHeader
|
|
Packit Service |
d40955 |
= getJournalBlockHeader(journal, rebuild->journalData, i);
|
|
Packit Service |
d40955 |
RecoveryBlockHeader header;
|
|
Packit Service |
d40955 |
unpackRecoveryBlockHeader(packedHeader, &header);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
if (!isExactRecoveryJournalBlock(journal, &header, i)) {
|
|
Packit Service |
d40955 |
// This block is invalid, so skip it.
|
|
Packit Service |
d40955 |
continue;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Don't extract more than the expected maximum entries per block.
|
|
Packit Service |
d40955 |
JournalEntryCount blockEntries = minBlock(journal->entriesPerBlock,
|
|
Packit Service |
d40955 |
header.entryCount);
|
|
Packit Service |
d40955 |
for (uint8_t j = 1; j < SECTORS_PER_BLOCK; j++) {
|
|
Packit Service |
d40955 |
// Stop when all entries counted in the header are applied or skipped.
|
|
Packit Service |
d40955 |
if (blockEntries == 0) {
|
|
Packit Service |
d40955 |
break;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
PackedJournalSector *sector = getJournalBlockSector(packedHeader, j);
|
|
Packit Service |
d40955 |
if (!isValidRecoveryJournalSector(&header, sector)) {
|
|
Packit Service |
d40955 |
blockEntries -= minBlock(blockEntries,
|
|
Packit Service |
d40955 |
RECOVERY_JOURNAL_ENTRIES_PER_SECTOR);
|
|
Packit Service |
d40955 |
continue;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Don't extract more than the expected maximum entries per sector.
|
|
Packit Service |
d40955 |
JournalEntryCount sectorEntries
|
|
Packit Service |
d40955 |
= minBlock(sector->entryCount, RECOVERY_JOURNAL_ENTRIES_PER_SECTOR);
|
|
Packit Service |
d40955 |
// Only extract as many as the block header calls for.
|
|
Packit Service |
d40955 |
sectorEntries = minBlock(sectorEntries, blockEntries);
|
|
Packit Service |
d40955 |
appendSectorEntries(rebuild, sector, sectorEntries);
|
|
Packit Service |
d40955 |
// Even if the sector wasn't full, count it as full when counting up
|
|
Packit Service |
d40955 |
// to the entry count the block header claims.
|
|
Packit Service |
d40955 |
blockEntries -= minBlock(blockEntries,
|
|
Packit Service |
d40955 |
RECOVERY_JOURNAL_ENTRIES_PER_SECTOR);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
return VDO_SUCCESS;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Determine the limits of the valid recovery journal and apply all
|
|
Packit Service |
d40955 |
* valid entries to the block map. This callback is registered in
|
|
Packit Service |
d40955 |
* rebuildJournalAsync().
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The sub-task completion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void applyJournalEntries(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild
|
|
Packit Service |
d40955 |
= asReadOnlyRebuildCompletion(completion->parent);
|
|
Packit Service |
d40955 |
VDO *vdo = rebuild->vdo;
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
logInfo("Finished reading recovery journal");
|
|
Packit Service |
d40955 |
assertOnLogicalZoneThread(vdo, 0, __func__);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
bool foundEntries = findHeadAndTail(vdo->recoveryJournal,
|
|
Packit Service |
d40955 |
rebuild->journalData, &rebuild->tail,
|
|
Packit Service |
d40955 |
&rebuild->head, NULL);
|
|
Packit Service |
d40955 |
if (foundEntries) {
|
|
Packit Service |
d40955 |
int result = extractJournalEntries(rebuild);
|
|
Packit Service |
d40955 |
if (abortRebuildOnError(result, rebuild)) {
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Suppress block map errors.
|
|
Packit Service |
d40955 |
setVDOPageCacheRebuildMode(getBlockMap(vdo)->zones[0].pageCache, true);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
// Play the recovery journal into the block map.
|
|
Packit Service |
d40955 |
prepareCompletion(completion, launchReferenceCountRebuild,
|
|
Packit Service |
d40955 |
finishParentCallback, completion->callbackThreadID,
|
|
Packit Service |
d40955 |
completion->parent);
|
|
Packit Service |
d40955 |
recoverBlockMap(vdo, rebuild->entryCount, rebuild->entries, completion);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**
|
|
Packit Service |
d40955 |
* Begin loading the journal.
|
|
Packit Service |
d40955 |
*
|
|
Packit Service |
d40955 |
* @param completion The sub task completion
|
|
Packit Service |
d40955 |
**/
|
|
Packit Service |
d40955 |
static void loadJournal(VDOCompletion *completion)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild
|
|
Packit Service |
d40955 |
= asReadOnlyRebuildCompletion(completion->parent);
|
|
Packit Service |
d40955 |
VDO *vdo = rebuild->vdo;
|
|
Packit Service |
d40955 |
assertOnLogicalZoneThread(vdo, 0, __func__);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
prepareCompletion(completion, applyJournalEntries, finishParentCallback,
|
|
Packit Service |
d40955 |
completion->callbackThreadID, completion->parent);
|
|
Packit Service |
d40955 |
loadJournalAsync(vdo->recoveryJournal, completion, &rebuild->journalData);
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
/**********************************************************************/
|
|
Packit Service |
d40955 |
void launchRebuild(VDO *vdo, VDOCompletion *parent)
|
|
Packit Service |
d40955 |
{
|
|
Packit Service |
d40955 |
// Note: These messages must be recognizable by Permabit::VDODeviceBase.
|
|
Packit Service |
d40955 |
if (vdo->loadState == VDO_REBUILD_FOR_UPGRADE) {
|
|
Packit Service |
d40955 |
logWarning("Rebuilding reference counts for upgrade");
|
|
Packit Service |
d40955 |
} else {
|
|
Packit Service |
d40955 |
logWarning("Rebuilding reference counts to clear read-only mode");
|
|
Packit Service |
d40955 |
vdo->readOnlyRecoveries++;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
ReadOnlyRebuildCompletion *rebuild;
|
|
Packit Service |
d40955 |
int result = makeRebuildCompletion(vdo, &rebuild);
|
|
Packit Service |
d40955 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
d40955 |
finishCompletion(parent, result);
|
|
Packit Service |
d40955 |
return;
|
|
Packit Service |
d40955 |
}
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
VDOCompletion *completion = &rebuild->completion;
|
|
Packit Service |
d40955 |
prepareCompletion(completion, finishRebuild, abortRebuild,
|
|
Packit Service |
d40955 |
parent->callbackThreadID, parent);
|
|
Packit Service |
d40955 |
|
|
Packit Service |
d40955 |
VDOCompletion *subTaskCompletion = &rebuild->subTaskCompletion;
|
|
Packit Service |
d40955 |
prepareCompletion(subTaskCompletion, loadJournal, finishParentCallback,
|
|
Packit Service |
d40955 |
getLogicalZoneThread(getThreadConfig(vdo), 0),
|
|
Packit Service |
d40955 |
completion);
|
|
Packit Service |
d40955 |
loadSlabDepot(vdo->depot, ADMIN_STATE_LOADING_FOR_REBUILD,
|
|
Packit Service |
d40955 |
subTaskCompletion, NULL);
|
|
Packit Service |
d40955 |
}
|