|
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/logicalZone.c#6 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "logicalZone.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "logger.h"
|
|
Packit Service |
310c69 |
#include "memoryAlloc.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "actionManager.h"
|
|
Packit Service |
310c69 |
#include "adminState.h"
|
|
Packit Service |
310c69 |
#include "allocationSelector.h"
|
|
Packit Service |
310c69 |
#include "atomic.h"
|
|
Packit Service |
310c69 |
#include "blockMap.h"
|
|
Packit Service |
310c69 |
#include "completion.h"
|
|
Packit Service |
310c69 |
#include "constants.h"
|
|
Packit Service |
310c69 |
#include "dataVIO.h"
|
|
Packit Service |
310c69 |
#include "flush.h"
|
|
Packit Service |
310c69 |
#include "intMap.h"
|
|
Packit Service |
310c69 |
#include "vdoInternal.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
struct logicalZone {
|
|
Packit Service |
310c69 |
/** The completion for flush notifications */
|
|
Packit Service |
310c69 |
VDOCompletion completion;
|
|
Packit Service |
310c69 |
/** The owner of this zone */
|
|
Packit Service |
310c69 |
LogicalZones *zones;
|
|
Packit Service |
310c69 |
/** Which logical zone this is */
|
|
Packit Service |
310c69 |
ZoneCount zoneNumber;
|
|
Packit Service |
310c69 |
/** The thread id for this zone */
|
|
Packit Service |
310c69 |
ThreadID threadID;
|
|
Packit Service |
310c69 |
/** In progress operations keyed by LBN */
|
|
Packit Service |
310c69 |
IntMap *lbnOperations;
|
|
Packit Service |
310c69 |
/** The logical to physical map */
|
|
Packit Service |
310c69 |
BlockMapZone *blockMapZone;
|
|
Packit Service |
310c69 |
/** The current flush generation */
|
|
Packit Service |
310c69 |
SequenceNumber flushGeneration;
|
|
Packit Service |
310c69 |
/** The oldest active generation in this zone */
|
|
Packit Service |
310c69 |
SequenceNumber oldestActiveGeneration;
|
|
Packit Service |
310c69 |
/** The number of IOs in the current flush generation */
|
|
Packit Service |
310c69 |
BlockCount iosInFlushGeneration;
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* The oldest locked generation in this zone (an atomic copy of
|
|
Packit Service |
310c69 |
* oldestActiveGeneration)
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
Atomic64 oldestLockedGeneration;
|
|
Packit Service |
310c69 |
/** The youngest generation of the current notification */
|
|
Packit Service |
310c69 |
SequenceNumber notificationGeneration;
|
|
Packit Service |
310c69 |
/** Whether a notification is in progress */
|
|
Packit Service |
310c69 |
bool notifying;
|
|
Packit Service |
310c69 |
/** The queue of active data write VIOs */
|
|
Packit Service |
310c69 |
RingNode writeVIOs;
|
|
Packit Service |
310c69 |
/** The administrative state of the zone */
|
|
Packit Service |
310c69 |
AdminState state;
|
|
Packit Service |
310c69 |
/** The selector for determining which physical zone to allocate from */
|
|
Packit Service |
310c69 |
AllocationSelector *selector;
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
struct logicalZones {
|
|
Packit Service |
310c69 |
/** The VDO whose zones these are */
|
|
Packit Service |
310c69 |
VDO *vdo;
|
|
Packit Service |
310c69 |
/** The manager for administrative actions */
|
|
Packit Service |
310c69 |
ActionManager *manager;
|
|
Packit Service |
310c69 |
/** The number of zones */
|
|
Packit Service |
310c69 |
ZoneCount zoneCount;
|
|
Packit Service |
310c69 |
/** The logical zones themselves */
|
|
Packit Service |
310c69 |
LogicalZone zones[];
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Convert a generic VDOCompletion to a LogicalZone.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The completion to convert
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return The completion as a LogicalZone
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static LogicalZone *asLogicalZone(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
STATIC_ASSERT(offsetof(LogicalZone, completion) == 0);
|
|
Packit Service |
310c69 |
assertCompletionType(completion->type, GENERATION_FLUSHED_COMPLETION);
|
|
Packit Service |
310c69 |
return (LogicalZone *) completion;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
LogicalZone *getLogicalZone(LogicalZones *zones, ZoneCount zoneNumber)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (zoneNumber < zones->zoneCount) ? &zones->zones[zoneNumber] : NULL;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Implements ZoneThreadGetter
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static ThreadID getThreadIDForZone(void *context, ZoneCount zoneNumber)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return getLogicalZoneThreadID(getLogicalZone(context, zoneNumber));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Initialize a logical zone.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param zones The LogicalZones to which this zone belongs
|
|
Packit Service |
310c69 |
* @param zoneNumber The LogicalZone's index
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static int initializeZone(LogicalZones *zones, ZoneCount zoneNumber)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
LogicalZone *zone = &zones->zones[zoneNumber];
|
|
Packit Service |
310c69 |
zone->zones = zones;
|
|
Packit Service |
310c69 |
int result = makeIntMap(LOCK_MAP_CAPACITY, 0, &zone->lbnOperations);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
VDO *vdo = zones->vdo;
|
|
Packit Service |
310c69 |
result = initializeEnqueueableCompletion(&zone->completion,
|
|
Packit Service |
310c69 |
GENERATION_FLUSHED_COMPLETION,
|
|
Packit Service |
310c69 |
vdo->layer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
zone->zoneNumber = zoneNumber;
|
|
Packit Service |
310c69 |
zone->threadID = getLogicalZoneThread(getThreadConfig(vdo),
|
|
Packit Service |
310c69 |
zoneNumber);
|
|
Packit Service |
310c69 |
zone->blockMapZone = getBlockMapZone(vdo->blockMap, zoneNumber);
|
|
Packit Service |
310c69 |
initializeRing(&zone->writeVIOs);
|
|
Packit Service |
310c69 |
atomicStore64(&zone->oldestLockedGeneration, 0);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return makeAllocationSelector(getThreadConfig(vdo)->physicalZoneCount,
|
|
Packit Service |
310c69 |
zone->threadID, &zone->selector);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int makeLogicalZones(VDO *vdo, LogicalZones **zonesPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
const ThreadConfig *threadConfig = getThreadConfig(vdo);
|
|
Packit Service |
310c69 |
if (threadConfig->logicalZoneCount == 0) {
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
LogicalZones *zones;
|
|
Packit Service |
310c69 |
int result = ALLOCATE_EXTENDED(LogicalZones, threadConfig->logicalZoneCount,
|
|
Packit Service |
310c69 |
LogicalZone, __func__, &zones);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
zones->vdo = vdo;
|
|
Packit Service |
310c69 |
zones->zoneCount = threadConfig->logicalZoneCount;
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < threadConfig->logicalZoneCount; zone++) {
|
|
Packit Service |
310c69 |
result = initializeZone(zones, zone);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
freeLogicalZones(&zones);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = makeActionManager(zones->zoneCount, getThreadIDForZone,
|
|
Packit Service |
310c69 |
getAdminThread(threadConfig), zones, NULL,
|
|
Packit Service |
310c69 |
vdo->layer, &zones->manager);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
freeLogicalZones(&zones);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*zonesPtr = zones;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void freeLogicalZones(LogicalZones **zonesPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
LogicalZones *zones = *zonesPtr;
|
|
Packit Service |
310c69 |
if (zones == NULL) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
freeActionManager(&zones->manager);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
for (ZoneCount index = 0; index < zones->zoneCount; index++) {
|
|
Packit Service |
310c69 |
LogicalZone *zone = &zones->zones[index];
|
|
Packit Service |
310c69 |
freeAllocationSelector(&zone->selector);
|
|
Packit Service |
310c69 |
destroyEnqueueable(&zone->completion);
|
|
Packit Service |
310c69 |
freeIntMap(&zone->lbnOperations);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
FREE(zones);
|
|
Packit Service |
310c69 |
*zonesPtr = NULL;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
static inline void assertOnZoneThread(LogicalZone *zone, const char *what)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((getCallbackThreadID() == zone->threadID),
|
|
Packit Service |
310c69 |
"%s() called on correct thread", what);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Check whether this zone has drained.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param zone The zone to check
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void checkForDrainComplete(LogicalZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (!isDraining(&zone->state) || zone->notifying
|
|
Packit Service |
310c69 |
|| !isRingEmpty(&zone->writeVIOs)) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
finishDraining(&zone->state);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Initiate a drain.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements AdminInitiator.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void initiateDrain(AdminState *state)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
checkForDrainComplete(container_of(state, LogicalZone, state));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Drain a logical zone.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ZoneAction.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void drainLogicalZone(void *context,
|
|
Packit Service |
310c69 |
ZoneCount zoneNumber,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
LogicalZone *zone = getLogicalZone(context, zoneNumber);
|
|
Packit Service |
310c69 |
startDraining(&zone->state, getCurrentManagerOperation(zone->zones->manager),
|
|
Packit Service |
310c69 |
parent, initiateDrain);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void drainLogicalZones(LogicalZones *zones,
|
|
Packit Service |
310c69 |
AdminStateCode operation,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
scheduleOperation(zones->manager, operation, NULL, drainLogicalZone, NULL,
|
|
Packit Service |
310c69 |
parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Resume a logical zone.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ZoneAction.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void resumeLogicalZone(void *context,
|
|
Packit Service |
310c69 |
ZoneCount zoneNumber,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
LogicalZone *zone = getLogicalZone(context, zoneNumber);
|
|
Packit Service |
310c69 |
finishCompletion(parent, resumeIfQuiescent(&zone->state));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void resumeLogicalZones(LogicalZones *zones, VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
scheduleOperation(zones->manager, ADMIN_STATE_RESUMING, NULL,
|
|
Packit Service |
310c69 |
resumeLogicalZone, NULL, parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
ThreadID getLogicalZoneThreadID(const LogicalZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return zone->threadID;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockMapZone *getBlockMapForZone(const LogicalZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return zone->blockMapZone;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
IntMap *getLBNLockMap(const LogicalZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return zone->lbnOperations;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
LogicalZone *getNextLogicalZone(const LogicalZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return getLogicalZone(zone->zones, zone->zoneNumber + 1);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Convert a RingNode to a DataVIO.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param ringNode The RingNode to convert
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return The DataVIO which owns the RingNode
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static inline DataVIO *dataVIOFromRingNode(RingNode *ringNode)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (DataVIO *) ((byte *) ringNode - offsetof(DataVIO, writeNode));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Update the oldest active generation. If it has changed, update the
|
|
Packit Service |
310c69 |
* atomic copy as well.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param zone The zone
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return true if the oldest active generation has changed
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static bool updateOldestActiveGeneration(LogicalZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
SequenceNumber currentOldest = zone->oldestActiveGeneration;
|
|
Packit Service |
310c69 |
if (isRingEmpty(&zone->writeVIOs)) {
|
|
Packit Service |
310c69 |
zone->oldestActiveGeneration = zone->flushGeneration;
|
|
Packit Service |
310c69 |
} else {
|
|
Packit Service |
310c69 |
zone->oldestActiveGeneration
|
|
Packit Service |
310c69 |
= dataVIOFromRingNode(zone->writeVIOs.next)->flushGeneration;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (zone->oldestActiveGeneration == currentOldest) {
|
|
Packit Service |
310c69 |
return false;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
atomicStore64(&zone->oldestLockedGeneration, zone->oldestActiveGeneration);
|
|
Packit Service |
310c69 |
return true;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void incrementFlushGeneration(LogicalZone *zone,
|
|
Packit Service |
310c69 |
SequenceNumber expectedGeneration)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
assertOnZoneThread(zone, __func__);
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((zone->flushGeneration == expectedGeneration),
|
|
Packit Service |
310c69 |
"logical zone %u flush generation %" PRIu64
|
|
Packit Service |
310c69 |
" should be %llu before increment",
|
|
Packit Service |
310c69 |
zone->zoneNumber, zone->flushGeneration,
|
|
Packit Service |
310c69 |
expectedGeneration);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
zone->flushGeneration++;
|
|
Packit Service |
310c69 |
zone->iosInFlushGeneration = 0;
|
|
Packit Service |
310c69 |
updateOldestActiveGeneration(zone);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
SequenceNumber getOldestLockedGeneration(const LogicalZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (SequenceNumber) atomicLoad64(&zone->oldestLockedGeneration);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int acquireFlushGenerationLock(DataVIO *dataVIO)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
LogicalZone *zone = dataVIO->logical.zone;
|
|
Packit Service |
310c69 |
assertOnZoneThread(zone, __func__);
|
|
Packit Service |
310c69 |
if (!isNormal(&zone->state)) {
|
|
Packit Service |
310c69 |
return VDO_INVALID_ADMIN_STATE;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
dataVIO->flushGeneration = zone->flushGeneration;
|
|
Packit Service |
310c69 |
pushRingNode(&zone->writeVIOs, &dataVIO->writeNode);
|
|
Packit Service |
310c69 |
dataVIO->hasFlushGenerationLock = true;
|
|
Packit Service |
310c69 |
zone->iosInFlushGeneration++;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
static void attemptGenerationCompleteNotification(VDOCompletion *completion);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Notify the flush that at least one generation no longer has active VIOs.
|
|
Packit Service |
310c69 |
* This callback is registered in attemptGenerationCompleteNotification().
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The zone completion
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void notifyFlusher(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
LogicalZone *zone = asLogicalZone(completion);
|
|
Packit Service |
310c69 |
completeFlushes(zone->zones->vdo->flusher);
|
|
Packit Service |
310c69 |
launchCallback(completion, attemptGenerationCompleteNotification,
|
|
Packit Service |
310c69 |
zone->threadID);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Notify the flusher if some generation no longer has active VIOs.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The zone completion
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void attemptGenerationCompleteNotification(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
LogicalZone *zone = asLogicalZone(completion);
|
|
Packit Service |
310c69 |
assertOnZoneThread(zone, __func__);
|
|
Packit Service |
310c69 |
if (zone->oldestActiveGeneration <= zone->notificationGeneration) {
|
|
Packit Service |
310c69 |
zone->notifying = false;
|
|
Packit Service |
310c69 |
checkForDrainComplete(zone);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
zone->notifying = true;
|
|
Packit Service |
310c69 |
zone->notificationGeneration = zone->oldestActiveGeneration;
|
|
Packit Service |
310c69 |
launchCallback(&zone->completion, notifyFlusher,
|
|
Packit Service |
310c69 |
getFlusherThreadID(zone->zones->vdo->flusher));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void releaseFlushGenerationLock(DataVIO *dataVIO)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
LogicalZone *zone = dataVIO->logical.zone;
|
|
Packit Service |
310c69 |
assertOnZoneThread(zone, __func__);
|
|
Packit Service |
310c69 |
if (isRingEmpty(&dataVIO->writeNode)) {
|
|
Packit Service |
310c69 |
// This VIO never got a lock, either because it is a read, or because
|
|
Packit Service |
310c69 |
// we are in read-only mode.
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(!dataVIO->hasFlushGenerationLock,
|
|
Packit Service |
310c69 |
"hasFlushGenerationLock false for VIO not on active list");
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
unspliceRingNode(&dataVIO->writeNode);
|
|
Packit Service |
310c69 |
dataVIO->hasFlushGenerationLock = false;
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(zone->oldestActiveGeneration <= dataVIO->flushGeneration,
|
|
Packit Service |
310c69 |
"DataVIO releasing lock on generation %" PRIu64
|
|
Packit Service |
310c69 |
" is not older than oldest active generation %llu",
|
|
Packit Service |
310c69 |
dataVIO->flushGeneration, zone->oldestActiveGeneration);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (!updateOldestActiveGeneration(zone) || zone->notifying) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
attemptGenerationCompleteNotification(&zone->completion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
AllocationSelector *getAllocationSelector(LogicalZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return zone->selector;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void dumpLogicalZone(const LogicalZone *zone)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
logInfo("LogicalZone %u", zone->zoneNumber);
|
|
Packit Service |
310c69 |
logInfo(" flushGeneration=%llu oldestActiveGeneration=%" PRIu64
|
|
Packit Service |
310c69 |
" oldestLockedGeneration=%llu notificationGeneration=%" PRIu64
|
|
Packit Service |
310c69 |
" notifying=%s iosInCurrentGeneration=%llu",
|
|
Packit Service |
310c69 |
zone->flushGeneration, zone->oldestActiveGeneration,
|
|
Packit Service |
310c69 |
relaxedLoad64(&zone->oldestLockedGeneration),
|
|
Packit Service |
310c69 |
zone->notificationGeneration, boolToString(zone->notifying),
|
|
Packit Service |
310c69 |
zone->iosInFlushGeneration);
|
|
Packit Service |
310c69 |
}
|