/* * Copyright (c) 2020 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/blockMapPage.h#8 $ */ #ifndef BLOCK_MAP_PAGE_H #define BLOCK_MAP_PAGE_H #include "numeric.h" #include "blockMapEntry.h" #include "header.h" #include "types.h" /** * The packed, on-disk representation of a block map page header. **/ typedef union __attribute__((packed)) { struct __attribute__((packed)) { /** * The 64-bit nonce of the current VDO, in little-endian byte order. Used * to determine whether or not a page has been formatted. **/ byte nonce[8]; /** The 64-bit PBN of this page, in little-endian byte order */ byte pbn[8]; /** Formerly recoverySequenceNumber; may be non-zero on disk */ byte unusedLongWord[8]; /** Whether this page has been initialized on disk (i.e. written twice) */ bool initialized; /** Formerly entryOffset; now unused since it should always be zero */ byte unusedByte1; /** Formerly interiorTreePageWriting; may be non-zero on disk */ byte unusedByte2; /** Formerly generation (for dirty tree pages); may be non-zero on disk */ byte unusedByte3; } fields; // A raw view of the packed encoding. uint8_t raw[8 + 8 + 8 + 1 + 1 + 1 + 1]; #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ // This view is only valid on little-endian machines and is only present for // ease of directly examining packed entries in GDB. struct __attribute__((packed)) { uint64_t nonce; PhysicalBlockNumber pbn; uint64_t unusedLongWord; bool initialized; uint8_t unusedByte1; uint8_t unusedByte2; uint8_t unusedByte3; } littleEndian; #endif } PageHeader; /** * The format of a block map page. **/ typedef struct __attribute__((packed)) { PackedVersionNumber version; PageHeader header; BlockMapEntry entries[]; } BlockMapPage; typedef enum { // A block map page is correctly initialized BLOCK_MAP_PAGE_VALID, // A block map page is uninitialized BLOCK_MAP_PAGE_INVALID, // A block map page is intialized, but is the wrong page BLOCK_MAP_PAGE_BAD, } BlockMapPageValidity; /** * Check whether a block map page has been initialized. * * @param page The page to check * * @return true if the page has been initialized **/ __attribute__((warn_unused_result)) static inline bool isBlockMapPageInitialized(const BlockMapPage *page) { return page->header.fields.initialized; } /** * Mark whether a block map page has been initialized. * * @param page The page to mark * @param initialized The state to set * * @return true if the initialized flag was modified **/ static inline bool markBlockMapPageInitialized(BlockMapPage *page, bool initialized) { if (initialized == page->header.fields.initialized) { return false; } page->header.fields.initialized = initialized; return true; } /** * Get the physical block number where a block map page is stored. * * @param page The page to query * * @return the page's physical block number **/ __attribute__((warn_unused_result)) static inline PhysicalBlockNumber getBlockMapPagePBN(const BlockMapPage *page) { return getUInt64LE(page->header.fields.pbn); } /** * Check whether a block map page is of the current version. * * @param page The page to check * * @return true if the page has the current version **/ bool isCurrentBlockMapPage(const BlockMapPage *page) __attribute__((warn_unused_result)); /** * Format a block map page in memory. * * @param buffer The buffer which holds the page * @param nonce The VDO nonce * @param pbn The absolute PBN of the page * @param initialized Whether the page should be marked as initialized * * @return the buffer pointer, as a block map page (for convenience) **/ BlockMapPage *formatBlockMapPage(void *buffer, Nonce nonce, PhysicalBlockNumber pbn, bool initialized); /** * Check whether a newly read page is valid, upgrading its in-memory format if * possible and necessary. If the page is valid, clear fields which are not * meaningful on disk. * * @param page The page to validate * @param nonce The VDO nonce * @param pbn The expected absolute PBN of the page * * @return The validity of the page **/ BlockMapPageValidity validateBlockMapPage(BlockMapPage *page, Nonce nonce, PhysicalBlockNumber pbn) __attribute__((warn_unused_result)); /** * Update an entry on a block map page. * * @param [in] page The page to update * @param [in] dataVIO The DataVIO making the update * @param [in] pbn The new PBN for the entry * @param [in] mappingState The new mapping state for the entry * @param [in,out] recoveryLock A reference to the current recovery sequence * number lock held by the page. Will be updated * if the lock changes to protect the new entry **/ void updateBlockMapPage(BlockMapPage *page, DataVIO *dataVIO, PhysicalBlockNumber pbn, BlockMappingState mappingState, SequenceNumber *recoveryLock); #endif // BLOCK_MAP_PAGE_H