|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
75d76b |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
75d76b |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
75d76b |
* of the License, or (at your option) any later version.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
75d76b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
75d76b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
75d76b |
* GNU General Public License for more details.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
75d76b |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
75d76b |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
75d76b |
* 02110-1301, USA.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/slab.c#9 $
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "slab.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "logger.h"
|
|
Packit Service |
75d76b |
#include "memoryAlloc.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
#include "adminState.h"
|
|
Packit Service |
75d76b |
#include "blockAllocatorInternals.h"
|
|
Packit Service |
75d76b |
#include "completion.h"
|
|
Packit Service |
75d76b |
#include "constants.h"
|
|
Packit Service |
75d76b |
#include "numUtils.h"
|
|
Packit Service |
75d76b |
#include "pbnLock.h"
|
|
Packit Service |
75d76b |
#include "recoveryJournal.h"
|
|
Packit Service |
75d76b |
#include "refCounts.h"
|
|
Packit Service |
75d76b |
#include "slabDepot.h"
|
|
Packit Service |
75d76b |
#include "slabJournal.h"
|
|
Packit Service |
75d76b |
#include "slabJournalInternals.h"
|
|
Packit Service |
75d76b |
#include "slabSummary.h"
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int configureSlab(BlockCount slabSize,
|
|
Packit Service |
75d76b |
BlockCount slabJournalBlocks,
|
|
Packit Service |
75d76b |
SlabConfig *slabConfig)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (slabJournalBlocks >= slabSize) {
|
|
Packit Service |
75d76b |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* This calculation should technically be a recurrence, but the total number
|
|
Packit Service |
75d76b |
* of metadata blocks is currently less than a single block of refCounts, so
|
|
Packit Service |
75d76b |
* we'd gain at most one data block in each slab with more iteration.
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
BlockCount refBlocks
|
|
Packit Service |
75d76b |
= getSavedReferenceCountSize(slabSize - slabJournalBlocks);
|
|
Packit Service |
75d76b |
BlockCount metaBlocks = (refBlocks + slabJournalBlocks);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
// Make sure test code hasn't configured slabs to be too small.
|
|
Packit Service |
75d76b |
if (metaBlocks >= slabSize) {
|
|
Packit Service |
75d76b |
return VDO_BAD_CONFIGURATION;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* If the slab size is very small, assume this must be a unit test and
|
|
Packit Service |
75d76b |
* override the number of data blocks to be a power of two (wasting blocks
|
|
Packit Service |
75d76b |
* in the slab). Many tests need their dataBlocks fields to be the exact
|
|
Packit Service |
75d76b |
* capacity of the configured volume, and that used to fall out since they
|
|
Packit Service |
75d76b |
* use a power of two for the number of data blocks, the slab size was a
|
|
Packit Service |
75d76b |
* power of two, and every block in a slab was a data block.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* XXX Try to figure out some way of structuring testParameters and unit
|
|
Packit Service |
75d76b |
* tests so this hack isn't needed without having to edit several unit tests
|
|
Packit Service |
75d76b |
* every time the metadata size changes by one block.
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
BlockCount dataBlocks = slabSize - metaBlocks;
|
|
Packit Service |
75d76b |
if ((slabSize < 1024) && !isPowerOfTwo(dataBlocks)) {
|
|
Packit Service |
75d76b |
dataBlocks = ((BlockCount) 1 << logBaseTwo(dataBlocks));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* Configure the slab journal thresholds. The flush threshold is 168 of 224
|
|
Packit Service |
75d76b |
* blocks in production, or 3/4ths, so we use this ratio for all sizes.
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
BlockCount flushingThreshold = ((slabJournalBlocks * 3) + 3) / 4;
|
|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* The blocking threshold should be far enough from the the flushing
|
|
Packit Service |
75d76b |
* threshold to not produce delays, but far enough from the end of the
|
|
Packit Service |
75d76b |
* journal to allow multiple successive recovery failures.
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
BlockCount remaining = slabJournalBlocks - flushingThreshold;
|
|
Packit Service |
75d76b |
BlockCount blockingThreshold = flushingThreshold + ((remaining * 5) / 7);
|
|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* The scrubbing threshold should be at least 2048 entries before the end of
|
|
Packit Service |
75d76b |
* the journal.
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
BlockCount minimalExtraSpace
|
|
Packit Service |
75d76b |
= 1 + (MAXIMUM_USER_VIOS / SLAB_JOURNAL_FULL_ENTRIES_PER_BLOCK);
|
|
Packit Service |
75d76b |
BlockCount scrubbingThreshold = blockingThreshold;
|
|
Packit Service |
75d76b |
if (slabJournalBlocks > minimalExtraSpace) {
|
|
Packit Service |
75d76b |
scrubbingThreshold = slabJournalBlocks - minimalExtraSpace;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
if (blockingThreshold > scrubbingThreshold) {
|
|
Packit Service |
75d76b |
blockingThreshold = scrubbingThreshold;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*slabConfig = (SlabConfig) {
|
|
Packit Service |
75d76b |
.slabBlocks = slabSize,
|
|
Packit Service |
75d76b |
.dataBlocks = dataBlocks,
|
|
Packit Service |
75d76b |
.referenceCountBlocks = refBlocks,
|
|
Packit Service |
75d76b |
.slabJournalBlocks = slabJournalBlocks,
|
|
Packit Service |
75d76b |
.slabJournalFlushingThreshold = flushingThreshold,
|
|
Packit Service |
75d76b |
.slabJournalBlockingThreshold = blockingThreshold,
|
|
Packit Service |
75d76b |
.slabJournalScrubbingThreshold = scrubbingThreshold
|
|
Packit Service |
75d76b |
};
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
PhysicalBlockNumber getSlabJournalStartBlock(const SlabConfig *slabConfig,
|
|
Packit Service |
75d76b |
PhysicalBlockNumber origin)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return origin + slabConfig->dataBlocks + slabConfig->referenceCountBlocks;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int makeSlab(PhysicalBlockNumber slabOrigin,
|
|
Packit Service |
75d76b |
BlockAllocator *allocator,
|
|
Packit Service |
75d76b |
PhysicalBlockNumber translation,
|
|
Packit Service |
75d76b |
RecoveryJournal *recoveryJournal,
|
|
Packit Service |
75d76b |
SlabCount slabNumber,
|
|
Packit Service |
75d76b |
bool isNew,
|
|
Packit Service |
75d76b |
Slab **slabPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
Slab *slab;
|
|
Packit Service |
75d76b |
int result = ALLOCATE(1, Slab, __func__, &slab;;
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
const SlabConfig *slabConfig = getSlabConfig(allocator->depot);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
slab->allocator = allocator;
|
|
Packit Service |
75d76b |
slab->start = slabOrigin;
|
|
Packit Service |
75d76b |
slab->end = slab->start + slabConfig->slabBlocks;
|
|
Packit Service |
75d76b |
slab->slabNumber = slabNumber;
|
|
Packit Service |
75d76b |
initializeRing(&slab->ringNode);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
slab->refCountsOrigin = slabOrigin + slabConfig->dataBlocks + translation;
|
|
Packit Service |
75d76b |
slab->journalOrigin = (getSlabJournalStartBlock(slabConfig, slabOrigin)
|
|
Packit Service |
75d76b |
+ translation);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
result = makeSlabJournal(allocator, slab, recoveryJournal, &slab->journal);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeSlab(&slab;;
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (isNew) {
|
|
Packit Service |
75d76b |
slab->state.state = ADMIN_STATE_NEW;
|
|
Packit Service |
75d76b |
result = allocateRefCountsForSlab(slab);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
freeSlab(&slab;;
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*slabPtr = slab;
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int allocateRefCountsForSlab(Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
BlockAllocator *allocator = slab->allocator;
|
|
Packit Service |
75d76b |
const SlabConfig *slabConfig = getSlabConfig(allocator->depot);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
int result = ASSERT(slab->referenceCounts == NULL,
|
|
Packit Service |
75d76b |
"Slab %u doesn't allocate refcounts twice",
|
|
Packit Service |
75d76b |
slab->slabNumber);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return makeRefCounts(slabConfig->dataBlocks, slab, slab->refCountsOrigin,
|
|
Packit Service |
75d76b |
allocator->readOnlyNotifier, &slab->referenceCounts);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void freeSlab(Slab **slabPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
Slab *slab = *slabPtr;
|
|
Packit Service |
75d76b |
if (slab == NULL) {
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
unspliceRingNode(&slab->ringNode);
|
|
Packit Service |
75d76b |
freeSlabJournal(&slab->journal);
|
|
Packit Service |
75d76b |
freeRefCounts(&slab->referenceCounts);
|
|
Packit Service |
75d76b |
FREE(slab);
|
|
Packit Service |
75d76b |
*slabPtr = NULL;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
ZoneCount getSlabZoneNumber(Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return slab->allocator->zoneNumber;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void markSlabReplaying(Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (slab->status == SLAB_REBUILT) {
|
|
Packit Service |
75d76b |
slab->status = SLAB_REPLAYING;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void markSlabUnrecovered(Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
slab->status = SLAB_REQUIRES_SCRUBBING;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
BlockCount getSlabFreeBlockCount(const Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return getUnreferencedBlockCount(slab->referenceCounts);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int modifySlabReferenceCount(Slab *slab,
|
|
Packit Service |
75d76b |
const JournalPoint *journalPoint,
|
|
Packit Service |
75d76b |
ReferenceOperation operation)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (slab == NULL) {
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/*
|
|
Packit Service |
75d76b |
* If the slab is unrecovered, preserve the refCount state and let scrubbing
|
|
Packit Service |
75d76b |
* correct the refCount. Note that the slab journal has already captured all
|
|
Packit Service |
75d76b |
* refCount updates.
|
|
Packit Service |
75d76b |
*/
|
|
Packit Service |
75d76b |
if (isUnrecoveredSlab(slab)) {
|
|
Packit Service |
75d76b |
SequenceNumber entryLock = journalPoint->sequenceNumber;
|
|
Packit Service |
75d76b |
adjustSlabJournalBlockReference(slab->journal, entryLock, -1);
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
bool freeStatusChanged;
|
|
Packit Service |
75d76b |
int result = adjustReferenceCount(slab->referenceCounts, operation,
|
|
Packit Service |
75d76b |
journalPoint, &freeStatusChanged);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (freeStatusChanged) {
|
|
Packit Service |
75d76b |
adjustFreeBlockCount(slab, !isIncrementOperation(operation.type));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int acquireProvisionalReference(Slab *slab,
|
|
Packit Service |
75d76b |
PhysicalBlockNumber pbn,
|
|
Packit Service |
75d76b |
PBNLock *lock)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (hasProvisionalReference(lock)) {
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
int result = provisionallyReferenceBlock(slab->referenceCounts, pbn, lock);
|
|
Packit Service |
75d76b |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
75d76b |
return result;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (hasProvisionalReference(lock)) {
|
|
Packit Service |
75d76b |
adjustFreeBlockCount(slab, false);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
int slabBlockNumberFromPBN(Slab *slab,
|
|
Packit Service |
75d76b |
PhysicalBlockNumber physicalBlockNumber,
|
|
Packit Service |
75d76b |
SlabBlockNumber *slabBlockNumberPtr)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (physicalBlockNumber < slab->start) {
|
|
Packit Service |
75d76b |
return VDO_OUT_OF_RANGE;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
uint64_t slabBlockNumber = physicalBlockNumber - slab->start;
|
|
Packit Service |
75d76b |
if (slabBlockNumber >= getSlabConfig(slab->allocator->depot)->dataBlocks) {
|
|
Packit Service |
75d76b |
return VDO_OUT_OF_RANGE;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
*slabBlockNumberPtr = slabBlockNumber;
|
|
Packit Service |
75d76b |
return VDO_SUCCESS;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
bool shouldSaveFullyBuiltSlab(const Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
// Write out the refCounts if the slab has written them before, or it has
|
|
Packit Service |
75d76b |
// any non-zero reference counts, or there are any slab journal blocks.
|
|
Packit Service |
75d76b |
BlockCount dataBlocks = getSlabConfig(slab->allocator->depot)->dataBlocks;
|
|
Packit Service |
75d76b |
return (mustLoadRefCounts(slab->allocator->summary, slab->slabNumber)
|
|
Packit Service |
75d76b |
|| (getSlabFreeBlockCount(slab) != dataBlocks)
|
|
Packit Service |
75d76b |
|| !isSlabJournalBlank(slab->journal));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**
|
|
Packit Service |
75d76b |
* Initiate a slab action.
|
|
Packit Service |
75d76b |
*
|
|
Packit Service |
75d76b |
* Implements AdminInitiator.
|
|
Packit Service |
75d76b |
**/
|
|
Packit Service |
75d76b |
static void initiateSlabAction(AdminState *state)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
Slab *slab = container_of(state, Slab, state);
|
|
Packit Service |
75d76b |
if (isDraining(state)) {
|
|
Packit Service |
75d76b |
if (state->state == ADMIN_STATE_SCRUBBING) {
|
|
Packit Service |
75d76b |
slab->status = SLAB_REBUILDING;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
drainSlabJournal(slab->journal);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (slab->referenceCounts != NULL) {
|
|
Packit Service |
75d76b |
drainRefCounts(slab->referenceCounts);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
checkIfSlabDrained(slab);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (isLoading(state)) {
|
|
Packit Service |
75d76b |
decodeSlabJournal(slab->journal);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (isResuming(state)) {
|
|
Packit Service |
75d76b |
queueSlab(slab);
|
|
Packit Service |
75d76b |
finishResuming(state);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
finishOperationWithResult(state, VDO_INVALID_ADMIN_STATE);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void startSlabAction(Slab *slab,
|
|
Packit Service |
75d76b |
AdminStateCode operation,
|
|
Packit Service |
75d76b |
VDOCompletion *parent)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
startOperationWithWaiter(&slab->state, operation, parent,
|
|
Packit Service |
75d76b |
initiateSlabAction);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void notifySlabJournalIsLoaded(Slab *slab, int result)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if ((result == VDO_SUCCESS) && isCleanLoad(&slab->state)) {
|
|
Packit Service |
75d76b |
// Since this is a normal or new load, we don't need the memory to read and
|
|
Packit Service |
75d76b |
// process the recovery journal, so we can allocate reference counts now.
|
|
Packit Service |
75d76b |
result = allocateRefCountsForSlab(slab);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
finishLoadingWithResult(&slab->state, result);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
bool isSlabOpen(Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return (!isQuiescing(&slab->state) && !isQuiescent(&slab->state));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
bool isSlabDraining(Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return isDraining(&slab->state);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void checkIfSlabDrained(Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (isDraining(&slab->state)
|
|
Packit Service |
75d76b |
&& !isSlabJournalActive(slab->journal)
|
|
Packit Service |
75d76b |
&& ((slab->referenceCounts == NULL)
|
|
Packit Service |
75d76b |
|| !areRefCountsActive(slab->referenceCounts))) {
|
|
Packit Service |
75d76b |
finishDrainingWithResult(&slab->state,
|
|
Packit Service |
75d76b |
(isReadOnly(slab->allocator->readOnlyNotifier)
|
|
Packit Service |
75d76b |
? VDO_READ_ONLY : VDO_SUCCESS));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void notifySlabJournalIsDrained(Slab *slab, int result)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (slab->referenceCounts == NULL) {
|
|
Packit Service |
75d76b |
// This can happen when shutting down a VDO that was in read-only mode when
|
|
Packit Service |
75d76b |
// loaded.
|
|
Packit Service |
75d76b |
notifyRefCountsAreDrained(slab, result);
|
|
Packit Service |
75d76b |
return;
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
setOperationResult(&slab->state, result);
|
|
Packit Service |
75d76b |
drainRefCounts(slab->referenceCounts);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void notifyRefCountsAreDrained(Slab *slab, int result)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
finishDrainingWithResult(&slab->state, result);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
bool isSlabResuming(Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
return isResuming(&slab->state);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void finishScrubbingSlab(Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
slab->status = SLAB_REBUILT;
|
|
Packit Service |
75d76b |
queueSlab(slab);
|
|
Packit Service |
75d76b |
reopenSlabJournal(slab->journal);
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
static const char *statusToString(SlabRebuildStatus status)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
switch (status) {
|
|
Packit Service |
75d76b |
case SLAB_REBUILT:
|
|
Packit Service |
75d76b |
return "REBUILT";
|
|
Packit Service |
75d76b |
case SLAB_REQUIRES_SCRUBBING:
|
|
Packit Service |
75d76b |
return "SCRUBBING";
|
|
Packit Service |
75d76b |
case SLAB_REQUIRES_HIGH_PRIORITY_SCRUBBING:
|
|
Packit Service |
75d76b |
return "PRIORITY_SCRUBBING";
|
|
Packit Service |
75d76b |
case SLAB_REBUILDING:
|
|
Packit Service |
75d76b |
return "REBUILDING";
|
|
Packit Service |
75d76b |
case SLAB_REPLAYING:
|
|
Packit Service |
75d76b |
return "REPLAYING";
|
|
Packit Service |
75d76b |
default:
|
|
Packit Service |
75d76b |
return "UNKNOWN";
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
/**********************************************************************/
|
|
Packit Service |
75d76b |
void dumpSlab(const Slab *slab)
|
|
Packit Service |
75d76b |
{
|
|
Packit Service |
75d76b |
if (slab->referenceCounts != NULL) {
|
|
Packit Service |
75d76b |
// Terse because there are a lot of slabs to dump and syslog is lossy.
|
|
Packit Service |
75d76b |
logInfo("slab %u: P%u, %llu free",
|
|
Packit Service |
75d76b |
slab->slabNumber, slab->priority, getSlabFreeBlockCount(slab));
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
logInfo("slab %u: status %s", slab->slabNumber,
|
|
Packit Service |
75d76b |
statusToString(slab->status));
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
dumpSlabJournal(slab->journal);
|
|
Packit Service |
75d76b |
|
|
Packit Service |
75d76b |
if (slab->referenceCounts != NULL) {
|
|
Packit Service |
75d76b |
dumpRefCounts(slab->referenceCounts);
|
|
Packit Service |
75d76b |
} else {
|
|
Packit Service |
75d76b |
logInfo("refCounts is null");
|
|
Packit Service |
75d76b |
}
|
|
Packit Service |
75d76b |
}
|