Blame source/vdo/base/blockMap.c

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
}