|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
310c69 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
310c69 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
310c69 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
310c69 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
310c69 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
310c69 |
* GNU General Public License for more details.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
310c69 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
310c69 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
310c69 |
* 02110-1301, USA.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/blockMapPage.c#8 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "blockMapPage.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "permassert.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "blockMap.h"
|
|
Packit Service |
310c69 |
#include "blockMapInternals.h"
|
|
Packit Service |
310c69 |
#include "blockMapTree.h"
|
|
Packit Service |
310c69 |
#include "constants.h"
|
|
Packit Service |
310c69 |
#include "dataVIO.h"
|
|
Packit Service |
310c69 |
#include "recoveryJournal.h"
|
|
Packit Service |
310c69 |
#include "statusCodes.h"
|
|
Packit Service |
310c69 |
#include "types.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
enum {
|
|
Packit Service |
310c69 |
PAGE_HEADER_4_1_SIZE = 8 + 8 + 8 + 1 + 1 + 1 + 1,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
static const VersionNumber BLOCK_MAP_4_1 = {
|
|
Packit Service |
310c69 |
.majorVersion = 4,
|
|
Packit Service |
310c69 |
.minorVersion = 1,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool isCurrentBlockMapPage(const BlockMapPage *page)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return areSameVersion(BLOCK_MAP_4_1, unpackVersionNumber(page->version));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockMapPage *formatBlockMapPage(void *buffer,
|
|
Packit Service |
310c69 |
Nonce nonce,
|
|
Packit Service |
310c69 |
PhysicalBlockNumber pbn,
|
|
Packit Service |
310c69 |
bool initialized)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
memset(buffer, 0, VDO_BLOCK_SIZE);
|
|
Packit Service |
310c69 |
BlockMapPage *page = (BlockMapPage *) buffer;
|
|
Packit Service |
310c69 |
page->version = packVersionNumber(BLOCK_MAP_4_1);
|
|
Packit Service |
310c69 |
storeUInt64LE(page->header.fields.nonce, nonce);
|
|
Packit Service |
310c69 |
storeUInt64LE(page->header.fields.pbn, pbn);
|
|
Packit Service |
310c69 |
page->header.fields.initialized = initialized;
|
|
Packit Service |
310c69 |
return page;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockMapPageValidity validateBlockMapPage(BlockMapPage *page,
|
|
Packit Service |
310c69 |
Nonce nonce,
|
|
Packit Service |
310c69 |
PhysicalBlockNumber pbn)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// Make sure the page layout isn't accidentally changed by changing the
|
|
Packit Service |
310c69 |
// length of the page header.
|
|
Packit Service |
310c69 |
STATIC_ASSERT_SIZEOF(PageHeader, PAGE_HEADER_4_1_SIZE);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (!areSameVersion(BLOCK_MAP_4_1, unpackVersionNumber(page->version))
|
|
Packit Service |
310c69 |
|| !isBlockMapPageInitialized(page)
|
|
Packit Service |
310c69 |
|| (nonce != getUInt64LE(page->header.fields.nonce))) {
|
|
Packit Service |
310c69 |
return BLOCK_MAP_PAGE_INVALID;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (pbn != getBlockMapPagePBN(page)) {
|
|
Packit Service |
310c69 |
return BLOCK_MAP_PAGE_BAD;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return BLOCK_MAP_PAGE_VALID;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void updateBlockMapPage(BlockMapPage *page,
|
|
Packit Service |
310c69 |
DataVIO *dataVIO,
|
|
Packit Service |
310c69 |
PhysicalBlockNumber pbn,
|
|
Packit Service |
310c69 |
BlockMappingState mappingState,
|
|
Packit Service |
310c69 |
SequenceNumber *recoveryLock)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// Encode the new mapping.
|
|
Packit Service |
310c69 |
TreeLock *treeLock = &dataVIO->treeLock;
|
|
Packit Service |
310c69 |
SlotNumber slot = treeLock->treeSlots[treeLock->height].blockMapSlot.slot;
|
|
Packit Service |
310c69 |
page->entries[slot] = packPBN(pbn, mappingState);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Adjust references (locks) on the recovery journal blocks.
|
|
Packit Service |
310c69 |
BlockMapZone *zone = getBlockMapForZone(dataVIO->logical.zone);
|
|
Packit Service |
310c69 |
BlockMap *blockMap = zone->blockMap;
|
|
Packit Service |
310c69 |
RecoveryJournal *journal = blockMap->journal;
|
|
Packit Service |
310c69 |
SequenceNumber oldLocked = *recoveryLock;
|
|
Packit Service |
310c69 |
SequenceNumber newLocked = dataVIO->recoverySequenceNumber;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if ((oldLocked == 0) || (oldLocked > newLocked)) {
|
|
Packit Service |
310c69 |
// Acquire a lock on the newly referenced journal block.
|
|
Packit Service |
310c69 |
acquireRecoveryJournalBlockReference(journal, newLocked, ZONE_TYPE_LOGICAL,
|
|
Packit Service |
310c69 |
zone->zoneNumber);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// If the block originally held a newer lock, release it.
|
|
Packit Service |
310c69 |
if (oldLocked > 0) {
|
|
Packit Service |
310c69 |
releaseRecoveryJournalBlockReference(journal, oldLocked,
|
|
Packit Service |
310c69 |
ZONE_TYPE_LOGICAL,
|
|
Packit Service |
310c69 |
zone->zoneNumber);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*recoveryLock = newLocked;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Release the transferred lock from the DataVIO.
|
|
Packit Service |
310c69 |
releasePerEntryLockFromOtherZone(journal, newLocked);
|
|
Packit Service |
310c69 |
dataVIO->recoverySequenceNumber = 0;
|
|
Packit Service |
310c69 |
}
|