Blame source/vdo/base/forest.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/forest.c#8 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "forest.h"
Packit Service 310c69
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
Packit Service 310c69
#include "blockMap.h"
Packit Service 310c69
#include "blockMapInternals.h"
Packit Service 310c69
#include "blockMapPage.h"
Packit Service 310c69
#include "blockMapTree.h"
Packit Service 310c69
#include "blockMapTreeInternals.h"
Packit Service 310c69
#include "constants.h"
Packit Service 310c69
#include "dirtyLists.h"
Packit Service 310c69
#include "forest.h"
Packit Service 310c69
#include "numUtils.h"
Packit Service 310c69
#include "recoveryJournal.h"
Packit Service 310c69
#include "slabDepot.h"
Packit Service 310c69
#include "slabJournal.h"
Packit Service 310c69
#include "types.h"
Packit Service 310c69
#include "vdoInternal.h"
Packit Service 310c69
#include "vio.h"
Packit Service 310c69
#include "vioPool.h"
Packit Service 310c69
Packit Service 310c69
enum {
Packit Service 310c69
  BLOCK_MAP_VIO_POOL_SIZE = 64,
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
typedef struct {
Packit Service 310c69
  TreePage *levels[BLOCK_MAP_TREE_HEIGHT];
Packit Service 310c69
} BlockMapTreeSegment;
Packit Service 310c69
Packit Service 310c69
typedef struct blockMapTree {
Packit Service 310c69
  BlockMapTreeSegment *segments;
Packit Service 310c69
} BlockMapTree;
Packit Service 310c69
Packit Service 310c69
struct forest {
Packit Service 310c69
  BlockMap      *map;
Packit Service 310c69
  size_t         segments;
Packit Service 310c69
  Boundary      *boundaries;
Packit Service 310c69
  TreePage     **pages;
Packit Service 310c69
  BlockMapTree   trees[];
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
typedef struct {
Packit Service 310c69
  PageNumber pageIndex;
Packit Service 310c69
  SlotNumber slot;
Packit Service 310c69
} CursorLevel;
Packit Service 310c69
Packit Service 310c69
typedef struct cursors Cursors;
Packit Service 310c69
Packit Service 310c69
typedef struct {
Packit Service 310c69
  Waiter        waiter;
Packit Service 310c69
  BlockMapTree *tree;
Packit Service 310c69
  Height        height;
Packit Service 310c69
  Cursors      *parent;
Packit Service 310c69
  Boundary      boundary;
Packit Service 310c69
  CursorLevel   levels[BLOCK_MAP_TREE_HEIGHT];
Packit Service 310c69
  VIOPoolEntry *vioPoolEntry;
Packit Service 310c69
} Cursor;
Packit Service 310c69
Packit Service 310c69
struct cursors {
Packit Service 310c69
  BlockMap         *map;
Packit Service 310c69
  BlockMapTreeZone *zone;
Packit Service 310c69
  VIOPool          *pool;
Packit Service 310c69
  EntryCallback    *entryCallback;
Packit Service 310c69
  VDOCompletion    *parent;
Packit Service 310c69
  RootCount         activeRoots;
Packit Service 310c69
  Cursor            cursors[];
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
TreePage *getTreePageByIndex(Forest       *forest,
Packit Service 310c69
                             RootCount     rootIndex,
Packit Service 310c69
                             Height        height,
Packit Service 310c69
                             PageNumber    pageIndex)
Packit Service 310c69
{
Packit Service 310c69
  PageNumber offset = 0;
Packit Service 310c69
  for (size_t segment = 0; segment < forest->segments; segment++) {
Packit Service 310c69
    PageNumber border = forest->boundaries[segment].levels[height - 1];
Packit Service 310c69
    if (pageIndex < border) {
Packit Service 310c69
      BlockMapTree *tree = &forest->trees[rootIndex];
Packit Service 310c69
      return &(tree->segments[segment].levels[height - 1][pageIndex - offset]);
Packit Service 310c69
    }
Packit Service 310c69
    offset = border;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return NULL;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Compute the number of pages which must be allocated at each level in order
Packit Service 310c69
 * to grow the forest to a new number of entries.
Packit Service 310c69
 *
Packit Service 310c69
 * @param [in]  rootCount      The number of roots
Packit Service 310c69
 * @param [in]  flatPageCount  The number of flat block map pages
Packit Service 310c69
 * @param [in]  oldSizes       The current size of the forest at each level
Packit Service 310c69
 * @param [in]  entries        The new number of entries the block map must
Packit Service 310c69
 *                             address
Packit Service 310c69
 * @param [out] newSizes       The new size of the forest at each level
Packit Service 310c69
 *
Packit Service 310c69
 * @return The total number of non-leaf pages required
Packit Service 310c69
 **/
Packit Service 310c69
static BlockCount computeNewPages(RootCount   rootCount,
Packit Service 310c69
                                  BlockCount  flatPageCount,
Packit Service 310c69
                                  Boundary   *oldSizes,
Packit Service 310c69
                                  BlockCount  entries,
Packit Service 310c69
                                  Boundary   *newSizes)
Packit Service 310c69
{
Packit Service 310c69
  PageCount leafPages
Packit Service 310c69
    = maxPageCount(computeBlockMapPageCount(entries) - flatPageCount, 1);
Packit Service 310c69
  PageCount  levelSize  = computeBucketCount(leafPages, rootCount);
Packit Service 310c69
  BlockCount totalPages = 0;
Packit Service 310c69
  for (Height height = 0; height < BLOCK_MAP_TREE_HEIGHT; height++) {
Packit Service 310c69
    levelSize = computeBucketCount(levelSize, BLOCK_MAP_ENTRIES_PER_PAGE);
Packit Service 310c69
    newSizes->levels[height] = levelSize;
Packit Service 310c69
    BlockCount newPages = levelSize;
Packit Service 310c69
    if (oldSizes != NULL) {
Packit Service 310c69
      newPages -= oldSizes->levels[height];
Packit Service 310c69
    }
Packit Service 310c69
    totalPages += (newPages * rootCount);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return totalPages;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int makeSegment(Forest      *oldForest,
Packit Service 310c69
                       BlockCount   newPages,
Packit Service 310c69
                       Boundary    *newBoundary,
Packit Service 310c69
                       Forest      *forest)
Packit Service 310c69
{
Packit Service 310c69
  size_t index     = (oldForest == NULL) ? 0 : oldForest->segments;
Packit Service 310c69
  forest->segments = index + 1;
Packit Service 310c69
Packit Service 310c69
  int result = ALLOCATE(forest->segments, Boundary, "forest boundary array",
Packit Service 310c69
                        &forest->boundaries);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = ALLOCATE(forest->segments, TreePage *, "forest page pointers",
Packit Service 310c69
                    &forest->pages);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = ALLOCATE(newPages, TreePage, "new forest pages",
Packit Service 310c69
                    &forest->pages[index]);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (index > 0) {
Packit Service 310c69
    memcpy(forest->boundaries, oldForest->boundaries,
Packit Service 310c69
           index * sizeof(Boundary));
Packit Service 310c69
    memcpy(forest->pages, oldForest->pages, index * sizeof(TreePage *));
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  memcpy(&(forest->boundaries[index]), newBoundary, sizeof(Boundary));
Packit Service 310c69
Packit Service 310c69
  PageCount segmentSizes[BLOCK_MAP_TREE_HEIGHT];
Packit Service 310c69
  for (Height height = 0; height < BLOCK_MAP_TREE_HEIGHT; height++) {
Packit Service 310c69
    segmentSizes[height] = newBoundary->levels[height];
Packit Service 310c69
    if (index > 0) {
Packit Service 310c69
      segmentSizes[height] -= oldForest->boundaries[index - 1].levels[height];
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  TreePage *pagePtr = forest->pages[index];
Packit Service 310c69
  for (RootCount root = 0; root < forest->map->rootCount; root++) {
Packit Service 310c69
    BlockMapTree *tree = &(forest->trees[root]);
Packit Service 310c69
    int result = ALLOCATE(forest->segments, BlockMapTreeSegment,
Packit Service 310c69
                          "tree root segments", &tree->segments);
Packit Service 310c69
    if (result != VDO_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    if (index > 0) {
Packit Service 310c69
      memcpy(tree->segments, oldForest->trees[root].segments,
Packit Service 310c69
             index * sizeof(BlockMapTreeSegment));
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    BlockMapTreeSegment *segment = &(tree->segments[index]);
Packit Service 310c69
    for (Height height = 0; height < BLOCK_MAP_TREE_HEIGHT; height++) {
Packit Service 310c69
      if (segmentSizes[height] == 0) {
Packit Service 310c69
        continue;
Packit Service 310c69
      }
Packit Service 310c69
Packit Service 310c69
      segment->levels[height] = pagePtr;
Packit Service 310c69
      if (height == (BLOCK_MAP_TREE_HEIGHT - 1)) {
Packit Service 310c69
        // Record the root.
Packit Service 310c69
        BlockMapPage *page = formatBlockMapPage(pagePtr->pageBuffer,
Packit Service 310c69
                                                forest->map->nonce,
Packit Service 310c69
                                                INVALID_PBN, true);
Packit Service 310c69
        page->entries[0] = packPBN(forest->map->rootOrigin + root,
Packit Service 310c69
                                   MAPPING_STATE_UNCOMPRESSED);
Packit Service 310c69
      }
Packit Service 310c69
      pagePtr += segmentSizes[height];
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void deforest(Forest *forest, size_t firstPageSegment)
Packit Service 310c69
{
Packit Service 310c69
  if (forest->pages != NULL) {
Packit Service 310c69
    for (size_t segment = firstPageSegment; segment < forest->segments;
Packit Service 310c69
         segment++) {
Packit Service 310c69
      FREE(forest->pages[segment]);
Packit Service 310c69
    }
Packit Service 310c69
    FREE(forest->pages);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  for (RootCount root = 0; root < forest->map->rootCount; root++) {
Packit Service 310c69
    BlockMapTree *tree = &(forest->trees[root]);
Packit Service 310c69
    FREE(tree->segments);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  FREE(forest->boundaries);
Packit Service 310c69
  FREE(forest);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int makeForest(BlockMap *map, BlockCount entries)
Packit Service 310c69
{
Packit Service 310c69
  STATIC_ASSERT(offsetof(TreePage, waiter) == 0);
Packit Service 310c69
Packit Service 310c69
  Forest   *oldForest   = map->forest;
Packit Service 310c69
  Boundary *oldBoundary = NULL;
Packit Service 310c69
  if (oldForest != NULL) {
Packit Service 310c69
    oldBoundary = &(oldForest->boundaries[oldForest->segments - 1]);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Boundary newBoundary;
Packit Service 310c69
  BlockCount newPages = computeNewPages(map->rootCount, map->flatPageCount,
Packit Service 310c69
                                        oldBoundary, entries, &newBoundary);
Packit Service 310c69
  if (newPages == 0) {
Packit Service 310c69
    map->nextEntryCount = entries;
Packit Service 310c69
    return VDO_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Forest *forest;
Packit Service 310c69
  int result = ALLOCATE_EXTENDED(Forest, map->rootCount, BlockMapTree,
Packit Service 310c69
                                 __func__, &forest);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  forest->map = map;
Packit Service 310c69
  result = makeSegment(oldForest, newPages, &newBoundary, forest);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    deforest(forest, forest->segments - 1);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  map->nextForest     = forest;
Packit Service 310c69
  map->nextEntryCount = entries;
Packit Service 310c69
  return VDO_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void freeForest(Forest **forestPtr)
Packit Service 310c69
{
Packit Service 310c69
  Forest *forest = *forestPtr;
Packit Service 310c69
  if (forest == NULL) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  deforest(forest, 0);
Packit Service 310c69
  *forestPtr = NULL;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void abandonForest(BlockMap *map)
Packit Service 310c69
{
Packit Service 310c69
  Forest *forest = map->nextForest;
Packit Service 310c69
  map->nextForest = NULL;
Packit Service 310c69
  if (forest != NULL) {
Packit Service 310c69
    deforest(forest, forest->segments - 1);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  map->nextEntryCount = 0;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void replaceForest(BlockMap *map)
Packit Service 310c69
{
Packit Service 310c69
  if (map->nextForest != NULL) {
Packit Service 310c69
    if (map->forest != NULL) {
Packit Service 310c69
      deforest(map->forest, map->forest->segments);
Packit Service 310c69
    }
Packit Service 310c69
    map->forest     = map->nextForest;
Packit Service 310c69
    map->nextForest = NULL;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  map->entryCount     = map->nextEntryCount;
Packit Service 310c69
  map->nextEntryCount = 0;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Finish the traversal of a single tree. If it was the last cursor, finish
Packit Service 310c69
 * the traversal.
Packit Service 310c69
 *
Packit Service 310c69
 * @param cursor  The cursor doing the traversal
Packit Service 310c69
 **/
Packit Service 310c69
static void finishCursor(Cursor *cursor)
Packit Service 310c69
{
Packit Service 310c69
  Cursors *cursors = cursor->parent;
Packit Service 310c69
  returnVIOToPool(cursors->pool, cursor->vioPoolEntry);
Packit Service 310c69
  if (--cursors->activeRoots > 0) {
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  VDOCompletion *parent = cursors->parent;
Packit Service 310c69
  FREE(cursors);
Packit Service 310c69
Packit Service 310c69
  finishCompletion(parent, VDO_SUCCESS);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void traverse(Cursor *cursor);
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Continue traversing a block map tree.
Packit Service 310c69
 *
Packit Service 310c69
 * @param completion  The VIO doing a read or write
Packit Service 310c69
 **/
Packit Service 310c69
static void continueTraversal(VDOCompletion *completion)
Packit Service 310c69
{
Packit Service 310c69
  VIOPoolEntry *poolEntry = completion->parent;
Packit Service 310c69
  Cursor       *cursor    = poolEntry->parent;
Packit Service 310c69
  traverse(cursor);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Continue traversing a block map tree now that a page has been loaded.
Packit Service 310c69
 *
Packit Service 310c69
 * @param completion  The VIO doing the read
Packit Service 310c69
 **/
Packit Service 310c69
static void finishTraversalLoad(VDOCompletion *completion)
Packit Service 310c69
{
Packit Service 310c69
  VIOPoolEntry *entry  = completion->parent;
Packit Service 310c69
  Cursor       *cursor = entry->parent;
Packit Service 310c69
  Height        height = cursor->height;
Packit Service 310c69
  CursorLevel  *level  = &cursor->levels[height];
Packit Service 310c69
Packit Service 310c69
  TreePage     *treePage
Packit Service 310c69
    = &(cursor->tree->segments[0].levels[height][level->pageIndex]);
Packit Service 310c69
  BlockMapPage *page = (BlockMapPage *) treePage->pageBuffer;
Packit Service 310c69
  copyValidPage(entry->buffer, cursor->parent->map->nonce,
Packit Service 310c69
                entry->vio->physical, page);
Packit Service 310c69
  traverse(cursor);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Traverse a single block map tree. This is the recursive heart of the
Packit Service 310c69
 * traversal process.
Packit Service 310c69
 *
Packit Service 310c69
 * @param cursor  The cursor doing the traversal
Packit Service 310c69
 **/
Packit Service 310c69
static void traverse(Cursor *cursor)
Packit Service 310c69
{
Packit Service 310c69
  for (; cursor->height < BLOCK_MAP_TREE_HEIGHT; cursor->height++) {
Packit Service 310c69
    Height       height = cursor->height;
Packit Service 310c69
    CursorLevel *level  = &cursor->levels[height];
Packit Service 310c69
    TreePage *treePage
Packit Service 310c69
      = &(cursor->tree->segments[0].levels[height][level->pageIndex]);
Packit Service 310c69
    BlockMapPage *page = (BlockMapPage *) treePage->pageBuffer;
Packit Service 310c69
    if (!isBlockMapPageInitialized(page)) {
Packit Service 310c69
      continue;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    for (; level->slot < BLOCK_MAP_ENTRIES_PER_PAGE; level->slot++) {
Packit Service 310c69
      DataLocation location = unpackBlockMapEntry(&page->entries[level->slot]);
Packit Service 310c69
      if (!isValidLocation(&location)) {
Packit Service 310c69
        // This entry is invalid, so remove it from the page.
Packit Service 310c69
        page->entries[level->slot]
Packit Service 310c69
          = packPBN(ZERO_BLOCK, MAPPING_STATE_UNMAPPED);
Packit Service 310c69
        writeTreePage(treePage, cursor->parent->zone);
Packit Service 310c69
        continue;
Packit Service 310c69
      }
Packit Service 310c69
Packit Service 310c69
      if (!isMappedLocation(&location)) {
Packit Service 310c69
        continue;
Packit Service 310c69
      }
Packit Service 310c69
Packit Service 310c69
      PageNumber entryIndex
Packit Service 310c69
        = (BLOCK_MAP_ENTRIES_PER_PAGE * level->pageIndex) + level->slot;
Packit Service 310c69
Packit Service 310c69
      // Erase mapped entries past the end of the logical space.
Packit Service 310c69
      if (entryIndex >= cursor->boundary.levels[height]) {
Packit Service 310c69
        page->entries[level->slot]
Packit Service 310c69
          = packPBN(ZERO_BLOCK, MAPPING_STATE_UNMAPPED);
Packit Service 310c69
        writeTreePage(treePage, cursor->parent->zone);
Packit Service 310c69
        continue;
Packit Service 310c69
      }
Packit Service 310c69
Packit Service 310c69
      if (cursor->height < BLOCK_MAP_TREE_HEIGHT - 1) {
Packit Service 310c69
        int result = cursor->parent->entryCallback(location.pbn,
Packit Service 310c69
                                                   cursor->parent->parent);
Packit Service 310c69
        if (result != VDO_SUCCESS) {
Packit Service 310c69
          page->entries[level->slot]
Packit Service 310c69
            = packPBN(ZERO_BLOCK, MAPPING_STATE_UNMAPPED);
Packit Service 310c69
          writeTreePage(treePage, cursor->parent->zone);
Packit Service 310c69
          continue;
Packit Service 310c69
        }
Packit Service 310c69
      }
Packit Service 310c69
Packit Service 310c69
      if (cursor->height == 0) {
Packit Service 310c69
        continue;
Packit Service 310c69
      }
Packit Service 310c69
Packit Service 310c69
      cursor->height--;
Packit Service 310c69
      CursorLevel *nextLevel = &cursor->levels[cursor->height];
Packit Service 310c69
      nextLevel->pageIndex   = entryIndex;
Packit Service 310c69
      nextLevel->slot        = 0;
Packit Service 310c69
      level->slot++;
Packit Service 310c69
      launchReadMetadataVIO(cursor->vioPoolEntry->vio, location.pbn,
Packit Service 310c69
                            finishTraversalLoad, continueTraversal);
Packit Service 310c69
      return;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  finishCursor(cursor);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Start traversing a single block map tree now that the Cursor has a VIO with
Packit Service 310c69
 * which to load pages.
Packit Service 310c69
 *
Packit Service 310c69
 * 

Implements WaiterCallback.

Packit Service 310c69
 *
Packit Service 310c69
 * @param waiter   The Cursor
Packit Service 310c69
 * @param context  The VIOPoolEntry just acquired
Packit Service 310c69
 **/
Packit Service 310c69
static void launchCursor(Waiter *waiter, void *context)
Packit Service 310c69
{
Packit Service 310c69
  STATIC_ASSERT(offsetof(Cursor, waiter) == 0);
Packit Service 310c69
  Cursor *cursor               = (Cursor *) waiter;
Packit Service 310c69
  cursor->vioPoolEntry         = (VIOPoolEntry *) context;
Packit Service 310c69
  cursor->vioPoolEntry->parent = cursor;
Packit Service 310c69
  vioAsCompletion(cursor->vioPoolEntry->vio)->callbackThreadID
Packit Service 310c69
    = cursor->parent->zone->mapZone->threadID;
Packit Service 310c69
  traverse(cursor);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Compute the number of pages used at each level of the given root's tree.
Packit Service 310c69
 *
Packit Service 310c69
 * @param map        The block map
Packit Service 310c69
 * @param rootIndex  The index of the root to measure
Packit Service 310c69
 *
Packit Service 310c69
 * @return The list of page counts as a Boundary
Packit Service 310c69
 **/
Packit Service 310c69
static Boundary computeBoundary(BlockMap *map, RootCount rootIndex)
Packit Service 310c69
{
Packit Service 310c69
  PageCount leafPages     = computeBlockMapPageCount(map->entryCount);
Packit Service 310c69
  PageCount treeLeafPages = leafPages - map->flatPageCount;
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Compute the leaf pages for this root. If the number of leaf pages does
Packit Service 310c69
   * not distribute evenly, we must determine if this root gets an extra page.
Packit Service 310c69
   * Extra pages are assigned to roots starting at firstTreeRoot and going up.
Packit Service 310c69
   */
Packit Service 310c69
  PageCount firstTreeRoot = map->flatPageCount % map->rootCount;
Packit Service 310c69
  PageCount lastTreeRoot  = (leafPages - 1) % map->rootCount;
Packit Service 310c69
Packit Service 310c69
  PageCount levelPages = treeLeafPages / map->rootCount;
Packit Service 310c69
  if (inCyclicRange(firstTreeRoot, rootIndex, lastTreeRoot, map->rootCount)) {
Packit Service 310c69
    levelPages++;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Boundary boundary;
Packit Service 310c69
  for (Height height = 0; height < BLOCK_MAP_TREE_HEIGHT - 1; height++) {
Packit Service 310c69
    boundary.levels[height] = levelPages;
Packit Service 310c69
    levelPages = computeBucketCount(levelPages, BLOCK_MAP_ENTRIES_PER_PAGE);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // The root node always exists, even if the root is otherwise unused.
Packit Service 310c69
  boundary.levels[BLOCK_MAP_TREE_HEIGHT - 1] = 1;
Packit Service 310c69
Packit Service 310c69
  return boundary;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void traverseForest(BlockMap      *map,
Packit Service 310c69
                    EntryCallback *entryCallback,
Packit Service 310c69
                    VDOCompletion *parent)
Packit Service 310c69
{
Packit Service 310c69
  if (computeBlockMapPageCount(map->entryCount) <= map->flatPageCount) {
Packit Service 310c69
    // There are no tree pages, so there's nothing to do.
Packit Service 310c69
    finishCompletion(parent, VDO_SUCCESS);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  Cursors *cursors;
Packit Service 310c69
  int result = ALLOCATE_EXTENDED(Cursors, map->rootCount, Cursor, __func__,
Packit Service 310c69
                                 &cursors);
Packit Service 310c69
  if (result != VDO_SUCCESS) {
Packit Service 310c69
    finishCompletion(parent, result);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  cursors->map           = map;
Packit Service 310c69
  cursors->zone          = &(getBlockMapZone(map, 0)->treeZone);
Packit Service 310c69
  cursors->pool          = cursors->zone->vioPool;
Packit Service 310c69
  cursors->entryCallback = entryCallback;
Packit Service 310c69
  cursors->parent        = parent;
Packit Service 310c69
  cursors->activeRoots   = map->rootCount;
Packit Service 310c69
  for (RootCount root = 0; root < map->rootCount; root++) {
Packit Service 310c69
    Cursor *cursor = &cursors->cursors[root];
Packit Service 310c69
    *cursor = (Cursor) {
Packit Service 310c69
      .tree     = &map->forest->trees[root],
Packit Service 310c69
      .height   = BLOCK_MAP_TREE_HEIGHT - 1,
Packit Service 310c69
      .parent   = cursors,
Packit Service 310c69
      .boundary = computeBoundary(map, root),
Packit Service 310c69
    };
Packit Service 310c69
Packit Service 310c69
    cursor->waiter.callback = launchCursor;
Packit Service 310c69
    acquireVIOFromPool(cursors->pool, &cursor->waiter);
Packit Service 310c69
  };
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
BlockCount computeForestSize(BlockCount logicalBlocks, RootCount rootCount)
Packit Service 310c69
{
Packit Service 310c69
  Boundary newSizes;
Packit Service 310c69
  BlockCount approximateNonLeaves
Packit Service 310c69
    = computeNewPages(rootCount, 0, NULL, logicalBlocks, &newSizes);
Packit Service 310c69
Packit Service 310c69
  // Exclude the tree roots since those aren't allocated from slabs,
Packit Service 310c69
  // and also exclude the super-roots, which only exist in memory.
Packit Service 310c69
  approximateNonLeaves
Packit Service 310c69
    -= rootCount * (newSizes.levels[BLOCK_MAP_TREE_HEIGHT - 2]
Packit Service 310c69
                    + newSizes.levels[BLOCK_MAP_TREE_HEIGHT - 1]);
Packit Service 310c69
Packit Service 310c69
  BlockCount approximateLeaves
Packit Service 310c69
    = computeBlockMapPageCount(logicalBlocks - approximateNonLeaves);
Packit Service 310c69
Packit Service 310c69
  // This can be a slight over-estimate since the tree will never have to
Packit Service 310c69
  // address these blocks, so it might be a tiny bit smaller.
Packit Service 310c69
  return (approximateNonLeaves + approximateLeaves);
Packit Service 310c69
}