Blame source/vdo/base/referenceCountRebuild.c

Packit Service d40955
/*
Packit Service d40955
 * Copyright (c) 2020 Red Hat, Inc.
Packit Service d40955
 *
Packit Service d40955
 * This program is free software; you can redistribute it and/or
Packit Service d40955
 * modify it under the terms of the GNU General Public License
Packit Service d40955
 * as published by the Free Software Foundation; either version 2
Packit Service d40955
 * of the License, or (at your option) any later version.
Packit Service d40955
 * 
Packit Service d40955
 * This program is distributed in the hope that it will be useful,
Packit Service d40955
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service d40955
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service d40955
 * GNU General Public License for more details.
Packit Service d40955
 * 
Packit Service d40955
 * You should have received a copy of the GNU General Public License
Packit Service d40955
 * along with this program; if not, write to the Free Software
Packit Service d40955
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service d40955
 * 02110-1301, USA. 
Packit Service d40955
 *
Packit Service d40955
 * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/referenceCountRebuild.c#6 $
Packit Service d40955
 */
Packit Service d40955
Packit Service d40955
#include "referenceCountRebuild.h"
Packit Service d40955
Packit Service d40955
#include "logger.h"
Packit Service d40955
#include "memoryAlloc.h"
Packit Service d40955
Packit Service d40955
#include "blockMap.h"
Packit Service d40955
#include "blockMapInternals.h"
Packit Service d40955
#include "blockMapPage.h"
Packit Service d40955
#include "forest.h"
Packit Service d40955
#include "constants.h"
Packit Service d40955
#include "numUtils.h"
Packit Service d40955
#include "refCounts.h"
Packit Service d40955
#include "slabDepot.h"
Packit Service d40955
#include "vdoInternal.h"
Packit Service d40955
#include "vdoPageCache.h"
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * A reference count rebuild completion.
Packit Service d40955
 * Note that the page completions kept in this structure are not immediately
Packit Service d40955
 * freed, so the corresponding pages will be locked down in the page cache
Packit Service d40955
 * until the rebuild frees them.
Packit Service d40955
 **/
Packit Service d40955
typedef struct {
Packit Service d40955
  /** completion header */
Packit Service d40955
  VDOCompletion      completion;
Packit Service d40955
  /** the completion for flushing the block map */
Packit Service d40955
  VDOCompletion      subTaskCompletion;
Packit Service d40955
  /** the thread on which all block map operations must be done */
Packit Service d40955
  ThreadID           logicalThreadID;
Packit Service d40955
  /** the admin thread */
Packit Service d40955
  ThreadID           adminThreadID;
Packit Service d40955
  /** the block map */
Packit Service d40955
  BlockMap          *blockMap;
Packit Service d40955
  /** the slab depot */
Packit Service d40955
  SlabDepot         *depot;
Packit Service d40955
  /** whether this recovery has been aborted */
Packit Service d40955
  bool               aborted;
Packit Service d40955
  /** whether we are currently launching the initial round of requests */
Packit Service d40955
  bool               launching;
Packit Service d40955
  /** The number of logical blocks observed used */
Packit Service d40955
  BlockCount        *logicalBlocksUsed;
Packit Service d40955
  /** The number of block map data blocks */
Packit Service d40955
  BlockCount        *blockMapDataBlocks;
Packit Service d40955
  /** the next page to fetch */
Packit Service d40955
  PageCount          pageToFetch;
Packit Service d40955
  /** the number of leaf pages in the block map */
Packit Service d40955
  PageCount          leafPages;
Packit Service d40955
  /** the last slot of the block map */
Packit Service d40955
  BlockMapSlot       lastSlot;
Packit Service d40955
  /** number of pending (non-ready) requests*/
Packit Service d40955
  PageCount          outstanding;
Packit Service d40955
  /** number of page completions */
Packit Service d40955
  PageCount          pageCount;
Packit Service d40955
  /** array of requested, potentially ready page completions */
Packit Service d40955
  VDOPageCompletion  pageCompletions[];
Packit Service d40955
} RebuildCompletion;
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Convert a VDOCompletion to a RebuildCompletion.
Packit Service d40955
 *
Packit Service d40955
 * @param completion  The completion to convert
Packit Service d40955
 *
Packit Service d40955
 * @return The completion as a RebuildCompletion
