/* * 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/refCountsInternals.h#4 $ */ #ifndef REF_COUNTS_INTERNALS_H #define REF_COUNTS_INTERNALS_H #include "refCounts.h" #include "journalPoint.h" #include "referenceBlock.h" #include "slab.h" #include "blockAllocatorInternals.h" #include "waitQueue.h" /** * Represents the possible status of a block. **/ typedef enum referenceStatus { RS_FREE, // this block is free RS_SINGLE, // this block is singly-referenced RS_SHARED, // this block is shared RS_PROVISIONAL // this block is provisionally allocated } ReferenceStatus; /** * The SearchCursor represents the saved position of a free block search. **/ typedef struct searchCursor { /** The reference block containing the current search index */ ReferenceBlock *block; /** The position at which to start searching for the next free counter */ SlabBlockNumber index; /** The position just past the last valid counter in the current block */ SlabBlockNumber endIndex; /** A pointer to the first reference block in the slab */ ReferenceBlock *firstBlock; /** A pointer to the last reference block in the slab */ ReferenceBlock *lastBlock; } SearchCursor; /* * RefCounts structure * * A reference count is maintained for each PhysicalBlockNumber. The vast * majority of blocks have a very small reference count (usually 0 or 1). * For references less than or equal to MAXIMUM_REFS (254) the reference count * is stored in counters[pbn]. * */ struct refCounts { /** The slab of this reference block */ Slab *slab; /** The size of the counters array */ uint32_t blockCount; /** The number of free blocks */ uint32_t freeBlocks; /** The array of reference counts */ ReferenceCount *counters; // use ALLOCATE to align data ptr /** The saved block pointer and array indexes for the free block search */ SearchCursor searchCursor; /** A list of the dirty blocks waiting to be written out */ WaitQueue dirtyBlocks; /** The number of blocks which are currently writing */ size_t activeCount; /** A waiter object for updating the slab summary */ Waiter slabSummaryWaiter; /** Whether slab summary update is in progress */ bool updatingSlabSummary; /** The notifier for read-only mode */ ReadOnlyNotifier *readOnlyNotifier; /** The refcount statistics, shared by all refcounts in our physical zone */ AtomicRefCountStatistics *statistics; /** The layer PBN for the first ReferenceBlock */ PhysicalBlockNumber origin; /** The latest slab journal entry this RefCounts has been updated with */ JournalPoint slabJournalPoint; /** The number of reference count blocks */ uint32_t referenceBlockCount; /** reference count block array */ ReferenceBlock blocks[]; }; /** * Convert a reference count to a reference status. * * @param count The count to convert * * @return The appropriate reference status **/ __attribute__((warn_unused_result)) ReferenceStatus referenceCountToStatus(ReferenceCount count); /** * Convert a generic VDOCompletion to a RefCounts. * * @param completion The completion to convert * * @return The completion as a RefCounts **/ RefCounts *asRefCounts(VDOCompletion *completion) __attribute__((warn_unused_result)); /** * Get the reference block that covers the given block index (exposed for * testing). * * @param refCounts The refcounts object * @param index The block index **/ ReferenceBlock *getReferenceBlock(RefCounts *refCounts, SlabBlockNumber index) __attribute__((warn_unused_result)); /** * Find the reference counters for a given block (exposed for testing). * * @param block The ReferenceBlock in question * * @return A pointer to the reference counters for this block **/ ReferenceCount *getReferenceCountersForBlock(ReferenceBlock *block) __attribute__((warn_unused_result)); /** * Copy data from a reference block to a buffer ready to be written out * (exposed for testing). * * @param block The block to copy * @param buffer The char buffer to fill with the packed block **/ void packReferenceBlock(ReferenceBlock *block, void *buffer); /** * Get the reference status of a block. Exposed only for unit testing. * * @param [in] refCounts The refcounts object * @param [in] pbn The physical block number * @param [out] statusPtr Where to put the status of the block * * @return A success or error code, specifically: * VDO_OUT_OF_RANGE if the pbn is out of range. **/ int getReferenceStatus(RefCounts *refCounts, PhysicalBlockNumber pbn, ReferenceStatus *statusPtr) __attribute__((warn_unused_result)); /** * Find the first block with a reference count of zero in the specified range * of reference counter indexes. Exposed for unit testing. * * @param [in] refCounts The reference counters to scan * @param [in] startIndex The array index at which to start scanning * (included in the scan) * @param [in] endIndex The array index at which to stop scanning * (excluded from the scan) * @param [out] indexPtr A pointer to hold the array index of the free block * * @return true if a free block was found in the specified range **/ bool findFreeBlock(const RefCounts *refCounts, SlabBlockNumber startIndex, SlabBlockNumber endIndex, SlabBlockNumber *indexPtr) __attribute__((warn_unused_result)); /** * Request a RefCounts save its oldest dirty block asynchronously. * * @param refCounts The RefCounts object to notify **/ void saveOldestReferenceBlock(RefCounts *refCounts); /** * Reset all reference counts back to RS_FREE. * * @param refCounts The reference counters to reset **/ void resetReferenceCounts(RefCounts *refCounts); #endif // REF_COUNTS_INTERNALS_H