|
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/blockMap.c#24 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "blockMap.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "logger.h"
|
|
Packit Service |
310c69 |
#include "memoryAlloc.h"
|
|
Packit Service |
310c69 |
#include "permassert.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "actionManager.h"
|
|
Packit Service |
310c69 |
#include "adminState.h"
|
|
Packit Service |
310c69 |
#include "blockMapInternals.h"
|
|
Packit Service |
310c69 |
#include "blockMapPage.h"
|
|
Packit Service |
310c69 |
#include "blockMapTree.h"
|
|
Packit Service |
310c69 |
#include "constants.h"
|
|
Packit Service |
310c69 |
#include "dataVIO.h"
|
|
Packit Service |
310c69 |
#include "forest.h"
|
|
Packit Service |
310c69 |
#include "numUtils.h"
|
|
Packit Service |
310c69 |
#include "recoveryJournal.h"
|
|
Packit Service |
310c69 |
#include "statusCodes.h"
|
|
Packit Service |
310c69 |
#include "types.h"
|
|
Packit Service |
310c69 |
#include "vdoInternal.h"
|
|
Packit Service |
310c69 |
#include "vdoPageCache.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
typedef struct {
|
|
Packit Service |
310c69 |
PhysicalBlockNumber flatPageOrigin;
|
|
Packit Service |
310c69 |
BlockCount flatPageCount;
|
|
Packit Service |
310c69 |
PhysicalBlockNumber rootOrigin;
|
|
Packit Service |
310c69 |
BlockCount rootCount;
|
|
Packit Service |
310c69 |
} __attribute__((packed)) BlockMapState2_0;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
static const Header BLOCK_MAP_HEADER_2_0 = {
|
|
Packit Service |
310c69 |
.id = BLOCK_MAP,
|
|
Packit Service |
310c69 |
.version = {
|
|
Packit Service |
310c69 |
.majorVersion = 2,
|
|
Packit Service |
310c69 |
.minorVersion = 0,
|
|
Packit Service |
310c69 |
},
|
|
Packit Service |
310c69 |
.size = sizeof(BlockMapState2_0),
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* State associated which each block map page while it is in the VDO page
|
|
Packit Service |
310c69 |
* cache.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
typedef struct {
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* The earliest recovery journal block containing uncommitted updates to the
|
|
Packit Service |
310c69 |
* block map page associated with this context. A reference (lock) is held
|
|
Packit Service |
310c69 |
* on that block to prevent it from being reaped. When this value changes,
|
|
Packit Service |
310c69 |
* the reference on the old value must be released and a reference on the
|
|
Packit Service |
310c69 |
* new value must be acquired.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
SequenceNumber recoveryLock;
|
|
Packit Service |
310c69 |
} BlockMapPageContext;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Implements VDOPageReadFunction.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static int validatePageOnRead(void *buffer,
|
|
Packit Service |
310c69 |
PhysicalBlockNumber pbn,
|
|
Packit Service |
310c69 |
BlockMapZone *zone,
|
|
Packit Service |
310c69 |
void *pageContext)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMapPage *page = buffer;
|
|
Packit Service |
310c69 |
BlockMapPageContext *context = pageContext;
|
|
Packit Service |
310c69 |
Nonce nonce = zone->blockMap->nonce;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockMapPageValidity validity = validateBlockMapPage(page, nonce, pbn);
|
|
Packit Service |
310c69 |
if (validity == BLOCK_MAP_PAGE_BAD) {
|
|
Packit Service |
310c69 |
return logErrorWithStringError(VDO_BAD_PAGE,
|
|
Packit Service |
310c69 |
"Expected page %" PRIu64
|
|
Packit Service |
310c69 |
" but got page %llu instead",
|
|
Packit Service |
310c69 |
pbn, getBlockMapPagePBN(page));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (validity == BLOCK_MAP_PAGE_INVALID) {
|
|
Packit Service |
310c69 |
formatBlockMapPage(page, nonce, pbn, false);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
context->recoveryLock = 0;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Handle journal updates and torn write protection.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements VDOPageWriteFunction.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static bool handlePageWrite(void *rawPage,
|
|
Packit Service |
310c69 |
BlockMapZone *zone,
|
|
Packit Service |
310c69 |
void *pageContext)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMapPage *page = rawPage;
|
|
Packit Service |
310c69 |
BlockMapPageContext *context = pageContext;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (markBlockMapPageInitialized(page, true)) {
|
|
Packit Service |
310c69 |
// Cause the page to be re-written.
|
|
Packit Service |
310c69 |
return true;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Release the page's references on the recovery journal.
|
|
Packit Service |
310c69 |
releaseRecoveryJournalBlockReference(zone->blockMap->journal,
|
|
Packit Service |
310c69 |
context->recoveryLock,
|
|
Packit Service |
310c69 |
ZONE_TYPE_LOGICAL, zone->zoneNumber);
|
|
Packit Service |
310c69 |
context->recoveryLock = 0;
|
|
Packit Service |
310c69 |
return false;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
PageCount computeBlockMapPageCount(BlockCount entries)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return computeBucketCount(entries, BLOCK_MAP_ENTRIES_PER_PAGE);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int makeBlockMap(BlockCount logicalBlocks,
|
|
Packit Service |
310c69 |
const ThreadConfig *threadConfig,
|
|
Packit Service |
310c69 |
BlockCount flatPageCount,
|
|
Packit Service |
310c69 |
PhysicalBlockNumber rootOrigin,
|
|
Packit Service |
310c69 |
BlockCount rootCount,
|
|
Packit Service |
310c69 |
BlockMap **mapPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
STATIC_ASSERT(BLOCK_MAP_ENTRIES_PER_PAGE
|
|
Packit Service |
310c69 |
== ((VDO_BLOCK_SIZE - sizeof(BlockMapPage))
|
|
Packit Service |
310c69 |
/ sizeof(BlockMapEntry)));
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockMap *map;
|
|
Packit Service |
310c69 |
int result = ALLOCATE_EXTENDED(BlockMap, threadConfig->logicalZoneCount,
|
|
Packit Service |
310c69 |
BlockMapZone, __func__, &map);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
map->flatPageCount = flatPageCount;
|
|
Packit Service |
310c69 |
map->rootOrigin = rootOrigin;
|
|
Packit Service |
310c69 |
map->rootCount = rootCount;
|
|
Packit Service |
310c69 |
map->entryCount = logicalBlocks;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
ZoneCount zoneCount = threadConfig->logicalZoneCount;
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < zoneCount; zone++) {
|
|
Packit Service |
310c69 |
BlockMapZone *blockMapZone = &map->zones[zone];
|
|
Packit Service |
310c69 |
blockMapZone->zoneNumber = zone;
|
|
Packit Service |
310c69 |
blockMapZone->threadID = getLogicalZoneThread(threadConfig, zone);
|
|
Packit Service |
310c69 |
blockMapZone->blockMap = map;
|
|
Packit Service |
310c69 |
map->zoneCount++;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*mapPtr = map;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Decode block map component state version 2.0 from a buffer.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
310c69 |
* @param state The state structure to receive the decoded values
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static int decodeBlockMapState_2_0(Buffer *buffer, BlockMapState2_0 *state)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
size_t initialLength = contentLength(buffer);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
PhysicalBlockNumber flatPageOrigin;
|
|
Packit Service |
310c69 |
int result = getUInt64LEFromBuffer(buffer, &flatPageOrigin);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockCount flatPageCount;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &flatPageCount);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
PhysicalBlockNumber rootOrigin;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &rootOrigin);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockCount rootCount;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &rootCount);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*state = (BlockMapState2_0) {
|
|
Packit Service |
310c69 |
.flatPageOrigin = flatPageOrigin,
|
|
Packit Service |
310c69 |
.flatPageCount = flatPageCount,
|
|
Packit Service |
310c69 |
.rootOrigin = rootOrigin,
|
|
Packit Service |
310c69 |
.rootCount = rootCount,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
size_t decodedSize = initialLength - contentLength(buffer);
|
|
Packit Service |
310c69 |
return ASSERT(BLOCK_MAP_HEADER_2_0.size == decodedSize,
|
|
Packit Service |
310c69 |
"decoded block map component size must match header size");
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int decodeBlockMap(Buffer *buffer,
|
|
Packit Service |
310c69 |
BlockCount logicalBlocks,
|
|
Packit Service |
310c69 |
const ThreadConfig *threadConfig,
|
|
Packit Service |
310c69 |
BlockMap **mapPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
Header header;
|
|
Packit Service |
310c69 |
int result = decodeHeader(buffer, &header);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = validateHeader(&BLOCK_MAP_HEADER_2_0, &header, true, __func__);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockMapState2_0 state;
|
|
Packit Service |
310c69 |
result = decodeBlockMapState_2_0(buffer, &state);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(state.flatPageOrigin == BLOCK_MAP_FLAT_PAGE_ORIGIN,
|
|
Packit Service |
310c69 |
"Flat page origin must be %u (recorded as %llu)",
|
|
Packit Service |
310c69 |
BLOCK_MAP_FLAT_PAGE_ORIGIN, state.flatPageOrigin);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockMap *map;
|
|
Packit Service |
310c69 |
result = makeBlockMap(logicalBlocks, threadConfig,
|
|
Packit Service |
310c69 |
state.flatPageCount, state.rootOrigin,
|
|
Packit Service |
310c69 |
state.rootCount, &map);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*mapPtr = map;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int decodeSodiumBlockMap(Buffer *buffer,
|
|
Packit Service |
310c69 |
BlockCount logicalBlocks,
|
|
Packit Service |
310c69 |
const ThreadConfig *threadConfig,
|
|
Packit Service |
310c69 |
BlockMap **mapPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// Sodium uses state version 2.0.
|
|
Packit Service |
310c69 |
return decodeBlockMap(buffer, logicalBlocks, threadConfig, mapPtr);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Initialize the per-zone portions of the block map.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param zone The zone to initialize
|
|
Packit Service |
310c69 |
* @param layer The physical layer on which the zone resides
|
|
Packit Service |
310c69 |
* @param readOnlyNotifier The read-only context for the VDO
|
|
Packit Service |
310c69 |
* @param cacheSize The size of the page cache for the zone
|
|
Packit Service |
310c69 |
* @param maximumAge The number of journal blocks before a dirtied page
|
|
Packit Service |
310c69 |
* is considered old and must be written out
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return VDO_SUCCESS or an error
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result))
|
|
Packit Service |
310c69 |
static int initializeBlockMapZone(BlockMapZone *zone,
|
|
Packit Service |
310c69 |
PhysicalLayer *layer,
|
|
Packit Service |
310c69 |
ReadOnlyNotifier *readOnlyNotifier,
|
|
Packit Service |
310c69 |
PageCount cacheSize,
|
|
Packit Service |
310c69 |
BlockCount maximumAge)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
zone->readOnlyNotifier = readOnlyNotifier;
|
|
Packit Service |
310c69 |
int result = initializeTreeZone(zone, layer, maximumAge);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return makeVDOPageCache(layer, cacheSize, validatePageOnRead,
|
|
Packit Service |
310c69 |
handlePageWrite, sizeof(BlockMapPageContext),
|
|
Packit Service |
310c69 |
maximumAge, zone, &zone->pageCache);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockMapZone *getBlockMapZone(BlockMap *map, ZoneCount zoneNumber)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return &map->zones[zoneNumber];
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Get the ID of the thread on which a given block map zone operates.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ZoneThreadGetter.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static ThreadID getBlockMapZoneThreadID(void *context, ZoneCount zoneNumber)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return getBlockMapZone(context, zoneNumber)->threadID;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Prepare for an era advance.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ActionPreamble.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void prepareForEraAdvance(void *context, VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMap *map = context;
|
|
Packit Service |
310c69 |
map->currentEraPoint = map->pendingEraPoint;
|
|
Packit Service |
310c69 |
completeCompletion(parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Update the progress of the era in a zone.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ZoneAction.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void advanceBlockMapZoneEra(void *context,
|
|
Packit Service |
310c69 |
ZoneCount zoneNumber,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMapZone *zone = getBlockMapZone(context, zoneNumber);
|
|
Packit Service |
310c69 |
advanceVDOPageCachePeriod(zone->pageCache, zone->blockMap->currentEraPoint);
|
|
Packit Service |
310c69 |
advanceZoneTreePeriod(&zone->treeZone, zone->blockMap->currentEraPoint);
|
|
Packit Service |
310c69 |
finishCompletion(parent, VDO_SUCCESS);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Schedule an era advance if necessary. This method should not be called
|
|
Packit Service |
310c69 |
* directly. Rather, call scheduleDefaultAction() on the block map's action
|
|
Packit Service |
310c69 |
* manager.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ActionScheduler.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static bool scheduleEraAdvance(void *context)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMap *map = context;
|
|
Packit Service |
310c69 |
if (map->currentEraPoint == map->pendingEraPoint) {
|
|
Packit Service |
310c69 |
return false;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return scheduleAction(map->actionManager, prepareForEraAdvance,
|
|
Packit Service |
310c69 |
advanceBlockMapZoneEra, NULL, NULL);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int makeBlockMapCaches(BlockMap *map,
|
|
Packit Service |
310c69 |
PhysicalLayer *layer,
|
|
Packit Service |
310c69 |
ReadOnlyNotifier *readOnlyNotifier,
|
|
Packit Service |
310c69 |
RecoveryJournal *journal,
|
|
Packit Service |
310c69 |
Nonce nonce,
|
|
Packit Service |
310c69 |
PageCount cacheSize,
|
|
Packit Service |
310c69 |
BlockCount maximumAge)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = ASSERT(cacheSize > 0, "block map cache size is specified");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
map->journal = journal;
|
|
Packit Service |
310c69 |
map->nonce = nonce;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = makeForest(map, map->entryCount);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
replaceForest(map);
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < map->zoneCount; zone++) {
|
|
Packit Service |
310c69 |
result = initializeBlockMapZone(&map->zones[zone], layer, readOnlyNotifier,
|
|
Packit Service |
310c69 |
cacheSize / map->zoneCount, maximumAge);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return makeActionManager(map->zoneCount, getBlockMapZoneThreadID,
|
|
Packit Service |
310c69 |
getRecoveryJournalThreadID(journal), map,
|
|
Packit Service |
310c69 |
scheduleEraAdvance, layer,
|
|
Packit Service |
310c69 |
&map->actionManager);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Clean up a BlockMapZone.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param zone The zone to uninitialize
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void uninitializeBlockMapZone(BlockMapZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
uninitializeBlockMapTreeZone(&zone->treeZone);
|
|
Packit Service |
310c69 |
freeVDOPageCache(&zone->pageCache);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void freeBlockMap(BlockMap **mapPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMap *map = *mapPtr;
|
|
Packit Service |
310c69 |
if (map == NULL) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < map->zoneCount; zone++) {
|
|
Packit Service |
310c69 |
uninitializeBlockMapZone(&map->zones[zone]);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
abandonBlockMapGrowth(map);
|
|
Packit Service |
310c69 |
freeForest(&map->forest);
|
|
Packit Service |
310c69 |
freeActionManager(&map->actionManager);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
FREE(map);
|
|
Packit Service |
310c69 |
*mapPtr = NULL;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
size_t getBlockMapEncodedSize(void)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return ENCODED_HEADER_SIZE + sizeof(BlockMapState2_0);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int encodeBlockMap(const BlockMap *map, Buffer *buffer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = encodeHeader(&BLOCK_MAP_HEADER_2_0, buffer);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
size_t initialLength = contentLength(buffer);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, BLOCK_MAP_FLAT_PAGE_ORIGIN);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, map->flatPageCount);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, map->rootOrigin);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, map->rootCount);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
size_t encodedSize = contentLength(buffer) - initialLength;
|
|
Packit Service |
310c69 |
return ASSERT(BLOCK_MAP_HEADER_2_0.size == encodedSize,
|
|
Packit Service |
310c69 |
"encoded block map component size must match header size");
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void initializeBlockMapFromJournal(BlockMap *map, RecoveryJournal *journal)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
map->currentEraPoint = getCurrentJournalSequenceNumber(journal);
|
|
Packit Service |
310c69 |
map->pendingEraPoint = map->currentEraPoint;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < map->zoneCount; zone++) {
|
|
Packit Service |
310c69 |
setTreeZoneInitialPeriod(&map->zones[zone].treeZone, map->currentEraPoint);
|
|
Packit Service |
310c69 |
setVDOPageCacheInitialPeriod(map->zones[zone].pageCache,
|
|
Packit Service |
310c69 |
map->currentEraPoint);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
ZoneCount computeLogicalZone(DataVIO *dataVIO)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMap *map = getBlockMap(getVDOFromDataVIO(dataVIO));
|
|
Packit Service |
310c69 |
TreeLock *treeLock = &dataVIO->treeLock;
|
|
Packit Service |
310c69 |
PageNumber pageNumber = computePageNumber(dataVIO->logical.lbn);
|
|
Packit Service |
310c69 |
treeLock->treeSlots[0].pageIndex = pageNumber;
|
|
Packit Service |
310c69 |
treeLock->rootIndex = pageNumber % map->rootCount;
|
|
Packit Service |
310c69 |
return (treeLock->rootIndex % map->zoneCount);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void findBlockMapSlotAsync(DataVIO *dataVIO,
|
|
Packit Service |
310c69 |
VDOAction *callback,
|
|
Packit Service |
310c69 |
ThreadID threadID)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMap *map = getBlockMap(getVDOFromDataVIO(dataVIO));
|
|
Packit Service |
310c69 |
if (dataVIO->logical.lbn >= map->entryCount) {
|
|
Packit Service |
310c69 |
finishDataVIO(dataVIO, VDO_OUT_OF_RANGE);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
TreeLock *treeLock = &dataVIO->treeLock;
|
|
Packit Service |
310c69 |
BlockMapTreeSlot *slot = &treeLock->treeSlots[0];
|
|
Packit Service |
310c69 |
slot->blockMapSlot.slot = computeSlot(dataVIO->logical.lbn);
|
|
Packit Service |
310c69 |
if (slot->pageIndex < map->flatPageCount) {
|
|
Packit Service |
310c69 |
slot->blockMapSlot.pbn = slot->pageIndex + BLOCK_MAP_FLAT_PAGE_ORIGIN;
|
|
Packit Service |
310c69 |
launchCallback(dataVIOAsCompletion(dataVIO), callback, threadID);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
treeLock->callback = callback;
|
|
Packit Service |
310c69 |
treeLock->threadID = threadID;
|
|
Packit Service |
310c69 |
lookupBlockMapPBN(dataVIO);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
PageCount getNumberOfFixedBlockMapPages(const BlockMap *map)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (map->flatPageCount + map->rootCount);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockCount getNumberOfBlockMapEntries(const BlockMap *map)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return map->entryCount;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void advanceBlockMapEra(BlockMap *map, SequenceNumber recoveryBlockNumber)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (map == NULL) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
map->pendingEraPoint = recoveryBlockNumber;
|
|
Packit Service |
310c69 |
scheduleDefaultAction(map->actionManager);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void checkForDrainComplete(BlockMapZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (isDraining(&zone->state)
|
|
Packit Service |
310c69 |
&& !isTreeZoneActive(&zone->treeZone)
|
|
Packit Service |
310c69 |
&& !isPageCacheActive(zone->pageCache)) {
|
|
Packit Service |
310c69 |
finishDrainingWithResult(&zone->state,
|
|
Packit Service |
310c69 |
(isReadOnly(zone->readOnlyNotifier)
|
|
Packit Service |
310c69 |
? VDO_READ_ONLY : VDO_SUCCESS));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Initiate a drain of the trees and page cache of a block map zone.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements AdminInitiator
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void initiateDrain(AdminState *state)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMapZone *zone = container_of(state, BlockMapZone, state);
|
|
Packit Service |
310c69 |
drainZoneTrees(&zone->treeZone);
|
|
Packit Service |
310c69 |
drainVDOPageCache(zone->pageCache);
|
|
Packit Service |
310c69 |
checkForDrainComplete(zone);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Drain a zone of the block map.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ZoneAction.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void drainZone(void *context,
|
|
Packit Service |
310c69 |
ZoneCount zoneNumber,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMapZone *zone = getBlockMapZone(context, zoneNumber);
|
|
Packit Service |
310c69 |
startDraining(&zone->state,
|
|
Packit Service |
310c69 |
getCurrentManagerOperation(zone->blockMap->actionManager),
|
|
Packit Service |
310c69 |
parent, initiateDrain);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void drainBlockMap(BlockMap *map,
|
|
Packit Service |
310c69 |
AdminStateCode operation,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
scheduleOperation(map->actionManager, operation, NULL, drainZone, NULL,
|
|
Packit Service |
310c69 |
parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Resume a zone of the block map.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ZoneAction.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void resumeBlockMapZone(void *context,
|
|
Packit Service |
310c69 |
ZoneCount zoneNumber,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMapZone *zone = getBlockMapZone(context, zoneNumber);
|
|
Packit Service |
310c69 |
finishCompletion(parent, resumeIfQuiescent(&zone->state));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void resumeBlockMap(BlockMap *map, VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
scheduleOperation(map->actionManager, ADMIN_STATE_RESUMING, NULL,
|
|
Packit Service |
310c69 |
resumeBlockMapZone, NULL, parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int prepareToGrowBlockMap(BlockMap *map, BlockCount newLogicalBlocks)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (map->nextEntryCount == newLogicalBlocks) {
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (map->nextEntryCount > 0) {
|
|
Packit Service |
310c69 |
abandonBlockMapGrowth(map);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (newLogicalBlocks < map->entryCount) {
|
|
Packit Service |
310c69 |
map->nextEntryCount = map->entryCount;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return makeForest(map, newLogicalBlocks);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockCount getNewEntryCount(BlockMap *map)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return map->nextEntryCount;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Grow the block map by replacing the forest with the one which was prepared.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ActionPreamble
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void growForest(void *context, VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
replaceForest(context);
|
|
Packit Service |
310c69 |
completeCompletion(completion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void growBlockMap(BlockMap *map, VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
scheduleOperation(map->actionManager, ADMIN_STATE_SUSPENDED_OPERATION,
|
|
Packit Service |
310c69 |
growForest, NULL, NULL, parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void abandonBlockMapGrowth(BlockMap *map)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
abandonForest(map);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Finish processing a block map get or put operation. This function releases
|
|
Packit Service |
310c69 |
* the page completion and then continues the requester.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The completion for the page fetch
|
|
Packit Service |
310c69 |
* @param result The result of the block map operation
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static inline void finishProcessingPage(VDOCompletion *completion, int result)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
VDOCompletion *parent = completion->parent;
|
|
Packit Service |
310c69 |
releaseVDOPageCompletion(completion);
|
|
Packit Service |
310c69 |
continueCompletion(parent, result);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Handle an error fetching a page from the cache. This error handler is
|
|
Packit Service |
310c69 |
* registered in setupMappedBlock().
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The page completion which got an error
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void handlePageError(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
finishProcessingPage(completion, completion->result);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Get the mapping page for a get/put mapped block operation and dispatch to
|
|
Packit Service |
310c69 |
* the appropriate handler.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param dataVIO The dataVIO
|
|
Packit Service |
310c69 |
* @param modifiable Whether we intend to modify the mapping
|
|
Packit Service |
310c69 |
* @param action The handler to process the mapping page
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void setupMappedBlock(DataVIO *dataVIO,
|
|
Packit Service |
310c69 |
bool modifiable,
|
|
Packit Service |
310c69 |
VDOAction *action)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMapZone *zone = getBlockMapForZone(dataVIO->logical.zone);
|
|
Packit Service |
310c69 |
if (isDraining(&zone->state)) {
|
|
Packit Service |
310c69 |
finishDataVIO(dataVIO, VDO_SHUTTING_DOWN);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
initVDOPageCompletion(&dataVIO->pageCompletion, zone->pageCache,
|
|
Packit Service |
310c69 |
dataVIO->treeLock.treeSlots[0].blockMapSlot.pbn,
|
|
Packit Service |
310c69 |
modifiable, dataVIOAsCompletion(dataVIO), action,
|
|
Packit Service |
310c69 |
handlePageError);
|
|
Packit Service |
310c69 |
getVDOPageAsync(&dataVIO->pageCompletion.completion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Decode and validate a block map entry and attempt to use it to set the
|
|
Packit Service |
310c69 |
* mapped location of a DataVIO.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param dataVIO The DataVIO to update with the map entry
|
|
Packit Service |
310c69 |
* @param entry The block map entry for the logical block
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return VDO_SUCCESS or VDO_BAD_MAPPING if the map entry is invalid
|
|
Packit Service |
310c69 |
* or an error code for any other failure
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result))
|
|
Packit Service |
310c69 |
static int setMappedEntry(DataVIO *dataVIO, const BlockMapEntry *entry)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// Unpack the PBN for logging purposes even if the entry is invalid.
|
|
Packit Service |
310c69 |
DataLocation mapped = unpackBlockMapEntry(entry);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (isValidLocation(&mapped)) {
|
|
Packit Service |
310c69 |
int result = setMappedLocation(dataVIO, mapped.pbn, mapped.state);
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Return success and all errors not specifically known to be errors from
|
|
Packit Service |
310c69 |
* validating the location. Yes, this expression is redundant; it is
|
|
Packit Service |
310c69 |
* intentional.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
if ((result == VDO_SUCCESS)
|
|
Packit Service |
310c69 |
|| ((result != VDO_OUT_OF_RANGE) && (result != VDO_BAD_MAPPING))) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Log the corruption even if we wind up ignoring it for write VIOs,
|
|
Packit Service |
310c69 |
// converting all cases to VDO_BAD_MAPPING.
|
|
Packit Service |
310c69 |
logErrorWithStringError(VDO_BAD_MAPPING, "PBN %" PRIu64
|
|
Packit Service |
310c69 |
" with state %u read from the block map was invalid",
|
|
Packit Service |
310c69 |
mapped.pbn, mapped.state);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// A read VIO has no option but to report the bad mapping--reading
|
|
Packit Service |
310c69 |
// zeros would be hiding known data loss.
|
|
Packit Service |
310c69 |
if (isReadDataVIO(dataVIO)) {
|
|
Packit Service |
310c69 |
return VDO_BAD_MAPPING;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// A write VIO only reads this mapping to decref the old block. Treat
|
|
Packit Service |
310c69 |
// this as an unmapped entry rather than fail the write.
|
|
Packit Service |
310c69 |
clearMappedLocation(dataVIO);
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* This callback is registered in getMappedBlockAsync().
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void getMappingFromFetchedPage(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (completion->result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
finishProcessingPage(completion, completion->result);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
const BlockMapPage *page = dereferenceReadableVDOPage(completion);
|
|
Packit Service |
310c69 |
int result = ASSERT(page != NULL, "page available");
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
finishProcessingPage(completion, result);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
DataVIO *dataVIO = asDataVIO(completion->parent);
|
|
Packit Service |
310c69 |
BlockMapTreeSlot *treeSlot = &dataVIO->treeLock.treeSlots[0];
|
|
Packit Service |
310c69 |
const BlockMapEntry *entry = &page->entries[treeSlot->blockMapSlot.slot];
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = setMappedEntry(dataVIO, entry);
|
|
Packit Service |
310c69 |
finishProcessingPage(completion, result);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* This callback is registered in putMappedBlockAsync().
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void putMappingInFetchedPage(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (completion->result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
finishProcessingPage(completion, completion->result);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockMapPage *page = dereferenceWritableVDOPage(completion);
|
|
Packit Service |
310c69 |
int result = ASSERT(page != NULL, "page available");
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
finishProcessingPage(completion, result);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
DataVIO *dataVIO = asDataVIO(completion->parent);
|
|
Packit Service |
310c69 |
BlockMapPageContext *context = getVDOPageCompletionContext(completion);
|
|
Packit Service |
310c69 |
SequenceNumber oldLock = context->recoveryLock;
|
|
Packit Service |
310c69 |
updateBlockMapPage(page, dataVIO, dataVIO->newMapped.pbn,
|
|
Packit Service |
310c69 |
dataVIO->newMapped.state, &context->recoveryLock);
|
|
Packit Service |
310c69 |
markCompletedVDOPageDirty(completion, oldLock, context->recoveryLock);
|
|
Packit Service |
310c69 |
finishProcessingPage(completion, VDO_SUCCESS);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void getMappedBlockAsync(DataVIO *dataVIO)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (dataVIO->treeLock.treeSlots[0].blockMapSlot.pbn == ZERO_BLOCK) {
|
|
Packit Service |
310c69 |
// We know that the block map page for this LBN has not been allocated,
|
|
Packit Service |
310c69 |
// so the block must be unmapped.
|
|
Packit Service |
310c69 |
clearMappedLocation(dataVIO);
|
|
Packit Service |
310c69 |
continueDataVIO(dataVIO, VDO_SUCCESS);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
setupMappedBlock(dataVIO, false, getMappingFromFetchedPage);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void putMappedBlockAsync(DataVIO *dataVIO)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
setupMappedBlock(dataVIO, true, putMappingInFetchedPage);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockMapStatistics getBlockMapStatistics(BlockMap *map)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockMapStatistics stats;
|
|
Packit Service |
310c69 |
memset(&stats, 0, sizeof(BlockMapStatistics));
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < map->zoneCount; zone++) {
|
|
Packit Service |
310c69 |
const AtomicPageCacheStatistics *atoms
|
|
Packit Service |
310c69 |
= getVDOPageCacheStatistics(map->zones[zone].pageCache);
|
|
Packit Service |
310c69 |
stats.dirtyPages += atomicLoad64(&atoms->counts.dirtyPages);
|
|
Packit Service |
310c69 |
stats.cleanPages += atomicLoad64(&atoms->counts.cleanPages);
|
|
Packit Service |
310c69 |
stats.freePages += atomicLoad64(&atoms->counts.freePages);
|
|
Packit Service |
310c69 |
stats.failedPages += atomicLoad64(&atoms->counts.failedPages);
|
|
Packit Service |
310c69 |
stats.incomingPages += atomicLoad64(&atoms->counts.incomingPages);
|
|
Packit Service |
310c69 |
stats.outgoingPages += atomicLoad64(&atoms->counts.outgoingPages);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
stats.cachePressure += atomicLoad64(&atoms->cachePressure);
|
|
Packit Service |
310c69 |
stats.readCount += atomicLoad64(&atoms->readCount);
|
|
Packit Service |
310c69 |
stats.writeCount += atomicLoad64(&atoms->writeCount);
|
|
Packit Service |
310c69 |
stats.failedReads += atomicLoad64(&atoms->failedReads);
|
|
Packit Service |
310c69 |
stats.failedWrites += atomicLoad64(&atoms->failedWrites);
|
|
Packit Service |
310c69 |
stats.reclaimed += atomicLoad64(&atoms->reclaimed);
|
|
Packit Service |
310c69 |
stats.readOutgoing += atomicLoad64(&atoms->readOutgoing);
|
|
Packit Service |
310c69 |
stats.foundInCache += atomicLoad64(&atoms->foundInCache);
|
|
Packit Service |
310c69 |
stats.discardRequired += atomicLoad64(&atoms->discardRequired);
|
|
Packit Service |
310c69 |
stats.waitForPage += atomicLoad64(&atoms->waitForPage);
|
|
Packit Service |
310c69 |
stats.fetchRequired += atomicLoad64(&atoms->fetchRequired);
|
|
Packit Service |
310c69 |
stats.pagesLoaded += atomicLoad64(&atoms->pagesLoaded);
|
|
Packit Service |
310c69 |
stats.pagesSaved += atomicLoad64(&atoms->pagesSaved);
|
|
Packit Service |
310c69 |
stats.flushCount += atomicLoad64(&atoms->flushCount);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return stats;
|
|
Packit Service |
310c69 |
}
|