Packit Service d40955
 **/
Packit Service d40955
__attribute__((warn_unused_result))
Packit Service d40955
static inline RebuildCompletion *asRebuildCompletion(VDOCompletion *completion)
Packit Service d40955
{
Packit Service d40955
  STATIC_ASSERT(offsetof(RebuildCompletion, completion) == 0);
Packit Service d40955
  assertCompletionType(completion->type, REFERENCE_COUNT_REBUILD_COMPLETION);
Packit Service d40955
  return (RebuildCompletion *) completion;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Free a RebuildCompletion and null out the reference to it.
Packit Service d40955
 *
Packit Service d40955
 * @param completionPtr  a pointer to the completion to free
Packit Service d40955
 **/
Packit Service d40955
static void freeRebuildCompletion(VDOCompletion **completionPtr)
Packit Service d40955
{
Packit Service d40955
  VDOCompletion *completion = *completionPtr;
Packit Service d40955
  if (completion == NULL) {
Packit Service d40955
    return;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  RebuildCompletion *rebuild = asRebuildCompletion(completion);
Packit Service d40955
  destroyEnqueueable(&rebuild->subTaskCompletion);
Packit Service d40955
  destroyEnqueueable(completion);
Packit Service d40955
  FREE(rebuild);
Packit Service d40955
  *completionPtr = NULL;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Free the RebuildCompletion and notify the parent that the block map
Packit Service d40955
 * rebuild is done. This callback is registered in rebuildBlockMap().
Packit Service d40955
 *
Packit Service d40955
 * @param completion  The RebuildCompletion
Packit Service d40955
 **/
Packit Service d40955
static void finishRebuild(VDOCompletion *completion)
Packit Service d40955
{
Packit Service d40955
  int            result = completion->result;
Packit Service d40955
  VDOCompletion *parent = completion->parent;
Packit Service d40955
  freeRebuildCompletion(&completion);
Packit Service d40955
  finishCompletion(parent, result);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Make a new rebuild completion.
Packit Service d40955
 *
Packit Service d40955
 * @param [in]  vdo                 The VDO
Packit Service d40955
 * @param [in]  logicalBlocksUsed   A pointer to hold the logical blocks used
Packit Service d40955
 * @param [in]  blockMapDataBlocks  A pointer to hold the number of block map
Packit Service d40955
 *                                  data blocks
Packit Service d40955
 * @param [in]  parent              The parent of the rebuild completion
Packit Service d40955
 * @param [out] rebuildPtr          The new block map rebuild completion
Packit Service d40955
 *
Packit Service d40955
 * @return a success or error code
Packit Service d40955
 **/
Packit Service d40955
static int makeRebuildCompletion(VDO                *vdo,
Packit Service d40955
                                 BlockCount         *logicalBlocksUsed,
Packit Service d40955
                                 BlockCount         *blockMapDataBlocks,
Packit Service d40955
                                 VDOCompletion      *parent,
Packit Service d40955
                                 RebuildCompletion **rebuildPtr)
Packit Service d40955
{
Packit Service d40955
  BlockMap *blockMap = getBlockMap(vdo);
Packit Service d40955
  PageCount pageCount
Packit Service d40955
    = minPageCount(getConfiguredCacheSize(vdo) >> 1,
Packit Service d40955
                   MAXIMUM_SIMULTANEOUS_BLOCK_MAP_RESTORATION_READS);
Packit Service d40955
Packit Service d40955
  RebuildCompletion *rebuild;
Packit Service d40955
  int result = ALLOCATE_EXTENDED(RebuildCompletion, pageCount,
Packit Service d40955
                                 VDOPageCompletion, __func__, &rebuild);
Packit Service d40955
  if (result != UDS_SUCCESS) {
Packit Service d40955
    return result;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  result = initializeEnqueueableCompletion(&rebuild->completion,
Packit Service d40955
                                           REFERENCE_COUNT_REBUILD_COMPLETION,
Packit Service d40955
                                           vdo->layer);
Packit Service d40955
  if (result != VDO_SUCCESS) {
Packit Service d40955
    VDOCompletion *completion = &rebuild->completion;
Packit Service d40955
    freeRebuildCompletion(&completion);
Packit Service d40955
    return result;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  result = initializeEnqueueableCompletion(&rebuild->subTaskCompletion,
Packit Service d40955
                                           SUB_TASK_COMPLETION, vdo->layer);
Packit Service d40955
  if (result != VDO_SUCCESS) {
Packit Service d40955
    VDOCompletion *completion = &rebuild->completion;
Packit Service d40955
    freeRebuildCompletion(&completion);
Packit Service d40955
    return result;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  rebuild->blockMap           = blockMap;
Packit Service d40955
  rebuild->depot              = vdo->depot;
Packit Service d40955
  rebuild->logicalBlocksUsed  = logicalBlocksUsed;
Packit Service d40955
  rebuild->blockMapDataBlocks = blockMapDataBlocks;
Packit Service d40955
  rebuild->pageCount          = pageCount;
Packit Service d40955
  rebuild->leafPages          = computeBlockMapPageCount(blockMap->entryCount);
Packit Service d40955
Packit Service d40955
  const ThreadConfig *threadConfig = getThreadConfig(vdo);
Packit Service d40955
  rebuild->logicalThreadID         = getLogicalZoneThread(threadConfig, 0);
Packit Service d40955
  rebuild->adminThreadID           = getAdminThread(threadConfig);
Packit Service d40955
Packit Service d40955
  ASSERT_LOG_ONLY((getCallbackThreadID() == rebuild->logicalThreadID),
Packit Service d40955
                  "%s must be called on logical thread %u (not %u)", __func__,
Packit Service d40955
                  rebuild->logicalThreadID, getCallbackThreadID());
Packit Service d40955
  prepareCompletion(&rebuild->completion, finishRebuild, finishRebuild,
Packit Service d40955
                    rebuild->logicalThreadID, parent);
Packit Service d40955
Packit Service d40955
  *rebuildPtr = rebuild;
Packit Service d40955
  return VDO_SUCCESS;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Flush the block map now that all the reference counts are rebuilt. This
Packit Service d40955
 * callback is registered in finishIfDone().
Packit Service d40955
 *
Packit Service d40955
 * @param completion  The sub-task completion
Packit Service d40955
 **/
Packit Service d40955
static void flushBlockMapUpdates(VDOCompletion *completion)
Packit Service d40955
{
Packit Service d40955
  logInfo("Flushing block map changes");
Packit Service d40955
  prepareToFinishParent(completion, completion->parent);
Packit Service d40955
  drainBlockMap(asRebuildCompletion(completion->parent)->blockMap,
Packit Service d40955
                ADMIN_STATE_RECOVERING, completion);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Check whether the rebuild is done. If it succeeded, continue by flushing the
Packit Service d40955
 * block map.
Packit Service d40955
 *
Packit Service d40955
 * @param rebuild  The rebuild completion
Packit Service d40955
 *
Packit Service d40955
 * @return true if the rebuild is complete
Packit Service d40955
 **/
Packit Service d40955
static bool finishIfDone(RebuildCompletion *rebuild)
Packit Service d40955
{
Packit Service d40955
  if (rebuild->launching || (rebuild->outstanding > 0)) {
Packit Service d40955
    return false;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  if (rebuild->aborted) {
Packit Service d40955
    completeCompletion(&rebuild->completion);
Packit Service d40955
    return true;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  if (rebuild->pageToFetch < rebuild->leafPages) {
Packit Service d40955
    return false;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  prepareCompletion(&rebuild->subTaskCompletion, flushBlockMapUpdates,
Packit Service d40955
                    finishParentCallback, rebuild->adminThreadID, rebuild);
Packit Service d40955
  invokeCallback(&rebuild->subTaskCompletion);
Packit Service d40955
  return true;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Record that there has been an error during the rebuild.
Packit Service d40955
 *
Packit Service d40955
 * @param rebuild  The rebuild completion
Packit Service d40955
 * @param result   The error result to use, if one is not already saved
Packit Service d40955
 **/
Packit Service d40955
static void abortRebuild(RebuildCompletion *rebuild, int result)
Packit Service d40955
{
Packit Service d40955
  rebuild->aborted = true;
Packit Service d40955
  setCompletionResult(&rebuild->completion, result);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Handle an error loading a page.
Packit Service d40955
 *
Packit Service d40955
 * @param completion  The VDOPageCompletion
Packit Service d40955
 **/
Packit Service d40955
static void handlePageLoadError(VDOCompletion *completion)
Packit Service d40955
{
Packit Service d40955
  RebuildCompletion *rebuild = asRebuildCompletion(completion->parent);
Packit Service d40955
  rebuild->outstanding--;
Packit Service d40955
  abortRebuild(rebuild, completion->result);
Packit Service d40955
  releaseVDOPageCompletion(completion);
Packit Service d40955
  finishIfDone(rebuild);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Rebuild reference counts from a block map page.
Packit Service d40955
 *
Packit Service d40955
 * @param rebuild     The rebuild completion
Packit Service d40955
 * @param completion  The page completion holding the page
Packit Service d40955
 *
Packit Service d40955
 * @return VDO_SUCCESS or an error
Packit Service d40955
 **/
Packit Service d40955
static int rebuildReferenceCountsFromPage(RebuildCompletion *rebuild,
Packit Service d40955
                                          VDOCompletion     *completion)
Packit Service d40955
{
Packit Service d40955
  BlockMapPage *page = dereferenceWritableVDOPage(completion);
Packit Service d40955
  int result = ASSERT(page != NULL, "page available");
Packit Service d40955
  if (result != VDO_SUCCESS) {
Packit Service d40955
    return result;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  if (!isBlockMapPageInitialized(page)) {
Packit Service d40955
    return VDO_SUCCESS;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  // Remove any bogus entries which exist beyond the end of the logical space.
Packit Service d40955
  if (getBlockMapPagePBN(page) == rebuild->lastSlot.pbn) {
Packit Service d40955
    for (SlotNumber slot = rebuild->lastSlot.slot;
Packit Service d40955
         slot < BLOCK_MAP_ENTRIES_PER_PAGE; slot++) {
Packit Service d40955
      DataLocation mapping = unpackBlockMapEntry(&page->entries[slot]);
Packit Service d40955
      if (isMappedLocation(&mapping)) {
Packit Service d40955
        page->entries[slot] = packPBN(ZERO_BLOCK, MAPPING_STATE_UNMAPPED);
Packit Service d40955
        requestVDOPageWrite(completion);
Packit Service d40955
      }
Packit Service d40955
    }
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  // Inform the slab depot of all entries on this page.
Packit Service d40955
  for (SlotNumber slot = 0; slot < BLOCK_MAP_ENTRIES_PER_PAGE; slot++) {
Packit Service d40955
    DataLocation mapping = unpackBlockMapEntry(&page->entries[slot]);
Packit Service d40955
    if (!isValidLocation(&mapping)) {
Packit Service d40955
      // This entry is invalid, so remove it from the page.
Packit Service d40955
      page->entries[slot] = packPBN(ZERO_BLOCK, MAPPING_STATE_UNMAPPED);
Packit Service d40955
      requestVDOPageWrite(completion);
Packit Service d40955
      continue;
Packit Service d40955
    }
Packit Service d40955
Packit Service d40955
    if (!isMappedLocation(&mapping)) {
Packit Service d40955
      continue;
Packit Service d40955
    }
Packit Service d40955
Packit Service d40955
    (*rebuild->logicalBlocksUsed)++;
Packit Service d40955
    if (mapping.pbn == ZERO_BLOCK) {
Packit Service d40955
      continue;
Packit Service d40955
    }
Packit Service d40955
Packit Service d40955
    if (!isPhysicalDataBlock(rebuild->depot, mapping.pbn)) {
Packit Service d40955
      // This is a nonsense mapping. Remove it from the map so we're at least
Packit Service d40955
      // consistent and mark the page dirty.
Packit Service d40955
      page->entries[slot] = packPBN(ZERO_BLOCK, MAPPING_STATE_UNMAPPED);
Packit Service d40955
      requestVDOPageWrite(completion);
Packit Service d40955
      continue;
Packit Service d40955
    }
Packit Service d40955
Packit Service d40955
    Slab *slab   = getSlab(rebuild->depot, mapping.pbn);
Packit Service d40955
    int   result = adjustReferenceCountForRebuild(slab->referenceCounts,
Packit Service d40955
                                                  mapping.pbn, DATA_INCREMENT);
Packit Service d40955
    if (result != VDO_SUCCESS) {
Packit Service d40955
      logErrorWithStringError(result,
Packit Service d40955
                              "Could not adjust reference count for PBN"
Packit Service d40955
                              " %llu, slot %u mapped to PBN %llu",
Packit Service d40955
                              getBlockMapPagePBN(page), slot, mapping.pbn);
Packit Service d40955
      page->entries[slot] = packPBN(ZERO_BLOCK, MAPPING_STATE_UNMAPPED);
Packit Service d40955
      requestVDOPageWrite(completion);
Packit Service d40955
    }
Packit Service d40955
  }
Packit Service d40955
  return VDO_SUCCESS;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
static void fetchPage(RebuildCompletion *rebuild, VDOCompletion *completion);
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Process a page which has just been loaded. This callback is registered by
Packit Service d40955
 * fetchPage().
Packit Service d40955
 *
Packit Service d40955
 * @param completion  The VDOPageCompletion for the fetched page
Packit Service d40955
 **/
Packit Service d40955
static void pageLoaded(VDOCompletion *completion)
Packit Service d40955
{
Packit Service d40955
  RebuildCompletion *rebuild = asRebuildCompletion(completion->parent);
Packit Service d40955
  rebuild->outstanding--;
Packit Service d40955
Packit Service d40955
  int result = rebuildReferenceCountsFromPage(rebuild, completion);
Packit Service d40955
  if (result != VDO_SUCCESS) {
Packit Service d40955
    abortRebuild(rebuild, result);
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  releaseVDOPageCompletion(completion);
Packit Service d40955
  if (finishIfDone(rebuild)) {
Packit Service d40955
    return;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  // Advance progress to the next page, and fetch the next page we
Packit Service d40955
  // haven't yet requested.
Packit Service d40955
  fetchPage(rebuild, completion);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Fetch a page from the block map.
Packit Service d40955
 *
Packit Service d40955
 * @param rebuild     the RebuildCompletion
Packit Service d40955
 * @param completion  the page completion to use
Packit Service d40955
 **/
Packit Service d40955
static void fetchPage(RebuildCompletion *rebuild, VDOCompletion *completion)
Packit Service d40955
{
Packit Service d40955
  while (rebuild->pageToFetch < rebuild->leafPages) {
Packit Service d40955
    PhysicalBlockNumber pbn = findBlockMapPagePBN(rebuild->blockMap,
Packit Service d40955
                                                  rebuild->pageToFetch++);
Packit Service d40955
    if (pbn == ZERO_BLOCK) {
Packit Service d40955
      continue;
Packit Service d40955
    }
Packit Service d40955
Packit Service d40955
    if (!isPhysicalDataBlock(rebuild->depot, pbn)) {
Packit Service d40955
      abortRebuild(rebuild, VDO_BAD_MAPPING);
Packit Service d40955
      if (finishIfDone(rebuild)) {
Packit Service d40955
        return;
Packit Service d40955
      }
Packit Service d40955
      continue;
Packit Service d40955
    }
Packit Service d40955
Packit Service d40955
    initVDOPageCompletion(((VDOPageCompletion *) completion),
Packit Service d40955
                          rebuild->blockMap->zones[0].pageCache,
Packit Service d40955
                          pbn, true, &rebuild->completion,
Packit Service d40955
                          pageLoaded, handlePageLoadError);
Packit Service d40955
    rebuild->outstanding++;
Packit Service d40955
    getVDOPageAsync(completion);
Packit Service d40955
    return;
Packit Service d40955
  }
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Rebuild reference counts from the leaf block map pages now that reference
Packit Service d40955
 * counts have been rebuilt from the interior tree pages (which have been
Packit Service d40955
 * loaded in the process). This callback is registered in
Packit Service d40955
 * rebuildReferenceCounts().
Packit Service d40955
 *
Packit Service d40955
 * @param completion  The sub-task completion
Packit Service d40955
 **/
Packit Service d40955
static void rebuildFromLeaves(VDOCompletion *completion)
Packit Service d40955
{
Packit Service d40955
  RebuildCompletion *rebuild = asRebuildCompletion(completion->parent);
Packit Service d40955
  *rebuild->logicalBlocksUsed = 0;
Packit Service d40955
Packit Service d40955
  // The PBN calculation doesn't work until the tree pages have been loaded,
Packit Service d40955
  // so we can't set this value at the start of rebuild.
Packit Service d40955
  rebuild->lastSlot = (BlockMapSlot) {
Packit Service d40955
    .slot = rebuild->blockMap->entryCount % BLOCK_MAP_ENTRIES_PER_PAGE,
Packit Service d40955
    .pbn  = findBlockMapPagePBN(rebuild->blockMap, rebuild->leafPages - 1),
Packit Service d40955
  };
Packit Service d40955
Packit Service d40955
  // Prevent any page from being processed until all pages have been launched.
Packit Service d40955
  rebuild->launching = true;
Packit Service d40955
  for (PageCount i = 0; i < rebuild->pageCount; i++) {
Packit Service d40955
    fetchPage(rebuild, &rebuild->pageCompletions[i].completion);
Packit Service d40955
  }
Packit Service d40955
  rebuild->launching = false;
Packit Service d40955
  finishIfDone(rebuild);
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**
Packit Service d40955
 * Process a single entry from the block map tree.
Packit Service d40955
 *
Packit Service d40955
 * 

Implements EntryCallback.

Packit Service d40955
 *
Packit Service d40955
 * @param pbn         A pbn which holds a block map tree page
Packit Service d40955
 * @param completion  The parent completion of the traversal
Packit Service d40955
 *
Packit Service d40955
 * @return VDO_SUCCESS or an error
Packit Service d40955
 **/
Packit Service d40955
static int processEntry(PhysicalBlockNumber pbn, VDOCompletion *completion)
Packit Service d40955
{
Packit Service d40955
  RebuildCompletion *rebuild = asRebuildCompletion(completion->parent);
Packit Service d40955
  if ((pbn == ZERO_BLOCK) || !isPhysicalDataBlock(rebuild->depot, pbn)) {
Packit Service d40955
    return logErrorWithStringError(VDO_BAD_CONFIGURATION,
Packit Service d40955
                                   "PBN %llu out of range",
Packit Service d40955
                                   pbn);
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  Slab *slab   = getSlab(rebuild->depot, pbn);
Packit Service d40955
  int   result = adjustReferenceCountForRebuild(slab->referenceCounts, pbn,
Packit Service d40955
                                                BLOCK_MAP_INCREMENT);
Packit Service d40955
  if (result != VDO_SUCCESS) {
Packit Service d40955
    return logErrorWithStringError(result,
Packit Service d40955
                                   "Could not adjust reference count for "
Packit Service d40955
                                   "block map tree PBN %llu",
Packit Service d40955
                                   pbn);
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  (*rebuild->blockMapDataBlocks)++;
Packit Service d40955
  return VDO_SUCCESS;
Packit Service d40955
}
Packit Service d40955
Packit Service d40955
/**********************************************************************/
Packit Service d40955
void rebuildReferenceCounts(VDO           *vdo,
Packit Service d40955
                            VDOCompletion *parent,
Packit Service d40955
                            BlockCount    *logicalBlocksUsed,
Packit Service d40955
                            BlockCount    *blockMapDataBlocks)
Packit Service d40955
{
Packit Service d40955
  RebuildCompletion *rebuild;
Packit Service d40955
  int result = makeRebuildCompletion(vdo, logicalBlocksUsed,
Packit Service d40955
                                     blockMapDataBlocks, parent, &rebuild);
Packit Service d40955
  if (result != VDO_SUCCESS) {
Packit Service d40955
    finishCompletion(parent, result);
Packit Service d40955
    return;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  // Completion chaining from page cache hits can lead to stack overflow
Packit Service d40955
  // during the rebuild, so clear out the cache before this rebuild phase.
Packit Service d40955
  result = invalidateVDOPageCache(rebuild->blockMap->zones[0].pageCache);
Packit Service d40955
  if (result != VDO_SUCCESS) {
Packit Service d40955
    finishCompletion(parent, result);
Packit Service d40955
    return;
Packit Service d40955
  }
Packit Service d40955
Packit Service d40955
  // First traverse the block map trees.
Packit Service d40955
  *rebuild->blockMapDataBlocks = 0;
Packit Service d40955
  VDOCompletion *completion = &rebuild->subTaskCompletion;
Packit Service d40955
  prepareCompletion(completion, rebuildFromLeaves, finishParentCallback,
Packit Service d40955
                    rebuild->logicalThreadID, rebuild);
Packit Service d40955
  traverseForest(rebuild->blockMap, processEntry, completion);
Packit Service d40955
}