/* * 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/slab.h#8 $ */ #ifndef VDO_SLAB_H #define VDO_SLAB_H #include "permassert.h" #include "adminState.h" #include "fixedLayout.h" #include "journalPoint.h" #include "referenceOperation.h" #include "ringNode.h" #include "types.h" typedef uint32_t SlabBlockNumber; typedef enum { SLAB_REBUILT = 0, SLAB_REPLAYING, SLAB_REQUIRES_SCRUBBING, SLAB_REQUIRES_HIGH_PRIORITY_SCRUBBING, SLAB_REBUILDING, } SlabRebuildStatus; /** * This is the type declaration for the Slab type. (The struct tag is named * vdoSlab to avoid a conflict with the linux kernel type). A Slab currently * consists of a run of 2^23 data blocks, but that will soon change to * dedicate a small number of those blocks for metadata storage for the * reference counts and slab journal for the slab. **/ struct vdoSlab { /** A RingNode to queue this slab in a BlockAllocator ring */ RingNode ringNode; /** The BlockAllocator that owns this slab */ BlockAllocator *allocator; /** The reference counts for the data blocks in this slab */ RefCounts *referenceCounts; /** The journal for this slab */ SlabJournal *journal; /** The slab number of this slab */ SlabCount slabNumber; /** The offset in the allocator partition of the first block in this slab */ PhysicalBlockNumber start; /** The offset of the first block past the end of this slab */ PhysicalBlockNumber end; /** The starting translated PBN of the slab journal */ PhysicalBlockNumber journalOrigin; /** The starting translated PBN of the reference counts */ PhysicalBlockNumber refCountsOrigin; /** The administrative state of the slab */ AdminState state; /** The status of the slab */ SlabRebuildStatus status; /** Whether the slab was ever queued for scrubbing */ bool wasQueuedForScrubbing; /** The priority at which this slab has been queued for allocation */ uint8_t priority; }; /** * Measure and initialize the configuration to use for each slab. * * @param [in] slabSize The number of blocks per slab * @param [in] slabJournalBlocks The number of blocks for the slab journal * @param [out] slabConfig The slab configuration to initialize * * @return VDO_SUCCESS or an error code **/ int configureSlab(BlockCount slabSize, BlockCount slabJournalBlocks, SlabConfig *slabConfig) __attribute__((warn_unused_result)); /** * Convert a Slab's RingNode back to the Slab. * * @param ringNode The RingNode to convert * * @return The RingNode as a Slab **/ static inline Slab *slabFromRingNode(RingNode *ringNode) { STATIC_ASSERT(offsetof(Slab, ringNode) == 0); return (Slab *) ringNode; } /** * Get the physical block number of the start of the slab journal * relative to the start block allocator partition. * * @param slabConfig The slab configuration of the VDO * @param origin The first block of the slab **/ __attribute__((warn_unused_result)) PhysicalBlockNumber getSlabJournalStartBlock(const SlabConfig *slabConfig, PhysicalBlockNumber origin); /** * Construct a new, empty slab. * * @param [in] slabOrigin The physical block number within the block * allocator partition of the first block in the * slab * @param [in] allocator The block allocator to which the slab belongs * @param [in] translation The translation from the depot's partition to * the physical storage * @param [in] recoveryJournal The recovery journal of the VDO * @param [in] slabNumber The slab number of the slab * @param [in] isNew true if this slab is being * allocated as part of a resize * @param [out] slabPtr A pointer to receive the new slab * * @return VDO_SUCCESS or an error code **/ int makeSlab(PhysicalBlockNumber slabOrigin, BlockAllocator *allocator, PhysicalBlockNumber translation, RecoveryJournal *recoveryJournal, SlabCount slabNumber, bool isNew, Slab **slabPtr) __attribute__((warn_unused_result)); /** * Allocate the reference counts for a slab. * * @param slab The slab whose reference counts need allocation. * * @return VDO_SUCCESS or an error code **/ int allocateRefCountsForSlab(Slab *slab) __attribute__((warn_unused_result)); /** * Destroy a slab and null out the reference to it. * * @param slabPtr The reference to the slab to destroy **/ void freeSlab(Slab **slabPtr); /** * Get the physical zone number of a slab. * * @param slab The slab * * @return The number of the slab's physical zone **/ ZoneCount getSlabZoneNumber(Slab *slab) __attribute__((warn_unused_result)); /** * Check whether a slab is unrecovered. * * @param slab The slab to check * * @return true if the slab is unrecovered **/ static inline bool isUnrecoveredSlab(const Slab *slab) { return (slab->status != SLAB_REBUILT); } /** * Check whether a slab is being replayed into. * * @param slab The slab to check * * @return true if the slab is replaying **/ static inline bool isReplayingSlab(const Slab *slab) { return (slab->status == SLAB_REPLAYING); } /** * Check whether a slab is being rebuilt. * * @param slab The slab to check * * @return true if the slab is being rebuilt **/ static inline bool slabIsRebuilding(const Slab *slab) { return (slab->status == SLAB_REBUILDING); } /** * Mark a slab as replaying, during offline recovery. * * @param slab The slab to mark **/ void markSlabReplaying(Slab *slab); /** * Mark a slab as unrecovered, for online recovery. * * @param slab The slab to mark **/ void markSlabUnrecovered(Slab *slab); /** * Get the current number of free blocks in a slab. * * @param slab The slab to query * * @return the number of free blocks in the slab **/ BlockCount getSlabFreeBlockCount(const Slab *slab) __attribute__((warn_unused_result)); /** * Increment or decrement the reference count of a block in a slab. * * @param slab The slab containing the block (may be NULL when * referencing the zero block) * @param journalPoint The slab journal entry corresponding to this change * @param operation The operation to perform on the reference count * * @return VDO_SUCCESS or an error **/ int modifySlabReferenceCount(Slab *slab, const JournalPoint *journalPoint, ReferenceOperation operation) __attribute__((warn_unused_result)); /** * Acquire a provisional reference on behalf of a PBN lock if the block it * locks is unreferenced. * * @param slab The slab which contains the block * @param pbn The physical block to reference * @param lock The lock * * @return VDO_SUCCESS or an error **/ int acquireProvisionalReference(Slab *slab, PhysicalBlockNumber pbn, PBNLock *lock) __attribute__((warn_unused_result)); /** * Determine the index within the slab of a particular physical block number. * * @param [in] slab The slab * @param [in] physicalBlockNumber The physical block number * @param [out] slabBlockNumberPtr A pointer to the slab block number * * @return VDO_SUCCESS or an error code **/ int slabBlockNumberFromPBN(Slab *slab, PhysicalBlockNumber physicalBlockNumber, SlabBlockNumber *slabBlockNumberPtr) __attribute__((warn_unused_result)); /** * Check whether the reference counts for a given rebuilt slab should be saved. * Implements SlabStatusChecker. * * @param slab The slab to check * * @return true if the slab should be saved **/ bool shouldSaveFullyBuiltSlab(const Slab *slab) __attribute__((warn_unused_result)); /** * Start an administrative operation on a slab. * * @param slab The slab to load * @param operation The type of load to perform * @param parent The object to notify when the operation is complete **/ void startSlabAction(Slab *slab, AdminStateCode operation, VDOCompletion *parent); /** * Inform a slab that its journal has been loaded. * * @param slab The slab whose journal has been loaded * @param result The result of the load operation **/ void notifySlabJournalIsLoaded(Slab *slab, int result); /** * Check whether a slab is open, i.e. is neither quiescent nor quiescing. * * @param slab The slab to check * * @return true if the slab is open **/ bool isSlabOpen(Slab *slab) __attribute__((warn_unused_result)); /** * Check whether a slab is currently draining. * * @param slab The slab to check * * @return true if the slab is performing a drain operation **/ bool isSlabDraining(Slab *slab) __attribute__((warn_unused_result)); /** * Check whether a slab has drained, and if so, send a notification thereof. * * @param slab The slab to check **/ void checkIfSlabDrained(Slab *slab); /** * Inform a slab that its journal has finished draining. * * @param slab The slab whose journal has been drained * @param result The result of the drain operation **/ void notifySlabJournalIsDrained(Slab *slab, int result); /** * Inform a slab that its RefCounts have finished draining. * * @param slab The slab whose RefCounts has been drained * @param result The result of the drain operation **/ void notifyRefCountsAreDrained(Slab *slab, int result); /** * Check whether a slab is currently resuming. * * @param slab The slab to check * * @return true if the slab is performing a resume operation **/ bool isSlabResuming(Slab *slab) __attribute__((warn_unused_result)); /** * Finish scrubbing a slab now that it has been rebuilt by updating its status, * queueing it for allocation, and reopening its journal. * * @param slab The slab whose reference counts have been rebuilt from its * journal **/ void finishScrubbingSlab(Slab *slab); /** * Dump information about a slab to the log for debugging. * * @param slab The slab to dump **/ void dumpSlab(const Slab *slab); #endif // VDO_SLAB_H