/*
* Copyright (c) 2020 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/packedRecoveryJournalBlock.h#3 $
*/
#ifndef PACKED_RECOVERY_JOURNAL_BLOCK_H
#define PACKED_RECOVERY_JOURNAL_BLOCK_H
#include "numeric.h"
#include "constants.h"
#include "recoveryJournalEntry.h"
#include "types.h"
typedef struct {
SequenceNumber blockMapHead; // Block map head sequence number
SequenceNumber slabJournalHead; // Slab journal head sequence number
SequenceNumber sequenceNumber; // Sequence number for this block
Nonce nonce; // A given VDO instance's nonce
BlockCount logicalBlocksUsed; // Count of logical blocks in use
BlockCount blockMapDataBlocks; // Count of allocated block map pages
JournalEntryCount entryCount; // Number of entries written
uint8_t checkByte; // The protection check byte
uint8_t recoveryCount; // The number of recoveries completed
VDOMetadataType metadataType; // Metadata type
} RecoveryBlockHeader;
/**
* The packed, on-disk representation of a recovery journal block header.
* All fields are kept in little-endian byte order.
**/
typedef union __attribute__((packed)) {
struct __attribute__((packed)) {
/** Block map head 64-bit sequence number */
byte blockMapHead[8];
/** Slab journal head 64-bit sequence number */
byte slabJournalHead[8];
/** The 64-bit sequence number for this block */
byte sequenceNumber[8];
/** A given VDO instance's 64-bit nonce */
byte nonce[8];
/** 8-bit metadata type (should always be one for the recovery journal) */
uint8_t metadataType;
/** 16-bit count of the entries encoded in the block */
byte entryCount[2];
/** 64-bit count of the logical blocks used when this block was opened */
byte logicalBlocksUsed[8];
/** 64-bit count of the block map blocks used when this block was opened */
byte blockMapDataBlocks[8];
/** The protection check byte */
uint8_t checkByte;
/** The number of recoveries completed */
uint8_t recoveryCount;
} fields;
// A raw view of the packed encoding.
uint8_t raw[8 + 8 + 8 + 8 + 1 + 2 + 8 + 8 + 1 + 1];
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
// This view is only valid on little-endian machines and is only present for
// ease of directly examining packed entries in GDB.
struct __attribute__((packed)) {
SequenceNumber blockMapHead;
SequenceNumber slabJournalHead;
SequenceNumber sequenceNumber;
Nonce nonce;
VDOMetadataType metadataType;
JournalEntryCount entryCount;
BlockCount logicalBlocksUsed;
BlockCount blockMapDataBlocks;
uint8_t checkByte;
uint8_t recoveryCount;
} littleEndian;
#endif
} PackedJournalHeader;
typedef struct {
/** The protection check byte */
uint8_t checkByte;
/** The number of recoveries completed */
uint8_t recoveryCount;
/** The number of entries in this sector */
uint8_t entryCount;
/** Journal entries for this sector */
PackedRecoveryJournalEntry entries[];
} __attribute__((packed)) PackedJournalSector;
enum {
// Allowing more than 311 entries in each block changes the math
// concerning the amortization of metadata writes and recovery speed.
RECOVERY_JOURNAL_ENTRIES_PER_BLOCK = 311,
/** The number of entries in each sector (except the last) when filled */
RECOVERY_JOURNAL_ENTRIES_PER_SECTOR
= ((VDO_SECTOR_SIZE - sizeof(PackedJournalSector))
/ sizeof(PackedRecoveryJournalEntry)),
/** The number of entries in the last sector when a block is full */
RECOVERY_JOURNAL_ENTRIES_PER_LAST_SECTOR
= (RECOVERY_JOURNAL_ENTRIES_PER_BLOCK
% RECOVERY_JOURNAL_ENTRIES_PER_SECTOR),
};
/**
* Find the recovery journal sector from the block header and sector number.
*
* @param header The header of the recovery journal block
* @param sectorNumber The index of the sector (1-based)
*
* @return A packed recovery journal sector
**/
__attribute__((warn_unused_result))
static inline
PackedJournalSector *getJournalBlockSector(PackedJournalHeader *header,
int sectorNumber)
{
char *sectorData = ((char *) header) + (VDO_SECTOR_SIZE * sectorNumber);
return (PackedJournalSector *) sectorData;
}
/**
* Generate the packed representation of a recovery block header.
*
* @param header The header containing the values to encode
* @param packed The header into which to pack the values
**/
static inline void packRecoveryBlockHeader(const RecoveryBlockHeader *header,
PackedJournalHeader *packed)
{
storeUInt64LE(packed->fields.blockMapHead, header->blockMapHead);
storeUInt64LE(packed->fields.slabJournalHead, header->slabJournalHead);
storeUInt64LE(packed->fields.sequenceNumber, header->sequenceNumber);
storeUInt64LE(packed->fields.nonce, header->nonce);
storeUInt64LE(packed->fields.logicalBlocksUsed, header->logicalBlocksUsed);
storeUInt64LE(packed->fields.blockMapDataBlocks, header->blockMapDataBlocks);
storeUInt16LE(packed->fields.entryCount, header->entryCount);
packed->fields.checkByte = header->checkByte;
packed->fields.recoveryCount = header->recoveryCount;
packed->fields.metadataType = header->metadataType;
}
/**
* Decode the packed representation of a recovery block header.
*
* @param packed The packed header to decode
* @param header The header into which to unpack the values
**/
static inline void unpackRecoveryBlockHeader(const PackedJournalHeader *packed,
RecoveryBlockHeader *header)
{
*header = (RecoveryBlockHeader) {
.blockMapHead = getUInt64LE(packed->fields.blockMapHead),
.slabJournalHead = getUInt64LE(packed->fields.slabJournalHead),
.sequenceNumber = getUInt64LE(packed->fields.sequenceNumber),
.nonce = getUInt64LE(packed->fields.nonce),
.logicalBlocksUsed = getUInt64LE(packed->fields.logicalBlocksUsed),
.blockMapDataBlocks = getUInt64LE(packed->fields.blockMapDataBlocks),
.entryCount = getUInt16LE(packed->fields.entryCount),
.checkByte = packed->fields.checkByte,
.recoveryCount = packed->fields.recoveryCount,
.metadataType = packed->fields.metadataType,
};
}
#endif // PACKED_RECOVERY_JOURNAL_BLOCK_H