|
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/vdo.c#21 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* This file contains the main entry points for normal operations on a VDO as
|
|
Packit Service |
310c69 |
* well as functions for constructing and destroying VDO instances (in memory).
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "vdoInternal.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "buffer.h"
|
|
Packit Service |
310c69 |
#include "logger.h"
|
|
Packit Service |
310c69 |
#include "memoryAlloc.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "adminCompletion.h"
|
|
Packit Service |
310c69 |
#include "blockMap.h"
|
|
Packit Service |
310c69 |
#include "extent.h"
|
|
Packit Service |
310c69 |
#include "hashZone.h"
|
|
Packit Service |
310c69 |
#include "header.h"
|
|
Packit Service |
310c69 |
#include "logicalZone.h"
|
|
Packit Service |
310c69 |
#include "numUtils.h"
|
|
Packit Service |
310c69 |
#include "packer.h"
|
|
Packit Service |
310c69 |
#include "physicalZone.h"
|
|
Packit Service |
310c69 |
#include "readOnlyNotifier.h"
|
|
Packit Service |
310c69 |
#include "recoveryJournal.h"
|
|
Packit Service |
310c69 |
#include "releaseVersions.h"
|
|
Packit Service |
310c69 |
#include "slabDepot.h"
|
|
Packit Service |
310c69 |
#include "slabSummary.h"
|
|
Packit Service |
310c69 |
#include "statistics.h"
|
|
Packit Service |
310c69 |
#include "statusCodes.h"
|
|
Packit Service |
310c69 |
#include "threadConfig.h"
|
|
Packit Service |
310c69 |
#include "vdoLayout.h"
|
|
Packit Service |
310c69 |
#include "vioWrite.h"
|
|
Packit Service |
310c69 |
#include "volumeGeometry.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* The master version of the on-disk format of a VDO. This should be
|
|
Packit Service |
310c69 |
* incremented any time the on-disk representation of any VDO structure
|
|
Packit Service |
310c69 |
* changes. Changes which require only online upgrade steps should increment
|
|
Packit Service |
310c69 |
* the minor version. Changes which require an offline upgrade or which can not
|
|
Packit Service |
310c69 |
* be upgraded to at all should increment the major version and set the minor
|
|
Packit Service |
310c69 |
* version to 0.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static const VersionNumber VDO_MASTER_VERSION_67_0 = {
|
|
Packit Service |
310c69 |
.majorVersion = 67,
|
|
Packit Service |
310c69 |
.minorVersion = 0,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* The current version for the data encoded in the super block. This must
|
|
Packit Service |
310c69 |
* be changed any time there is a change to encoding of the component data
|
|
Packit Service |
310c69 |
* of any VDO component.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static const VersionNumber VDO_COMPONENT_DATA_41_0 = {
|
|
Packit Service |
310c69 |
.majorVersion = 41,
|
|
Packit Service |
310c69 |
.minorVersion = 0,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* This is the structure that captures the VDO fields saved as a SuperBlock
|
|
Packit Service |
310c69 |
* component.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
typedef struct {
|
|
Packit Service |
310c69 |
VDOState state;
|
|
Packit Service |
310c69 |
uint64_t completeRecoveries;
|
|
Packit Service |
310c69 |
uint64_t readOnlyRecoveries;
|
|
Packit Service |
310c69 |
VDOConfig config;
|
|
Packit Service |
310c69 |
Nonce nonce;
|
|
Packit Service |
310c69 |
} __attribute__((packed)) VDOComponent41_0;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int allocateVDO(PhysicalLayer *layer, VDO **vdoPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = registerStatusCodes();
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
VDO *vdo;
|
|
Packit Service |
310c69 |
result = ALLOCATE(1, VDO, __func__, &vdo;;
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
vdo->layer = layer;
|
|
Packit Service |
310c69 |
if (layer->createEnqueueable != NULL) {
|
|
Packit Service |
310c69 |
result = initializeAdminCompletion(vdo, &vdo->adminCompletion);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
freeVDO(&vdo;;
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*vdoPtr = vdo;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int makeVDO(PhysicalLayer *layer, VDO **vdoPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
VDO *vdo;
|
|
Packit Service |
310c69 |
int result = allocateVDO(layer, &vdo;;
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = makeZeroThreadConfig(&vdo->loadConfig.threadConfig);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
freeVDO(&vdo;;
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*vdoPtr = vdo;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void destroyVDO(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
freeFlusher(&vdo->flusher);
|
|
Packit Service |
310c69 |
freePacker(&vdo->packer);
|
|
Packit Service |
310c69 |
freeRecoveryJournal(&vdo->recoveryJournal);
|
|
Packit Service |
310c69 |
freeSlabDepot(&vdo->depot);
|
|
Packit Service |
310c69 |
freeVDOLayout(&vdo->layout);
|
|
Packit Service |
310c69 |
freeSuperBlock(&vdo->superBlock);
|
|
Packit Service |
310c69 |
freeBlockMap(&vdo->blockMap);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
const ThreadConfig *threadConfig = getThreadConfig(vdo);
|
|
Packit Service |
310c69 |
if (vdo->hashZones != NULL) {
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < threadConfig->hashZoneCount; zone++) {
|
|
Packit Service |
310c69 |
freeHashZone(&vdo->hashZones[zone]);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
FREE(vdo->hashZones);
|
|
Packit Service |
310c69 |
vdo->hashZones = NULL;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
freeLogicalZones(&vdo->logicalZones);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (vdo->physicalZones != NULL) {
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < threadConfig->physicalZoneCount; zone++) {
|
|
Packit Service |
310c69 |
freePhysicalZone(&vdo->physicalZones[zone]);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
FREE(vdo->physicalZones);
|
|
Packit Service |
310c69 |
vdo->physicalZones = NULL;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
uninitializeAdminCompletion(&vdo->adminCompletion);
|
|
Packit Service |
310c69 |
freeReadOnlyNotifier(&vdo->readOnlyNotifier);
|
|
Packit Service |
310c69 |
freeThreadConfig(&vdo->loadConfig.threadConfig);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void freeVDO(VDO **vdoPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (*vdoPtr == NULL) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
destroyVDO(*vdoPtr);
|
|
Packit Service |
310c69 |
FREE(*vdoPtr);
|
|
Packit Service |
310c69 |
*vdoPtr = NULL;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
size_t getComponentDataSize(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (sizeof(VersionNumber)
|
|
Packit Service |
310c69 |
+ sizeof(VersionNumber)
|
|
Packit Service |
310c69 |
+ sizeof(VDOComponent41_0)
|
|
Packit Service |
310c69 |
+ getVDOLayoutEncodedSize(vdo->layout)
|
|
Packit Service |
310c69 |
+ getRecoveryJournalEncodedSize()
|
|
Packit Service |
310c69 |
+ getSlabDepotEncodedSize()
|
|
Packit Service |
310c69 |
+ getBlockMapEncodedSize());
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Encode the VDO master version.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param buffer The buffer in which to encode the version
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return VDO_SUCCESS or an error
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result))
|
|
Packit Service |
310c69 |
static int encodeMasterVersion(Buffer *buffer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return encodeVersionNumber(VDO_MASTER_VERSION_67_0, buffer);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Encode a VDOConfig structure into a buffer.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param config The config structure to encode
|
|
Packit Service |
310c69 |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return VDO_SUCCESS or an error
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result))
|
|
Packit Service |
310c69 |
static int encodeVDOConfig(const VDOConfig *config, Buffer *buffer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = putUInt64LEIntoBuffer(buffer, config->logicalBlocks);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, config->physicalBlocks);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, config->slabSize);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, config->recoveryJournalSize);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return putUInt64LEIntoBuffer(buffer, config->slabJournalBlocks);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Encode the component data for the VDO itself.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param vdo The vdo to encode
|
|
Packit Service |
310c69 |
* @param buffer The buffer in which to encode the VDO
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return VDO_SUCCESS or an error
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result))
|
|
Packit Service |
310c69 |
static int encodeVDOComponent(const VDO *vdo, Buffer *buffer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = encodeVersionNumber(VDO_COMPONENT_DATA_41_0, buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
size_t initialLength = contentLength(buffer);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt32LEIntoBuffer(buffer, vdo->state);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, vdo->completeRecoveries);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, vdo->readOnlyRecoveries);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = encodeVDOConfig(&vdo->config, buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putUInt64LEIntoBuffer(buffer, vdo->nonce);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
size_t encodedSize = contentLength(buffer) - initialLength;
|
|
Packit Service |
310c69 |
return ASSERT(encodedSize == sizeof(VDOComponent41_0),
|
|
Packit Service |
310c69 |
"encoded VDO component size must match structure size");
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
static int encodeVDO(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
Buffer *buffer = getComponentBuffer(vdo->superBlock);
|
|
Packit Service |
310c69 |
int result = resetBufferEnd(buffer, 0);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = encodeMasterVersion(buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = encodeVDOComponent(vdo, buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = encodeVDOLayout(vdo->layout, buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = encodeRecoveryJournal(vdo->recoveryJournal, buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = encodeSlabDepot(vdo->depot, buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = encodeBlockMap(vdo->blockMap, buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((contentLength(buffer) == getComponentDataSize(vdo)),
|
|
Packit Service |
310c69 |
"All super block component data was encoded");
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int saveVDOComponents(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = encodeVDO(vdo);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return saveSuperBlock(vdo->layer, vdo->superBlock, getFirstBlockOffset(vdo));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void saveVDOComponentsAsync(VDO *vdo, VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = encodeVDO(vdo);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
finishCompletion(parent, result);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
saveSuperBlockAsync(vdo->superBlock, getFirstBlockOffset(vdo), parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int saveReconfiguredVDO(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
Buffer *buffer = getComponentBuffer(vdo->superBlock);
|
|
Packit Service |
310c69 |
size_t componentsSize = contentLength(buffer);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
byte *components;
|
|
Packit Service |
310c69 |
int result = copyBytes(buffer, componentsSize, &components);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = resetBufferEnd(buffer, 0);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
FREE(components);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = encodeMasterVersion(buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
FREE(components);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = encodeVDOComponent(vdo, buffer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
FREE(components);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = putBytes(buffer, componentsSize, components);
|
|
Packit Service |
310c69 |
FREE(components);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return saveSuperBlock(vdo->layer, vdo->superBlock, getFirstBlockOffset(vdo));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int decodeVDOVersion(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return decodeVersionNumber(getComponentBuffer(vdo->superBlock),
|
|
Packit Service |
310c69 |
&vdo->loadVersion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int validateVDOVersion(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = decodeVDOVersion(vdo);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
ReleaseVersionNumber loadedReleaseVersion
|
|
Packit Service |
310c69 |
= getLoadedReleaseVersion(vdo->superBlock);
|
|
Packit Service |
310c69 |
if (vdo->loadConfig.releaseVersion != loadedReleaseVersion) {
|
|
Packit Service |
310c69 |
return logErrorWithStringError(VDO_UNSUPPORTED_VERSION,
|
|
Packit Service |
310c69 |
"Geometry release version %" PRIu32 " does "
|
|
Packit Service |
310c69 |
"not match super block release version %"
|
|
Packit Service |
310c69 |
PRIu32,
|
|
Packit Service |
310c69 |
vdo->loadConfig.releaseVersion,
|
|
Packit Service |
310c69 |
loadedReleaseVersion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return validateVersion(VDO_MASTER_VERSION_67_0, vdo->loadVersion, "master");
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Decode a VDOConfig structure from a buffer.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
310c69 |
* @param config The config structure to receive the decoded values
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result))
|
|
Packit Service |
310c69 |
static int decodeVDOConfig(Buffer *buffer, VDOConfig *config)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
BlockCount logicalBlocks;
|
|
Packit Service |
310c69 |
int result = getUInt64LEFromBuffer(buffer, &logicalBlocks);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockCount physicalBlocks;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &physicalBlocks);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockCount slabSize;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &slabSize);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockCount recoveryJournalSize;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &recoveryJournalSize);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
BlockCount slabJournalBlocks;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &slabJournalBlocks);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*config = (VDOConfig) {
|
|
Packit Service |
310c69 |
.logicalBlocks = logicalBlocks,
|
|
Packit Service |
310c69 |
.physicalBlocks = physicalBlocks,
|
|
Packit Service |
310c69 |
.slabSize = slabSize,
|
|
Packit Service |
310c69 |
.recoveryJournalSize = recoveryJournalSize,
|
|
Packit Service |
310c69 |
.slabJournalBlocks = slabJournalBlocks,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Decode the version 41.0 component state for the VDO itself from a buffer.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param buffer A buffer positioned at the start of the encoding
|
|
Packit Service |
310c69 |
* @param state The state structure to receive the decoded values
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return VDO_SUCCESS or an error
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result))
|
|
Packit Service |
310c69 |
static int decodeVDOComponent_41_0(Buffer *buffer, VDOComponent41_0 *state)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
size_t initialLength = contentLength(buffer);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
VDOState vdoState;
|
|
Packit Service |
310c69 |
int result = getUInt32LEFromBuffer(buffer, &vdoState);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
uint64_t completeRecoveries;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &completeRecoveries);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
uint64_t readOnlyRecoveries;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &readOnlyRecoveries);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
VDOConfig config;
|
|
Packit Service |
310c69 |
result = decodeVDOConfig(buffer, &config);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
Nonce nonce;
|
|
Packit Service |
310c69 |
result = getUInt64LEFromBuffer(buffer, &nonce);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*state = (VDOComponent41_0) {
|
|
Packit Service |
310c69 |
.state = vdoState,
|
|
Packit Service |
310c69 |
.completeRecoveries = completeRecoveries,
|
|
Packit Service |
310c69 |
.readOnlyRecoveries = readOnlyRecoveries,
|
|
Packit Service |
310c69 |
.config = config,
|
|
Packit Service |
310c69 |
.nonce = nonce,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
size_t decodedSize = initialLength - contentLength(buffer);
|
|
Packit Service |
310c69 |
return ASSERT(decodedSize == sizeof(VDOComponent41_0),
|
|
Packit Service |
310c69 |
"decoded VDO component size must match structure size");
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int decodeVDOComponent(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
Buffer *buffer = getComponentBuffer(vdo->superBlock);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
VersionNumber version;
|
|
Packit Service |
310c69 |
int result = decodeVersionNumber(buffer, &version);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = validateVersion(version, VDO_COMPONENT_DATA_41_0,
|
|
Packit Service |
310c69 |
"VDO component data");
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
VDOComponent41_0 component;
|
|
Packit Service |
310c69 |
result = decodeVDOComponent_41_0(buffer, &component);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Copy the decoded component into the VDO structure.
|
|
Packit Service |
310c69 |
vdo->state = component.state;
|
|
Packit Service |
310c69 |
vdo->loadState = component.state;
|
|
Packit Service |
310c69 |
vdo->completeRecoveries = component.completeRecoveries;
|
|
Packit Service |
310c69 |
vdo->readOnlyRecoveries = component.readOnlyRecoveries;
|
|
Packit Service |
310c69 |
vdo->config = component.config;
|
|
Packit Service |
310c69 |
vdo->nonce = component.nonce;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int validateVDOConfig(const VDOConfig *config,
|
|
Packit Service |
310c69 |
BlockCount blockCount,
|
|
Packit Service |
310c69 |
bool requireLogical)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
int result = ASSERT(config->slabSize > 0, "slab size unspecified");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(isPowerOfTwo(config->slabSize),
|
|
Packit Service |
310c69 |
"slab size must be a power of two");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(config->slabSize <= (1 << MAX_SLAB_BITS),
|
|
Packit Service |
310c69 |
"slab size must be less than or equal to 2^%d",
|
|
Packit Service |
310c69 |
MAX_SLAB_BITS);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(config->slabJournalBlocks >= MINIMUM_SLAB_JOURNAL_BLOCKS,
|
|
Packit Service |
310c69 |
"slab journal size meets minimum size");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(config->slabJournalBlocks <= config->slabSize,
|
|
Packit Service |
310c69 |
"slab journal size is within expected bound");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
SlabConfig slabConfig;
|
|
Packit Service |
310c69 |
result = configureSlab(config->slabSize, config->slabJournalBlocks,
|
|
Packit Service |
310c69 |
&slabConfig);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT((slabConfig.dataBlocks >= 1),
|
|
Packit Service |
310c69 |
"slab must be able to hold at least one block");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(config->physicalBlocks > 0, "physical blocks unspecified");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(config->physicalBlocks <= MAXIMUM_PHYSICAL_BLOCKS,
|
|
Packit Service |
310c69 |
"physical block count %llu exceeds maximum %llu",
|
|
Packit Service |
310c69 |
config->physicalBlocks, MAXIMUM_PHYSICAL_BLOCKS);
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return VDO_OUT_OF_RANGE;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// This can't check equality because FileLayer et al can only known about
|
|
Packit Service |
310c69 |
// the storage size, which may not match the super block size.
|
|
Packit Service |
310c69 |
if (blockCount < config->physicalBlocks) {
|
|
Packit Service |
310c69 |
logError("A physical size of %llu blocks was specified,"
|
|
Packit Service |
310c69 |
" but that is smaller than the %llu blocks"
|
|
Packit Service |
310c69 |
" configured in the VDO super block",
|
|
Packit Service |
310c69 |
blockCount, config->physicalBlocks);
|
|
Packit Service |
310c69 |
return VDO_PARAMETER_MISMATCH;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(!requireLogical || (config->logicalBlocks > 0),
|
|
Packit Service |
310c69 |
"logical blocks unspecified");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(config->logicalBlocks <= MAXIMUM_LOGICAL_BLOCKS,
|
|
Packit Service |
310c69 |
"logical blocks too large");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(config->recoveryJournalSize > 0,
|
|
Packit Service |
310c69 |
"recovery journal size unspecified");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = ASSERT(isPowerOfTwo(config->recoveryJournalSize),
|
|
Packit Service |
310c69 |
"recovery journal size must be a power of two");
|
|
Packit Service |
310c69 |
if (result != UDS_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Notify a VDO that it is going read-only. This will save the read-only state
|
|
Packit Service |
310c69 |
* to the super block.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ReadOnlyNotification.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param listener The VDO
|
|
Packit Service |
310c69 |
* @param parent The completion to notify in order to acknowledge the
|
|
Packit Service |
310c69 |
* notification
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void notifyVDOOfReadOnlyMode(void *listener, VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
VDO *vdo = listener;
|
|
Packit Service |
310c69 |
if (inReadOnlyMode(vdo)) {
|
|
Packit Service |
310c69 |
completeCompletion(parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
vdo->state = VDO_READ_ONLY_MODE;
|
|
Packit Service |
310c69 |
saveVDOComponentsAsync(vdo, parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int enableReadOnlyEntry(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return registerReadOnlyListener(vdo->readOnlyNotifier, vdo,
|
|
Packit Service |
310c69 |
notifyVDOOfReadOnlyMode,
|
|
Packit Service |
310c69 |
getAdminThread(getThreadConfig(vdo)));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool inReadOnlyMode(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (vdo->state == VDO_READ_ONLY_MODE);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool isClean(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return ((vdo->state == VDO_CLEAN) || (vdo->state == VDO_NEW));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool wasClean(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return ((vdo->loadState == VDO_CLEAN) || (vdo->loadState == VDO_NEW));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool wasNew(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (vdo->loadState == VDO_NEW);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool requiresReadOnlyRebuild(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return ((vdo->loadState == VDO_FORCE_REBUILD)
|
|
Packit Service |
310c69 |
|| (vdo->loadState == VDO_REBUILD_FOR_UPGRADE));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool requiresRebuild(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return ((vdo->state == VDO_DIRTY)
|
|
Packit Service |
310c69 |
|| (vdo->state == VDO_FORCE_REBUILD)
|
|
Packit Service |
310c69 |
|| (vdo->state == VDO_REPLAYING)
|
|
Packit Service |
310c69 |
|| (vdo->state == VDO_REBUILD_FOR_UPGRADE));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool requiresRecovery(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return ((vdo->loadState == VDO_DIRTY) || (vdo->loadState == VDO_REPLAYING)
|
|
Packit Service |
310c69 |
|| (vdo->loadState == VDO_RECOVERING));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool isReplaying(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (vdo->state == VDO_REPLAYING);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool inRecoveryMode(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (vdo->state == VDO_RECOVERING);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void enterRecoveryMode(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
assertOnAdminThread(vdo, __func__);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (inReadOnlyMode(vdo)) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
logInfo("Entering recovery mode");
|
|
Packit Service |
310c69 |
vdo->state = VDO_RECOVERING;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void leaveRecoveryMode(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
assertOnAdminThread(vdo, __func__);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Since scrubbing can be stopped by vdoClose during recovery mode,
|
|
Packit Service |
310c69 |
* do not change the VDO state if there are outstanding unrecovered slabs.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
if (inReadOnlyMode(vdo)) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY(inRecoveryMode(vdo), "VDO is in recovery mode");
|
|
Packit Service |
310c69 |
logInfo("Exiting recovery mode");
|
|
Packit Service |
310c69 |
vdo->state = VDO_DIRTY;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void makeVDOReadOnly(VDO *vdo, int errorCode)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
enterReadOnlyMode(vdo->readOnlyNotifier, errorCode);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool setVDOCompressing(VDO *vdo, bool enableCompression)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
bool stateChanged = compareAndSwapBool(&vdo->compressing, !enableCompression,
|
|
Packit Service |
310c69 |
enableCompression);
|
|
Packit Service |
310c69 |
if (stateChanged && !enableCompression) {
|
|
Packit Service |
310c69 |
// Flushing the packer is asynchronous, but we don't care when it
|
|
Packit Service |
310c69 |
// finishes.
|
|
Packit Service |
310c69 |
flushPacker(vdo->packer);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
logInfo("compression is %s", (enableCompression ? "enabled" : "disabled"));
|
|
Packit Service |
310c69 |
return (stateChanged ? !enableCompression : enableCompression);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool getVDOCompressing(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return atomicLoadBool(&vdo->compressing);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
static size_t getBlockMapCacheSize(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return ((size_t) vdo->loadConfig.cacheSize) * VDO_BLOCK_SIZE;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Tally the hash lock statistics from all the hash zones.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param vdo The vdo to query
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return The sum of the hash lock statistics from all hash zones
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static HashLockStatistics getHashLockStatistics(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
HashLockStatistics totals;
|
|
Packit Service |
310c69 |
memset(&totals, 0, sizeof(totals));
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
const ThreadConfig *threadConfig = getThreadConfig(vdo);
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < threadConfig->hashZoneCount; zone++) {
|
|
Packit Service |
310c69 |
HashLockStatistics stats = getHashZoneStatistics(vdo->hashZones[zone]);
|
|
Packit Service |
310c69 |
totals.dedupeAdviceValid += stats.dedupeAdviceValid;
|
|
Packit Service |
310c69 |
totals.dedupeAdviceStale += stats.dedupeAdviceStale;
|
|
Packit Service |
310c69 |
totals.concurrentDataMatches += stats.concurrentDataMatches;
|
|
Packit Service |
310c69 |
totals.concurrentHashCollisions += stats.concurrentHashCollisions;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return totals;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Get the current error statistics from VDO.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param vdo The vdo to query
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return a copy of the current VDO error counters
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static ErrorStatistics getVDOErrorStatistics(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* The error counts can be incremented from arbitrary threads and so must be
|
|
Packit Service |
310c69 |
* incremented atomically, but they are just statistics with no semantics
|
|
Packit Service |
310c69 |
* that could rely on memory order, so unfenced reads are sufficient.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
const AtomicErrorStatistics *atoms = &vdo->errorStats;
|
|
Packit Service |
310c69 |
return (ErrorStatistics) {
|
|
Packit Service |
310c69 |
.invalidAdvicePBNCount = relaxedLoad64(&atoms->invalidAdvicePBNCount),
|
|
Packit Service |
310c69 |
.noSpaceErrorCount = relaxedLoad64(&atoms->noSpaceErrorCount),
|
|
Packit Service |
310c69 |
.readOnlyErrorCount = relaxedLoad64(&atoms->readOnlyErrorCount),
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
static const char *describeWritePolicy(WritePolicy policy)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
switch (policy) {
|
|
Packit Service |
310c69 |
case WRITE_POLICY_ASYNC:
|
|
Packit Service |
310c69 |
return "async";
|
|
Packit Service |
310c69 |
case WRITE_POLICY_ASYNC_UNSAFE:
|
|
Packit Service |
310c69 |
return "async-unsafe";
|
|
Packit Service |
310c69 |
case WRITE_POLICY_SYNC:
|
|
Packit Service |
310c69 |
return "sync";
|
|
Packit Service |
310c69 |
default:
|
|
Packit Service |
310c69 |
return "unknown";
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void getVDOStatistics(const VDO *vdo, VDOStatistics *stats)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// These are immutable properties of the VDO object, so it is safe to
|
|
Packit Service |
310c69 |
// query them from any thread.
|
|
Packit Service |
310c69 |
RecoveryJournal *journal = vdo->recoveryJournal;
|
|
Packit Service |
310c69 |
SlabDepot *depot = vdo->depot;
|
|
Packit Service |
310c69 |
// XXX config.physicalBlocks is actually mutated during resize and is in a
|
|
Packit Service |
310c69 |
// packed structure, but resize runs on the admin thread so we're usually OK.
|
|
Packit Service |
310c69 |
stats->version = STATISTICS_VERSION;
|
|
Packit Service |
310c69 |
stats->releaseVersion = CURRENT_RELEASE_VERSION_NUMBER;
|
|
Packit Service |
310c69 |
stats->logicalBlocks = vdo->config.logicalBlocks;
|
|
Packit Service |
310c69 |
stats->physicalBlocks = vdo->config.physicalBlocks;
|
|
Packit Service |
310c69 |
stats->blockSize = VDO_BLOCK_SIZE;
|
|
Packit Service |
310c69 |
stats->completeRecoveries = vdo->completeRecoveries;
|
|
Packit Service |
310c69 |
stats->readOnlyRecoveries = vdo->readOnlyRecoveries;
|
|
Packit Service |
310c69 |
stats->blockMapCacheSize = getBlockMapCacheSize(vdo);
|
|
Packit Service |
310c69 |
snprintf(stats->writePolicy, sizeof(stats->writePolicy), "%s",
|
|
Packit Service |
310c69 |
describeWritePolicy(getWritePolicy(vdo)));
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// The callees are responsible for thread-safety.
|
|
Packit Service |
310c69 |
stats->dataBlocksUsed = getPhysicalBlocksAllocated(vdo);
|
|
Packit Service |
310c69 |
stats->overheadBlocksUsed = getPhysicalBlocksOverhead(vdo);
|
|
Packit Service |
310c69 |
stats->logicalBlocksUsed = getJournalLogicalBlocksUsed(journal);
|
|
Packit Service |
310c69 |
stats->allocator = getDepotBlockAllocatorStatistics(depot);
|
|
Packit Service |
310c69 |
stats->journal = getRecoveryJournalStatistics(journal);
|
|
Packit Service |
310c69 |
stats->packer = getPackerStatistics(vdo->packer);
|
|
Packit Service |
310c69 |
stats->slabJournal = getDepotSlabJournalStatistics(depot);
|
|
Packit Service |
310c69 |
stats->slabSummary = getSlabSummaryStatistics(getSlabSummary(depot));
|
|
Packit Service |
310c69 |
stats->refCounts = getDepotRefCountsStatistics(depot);
|
|
Packit Service |
310c69 |
stats->blockMap = getBlockMapStatistics(vdo->blockMap);
|
|
Packit Service |
310c69 |
stats->hashLock = getHashLockStatistics(vdo);
|
|
Packit Service |
310c69 |
stats->errors = getVDOErrorStatistics(vdo);
|
|
Packit Service |
310c69 |
SlabCount slabTotal = getDepotSlabCount(depot);
|
|
Packit Service |
310c69 |
stats->recoveryPercentage
|
|
Packit Service |
310c69 |
= (slabTotal - getDepotUnrecoveredSlabCount(depot)) * 100 / slabTotal;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// The "state" field is mutable, but we just need a unfenced atomic read.
|
|
Packit Service |
310c69 |
VDOState state = *((const volatile VDOState *) &vdo->state);
|
|
Packit Service |
310c69 |
stats->inRecoveryMode = (state == VDO_RECOVERING);
|
|
Packit Service |
310c69 |
snprintf(stats->mode, sizeof(stats->mode), "%s", describeVDOState(state));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockCount getPhysicalBlocksAllocated(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (getDepotAllocatedBlocks(vdo->depot)
|
|
Packit Service |
310c69 |
- getJournalBlockMapDataBlocksUsed(vdo->recoveryJournal));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockCount getPhysicalBlocksFree(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return getDepotFreeBlocks(vdo->depot);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockCount getPhysicalBlocksOverhead(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// XXX config.physicalBlocks is actually mutated during resize and is in a
|
|
Packit Service |
310c69 |
// packed structure, but resize runs on admin thread so we're usually OK.
|
|
Packit Service |
310c69 |
return (vdo->config.physicalBlocks
|
|
Packit Service |
310c69 |
- getDepotDataBlocks(vdo->depot)
|
|
Packit Service |
310c69 |
+ getJournalBlockMapDataBlocksUsed(vdo->recoveryJournal));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockCount getTotalBlockMapBlocks(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (getNumberOfFixedBlockMapPages(vdo->blockMap)
|
|
Packit Service |
310c69 |
+ getJournalBlockMapDataBlocksUsed(vdo->recoveryJournal));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
WritePolicy getWritePolicy(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return vdo->loadConfig.writePolicy;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void setWritePolicy(VDO *vdo, WritePolicy new)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
vdo->loadConfig.writePolicy = new;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
const VDOLoadConfig *getVDOLoadConfig(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return &vdo->loadConfig;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
const ThreadConfig *getThreadConfig(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return vdo->loadConfig.threadConfig;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockCount getConfiguredBlockMapMaximumAge(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return vdo->loadConfig.maximumAge;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
PageCount getConfiguredCacheSize(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return vdo->loadConfig.cacheSize;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
PhysicalBlockNumber getFirstBlockOffset(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return vdo->loadConfig.firstBlockOffset;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
BlockMap *getBlockMap(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return vdo->blockMap;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
SlabDepot *getSlabDepot(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return vdo->depot;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
RecoveryJournal *getRecoveryJournal(VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return vdo->recoveryJournal;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void dumpVDOStatus(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
dumpFlusher(vdo->flusher);
|
|
Packit Service |
310c69 |
dumpRecoveryJournalStatistics(vdo->recoveryJournal);
|
|
Packit Service |
310c69 |
dumpPacker(vdo->packer);
|
|
Packit Service |
310c69 |
dumpSlabDepot(vdo->depot);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
const ThreadConfig *threadConfig = getThreadConfig(vdo);
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < threadConfig->logicalZoneCount; zone++) {
|
|
Packit Service |
310c69 |
dumpLogicalZone(getLogicalZone(vdo->logicalZones, zone));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < threadConfig->physicalZoneCount; zone++) {
|
|
Packit Service |
310c69 |
dumpPhysicalZone(vdo->physicalZones[zone]);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
for (ZoneCount zone = 0; zone < threadConfig->hashZoneCount; zone++) {
|
|
Packit Service |
310c69 |
dumpHashZone(vdo->hashZones[zone]);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void setVDOTracingFlags(VDO *vdo, bool vioTracing)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
vdo->vioTraceRecording = vioTracing;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool vdoVIOTracingEnabled(const VDO *vdo)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return ((vdo != NULL) && vdo->vioTraceRecording);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void assertOnAdminThread(VDO *vdo, const char *name)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((getCallbackThreadID()
|
|
Packit Service |
310c69 |
== getAdminThread(getThreadConfig(vdo))),
|
|
Packit Service |
310c69 |
"%s called on admin thread", name);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void assertOnLogicalZoneThread(const VDO *vdo,
|
|
Packit Service |
310c69 |
ZoneCount logicalZone,
|
|
Packit Service |
310c69 |
const char *name)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((getCallbackThreadID()
|
|
Packit Service |
310c69 |
== getLogicalZoneThread(getThreadConfig(vdo), logicalZone)),
|
|
Packit Service |
310c69 |
"%s called on logical thread", name);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void assertOnPhysicalZoneThread(const VDO *vdo,
|
|
Packit Service |
310c69 |
ZoneCount physicalZone,
|
|
Packit Service |
310c69 |
const char *name)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((getCallbackThreadID()
|
|
Packit Service |
310c69 |
== getPhysicalZoneThread(getThreadConfig(vdo),
|
|
Packit Service |
310c69 |
physicalZone)),
|
|
Packit Service |
310c69 |
"%s called on physical thread", name);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
HashZone *selectHashZone(const VDO *vdo, const UdsChunkName *name)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Use a fragment of the chunk name as a hash code. To ensure uniform
|
|
Packit Service |
310c69 |
* distributions, it must not overlap with fragments used elsewhere. Eight
|
|
Packit Service |
310c69 |
* bits of hash should suffice since the number of hash zones is small.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
// XXX Make a central repository for these offsets ala hashUtils.
|
|
Packit Service |
310c69 |
// XXX Verify that the first byte is independent enough.
|
|
Packit Service |
310c69 |
uint32_t hash = name->name[0];
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Scale the 8-bit hash fragment to a zone index by treating it as a binary
|
|
Packit Service |
310c69 |
* fraction and multiplying that by the zone count. If the hash is uniformly
|
|
Packit Service |
310c69 |
* distributed over [0 .. 2^8-1], then (hash * count / 2^8) should be
|
|
Packit Service |
310c69 |
* uniformly distributed over [0 .. count-1]. The multiply and shift is much
|
|
Packit Service |
310c69 |
* faster than a divide (modulus) on X86 CPUs.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
return vdo->hashZones[(hash * getThreadConfig(vdo)->hashZoneCount) >> 8];
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int getPhysicalZone(const VDO *vdo,
|
|
Packit Service |
310c69 |
PhysicalBlockNumber pbn,
|
|
Packit Service |
310c69 |
PhysicalZone **zonePtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (pbn == ZERO_BLOCK) {
|
|
Packit Service |
310c69 |
*zonePtr = NULL;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Used because it does a more restrictive bounds check than getSlab(), and
|
|
Packit Service |
310c69 |
// done first because it won't trigger read-only mode on an invalid PBN.
|
|
Packit Service |
310c69 |
if (!isPhysicalDataBlock(vdo->depot, pbn)) {
|
|
Packit Service |
310c69 |
return VDO_OUT_OF_RANGE;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// With the PBN already checked, we should always succeed in finding a slab.
|
|
Packit Service |
310c69 |
Slab *slab = getSlab(vdo->depot, pbn);
|
|
Packit Service |
310c69 |
int result = ASSERT(slab != NULL, "getSlab must succeed on all valid PBNs");
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*zonePtr = vdo->physicalZones[getSlabZoneNumber(slab)];
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
ZonedPBN validateDedupeAdvice(VDO *vdo,
|
|
Packit Service |
310c69 |
const DataLocation *advice,
|
|
Packit Service |
310c69 |
LogicalBlockNumber lbn)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ZonedPBN noAdvice = { .pbn = ZERO_BLOCK };
|
|
Packit Service |
310c69 |
if (advice == NULL) {
|
|
Packit Service |
310c69 |
return noAdvice;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Don't use advice that's clearly meaningless.
|
|
Packit Service |
310c69 |
if ((advice->state == MAPPING_STATE_UNMAPPED)
|
|
Packit Service |
310c69 |
|| (advice->pbn == ZERO_BLOCK)) {
|
|
Packit Service |
310c69 |
logDebug("Invalid advice from deduplication server: pbn %llu, "
|
|
Packit Service |
310c69 |
"state %u. Giving up on deduplication of logical block %llu",
|
|
Packit Service |
310c69 |
advice->pbn, advice->state, lbn);
|
|
Packit Service |
310c69 |
atomicAdd64(&vdo->errorStats.invalidAdvicePBNCount, 1);
|
|
Packit Service |
310c69 |
return noAdvice;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
PhysicalZone *zone;
|
|
Packit Service |
310c69 |
int result = getPhysicalZone(vdo, advice->pbn, &zone);
|
|
Packit Service |
310c69 |
if ((result != VDO_SUCCESS) || (zone == NULL)) {
|
|
Packit Service |
310c69 |
logDebug("Invalid physical block number from deduplication server: %"
|
|
Packit Service |
310c69 |
PRIu64 ", giving up on deduplication of logical block %llu",
|
|
Packit Service |
310c69 |
advice->pbn, lbn);
|
|
Packit Service |
310c69 |
atomicAdd64(&vdo->errorStats.invalidAdvicePBNCount, 1);
|
|
Packit Service |
310c69 |
return noAdvice;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return (ZonedPBN) {
|
|
Packit Service |
310c69 |
.pbn = advice->pbn,
|
|
Packit Service |
310c69 |
.state = advice->state,
|
|
Packit Service |
310c69 |
.zone = zone,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
}
|