Blame source/vdo/base/blockMapPage.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/blockMapPage.c#8 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "blockMapPage.h"
Packit Service 310c69
Packit Service 310c69
#include "permassert.h"
Packit Service 310c69
Packit Service 310c69
#include "blockMap.h"
Packit Service 310c69
#include "blockMapInternals.h"
Packit Service 310c69
#include "blockMapTree.h"
Packit Service 310c69
#include "constants.h"
Packit Service 310c69
#include "dataVIO.h"
Packit Service 310c69
#include "recoveryJournal.h"
Packit Service 310c69
#include "statusCodes.h"
Packit Service 310c69
#include "types.h"
Packit Service 310c69
Packit Service 310c69
enum {
Packit Service 310c69
  PAGE_HEADER_4_1_SIZE = 8 + 8 + 8 + 1 + 1 + 1 + 1,
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
static const VersionNumber BLOCK_MAP_4_1 = {
Packit Service 310c69
  .majorVersion = 4,
Packit Service 310c69
  .minorVersion = 1,
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool isCurrentBlockMapPage(const BlockMapPage *page)
Packit Service 310c69
{
Packit Service 310c69
  return areSameVersion(BLOCK_MAP_4_1, unpackVersionNumber(page->version));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
BlockMapPage *formatBlockMapPage(void                *buffer,
Packit Service 310c69
                                 Nonce                nonce,
Packit Service 310c69
                                 PhysicalBlockNumber  pbn,
Packit Service 310c69
                                 bool                 initialized)
Packit Service 310c69
{
Packit Service 310c69
  memset(buffer, 0, VDO_BLOCK_SIZE);
Packit Service 310c69
  BlockMapPage *page = (BlockMapPage *) buffer;
Packit Service 310c69
  page->version = packVersionNumber(BLOCK_MAP_4_1);
Packit Service 310c69
  storeUInt64LE(page->header.fields.nonce, nonce);
Packit Service 310c69
  storeUInt64LE(page->header.fields.pbn, pbn);
Packit Service 310c69
  page->header.fields.initialized = initialized;
Packit Service 310c69
  return page;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
BlockMapPageValidity validateBlockMapPage(BlockMapPage        *page,
Packit Service 310c69
                                          Nonce                nonce,
Packit Service 310c69
                                          PhysicalBlockNumber  pbn)
Packit Service 310c69
{
Packit Service 310c69
  // Make sure the page layout isn't accidentally changed by changing the
Packit Service 310c69
  // length of the page header.
Packit Service 310c69
  STATIC_ASSERT_SIZEOF(PageHeader, PAGE_HEADER_4_1_SIZE);
Packit Service 310c69
Packit Service 310c69
  if (!areSameVersion(BLOCK_MAP_4_1, unpackVersionNumber(page->version))
Packit Service 310c69
      || !isBlockMapPageInitialized(page)
Packit Service 310c69
      || (nonce != getUInt64LE(page->header.fields.nonce))) {
Packit Service 310c69
    return BLOCK_MAP_PAGE_INVALID;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (pbn != getBlockMapPagePBN(page)) {
Packit Service 310c69
    return BLOCK_MAP_PAGE_BAD;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return BLOCK_MAP_PAGE_VALID;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void updateBlockMapPage(BlockMapPage        *page,
Packit Service 310c69
                        DataVIO             *dataVIO,
Packit Service 310c69
                        PhysicalBlockNumber  pbn,
Packit Service 310c69
                        BlockMappingState    mappingState,
Packit Service 310c69
                        SequenceNumber      *recoveryLock)
Packit Service 310c69
{
Packit Service 310c69
  // Encode the new mapping.
Packit Service 310c69
  TreeLock *treeLock = &dataVIO->treeLock;
Packit Service 310c69
  SlotNumber slot = treeLock->treeSlots[treeLock->height].blockMapSlot.slot;
Packit Service 310c69
  page->entries[slot] = packPBN(pbn, mappingState);
Packit Service 310c69
Packit Service 310c69
  // Adjust references (locks) on the recovery journal blocks.
Packit Service 310c69
  BlockMapZone    *zone      = getBlockMapForZone(dataVIO->logical.zone);
Packit Service 310c69
  BlockMap        *blockMap  = zone->blockMap;
Packit Service 310c69
  RecoveryJournal *journal   = blockMap->journal;
Packit Service 310c69
  SequenceNumber   oldLocked = *recoveryLock;
Packit Service 310c69
  SequenceNumber   newLocked = dataVIO->recoverySequenceNumber;
Packit Service 310c69
Packit Service 310c69
  if ((oldLocked == 0) || (oldLocked > newLocked)) {
Packit Service 310c69
    // Acquire a lock on the newly referenced journal block.
Packit Service 310c69
    acquireRecoveryJournalBlockReference(journal, newLocked, ZONE_TYPE_LOGICAL,
Packit Service 310c69
                                         zone->zoneNumber);
Packit Service 310c69
Packit Service 310c69
    // If the block originally held a newer lock, release it.
Packit Service 310c69
    if (oldLocked > 0) {
Packit Service 310c69
      releaseRecoveryJournalBlockReference(journal, oldLocked,
Packit Service 310c69
                                           ZONE_TYPE_LOGICAL,
Packit Service 310c69
                                           zone->zoneNumber);
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    *recoveryLock = newLocked;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Release the transferred lock from the DataVIO.
Packit Service 310c69
  releasePerEntryLockFromOtherZone(journal, newLocked);
Packit Service 310c69
  dataVIO->recoverySequenceNumber = 0;
Packit Service 310c69
}