Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/md/dm-vdo/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 42 kB image not shown  

Quelle  encodings.h   Sprache: C

 
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright 2023 Red Hat
 */


#ifndef VDO_ENCODINGS_H
#define VDO_ENCODINGS_H

#include <linux/blk_types.h>
#include <linux/crc32.h>
#include <linux/limits.h>
#include <linux/uuid.h>

#include "numeric.h"

#include "constants.h"
#include "types.h"

/*
 * An in-memory representation of a version number for versioned structures on disk.
 *
 * A version number consists of two portions, a major version and a minor version. Any format
 * change which does not require an explicit upgrade step from the previous version should
 * increment the minor version. Any format change which either requires an explicit upgrade step,
 * or is wholly incompatible (i.e. can not be upgraded to), should increment the major version, and
 * set the minor version to 0.
 */

struct version_number {
 u32 major_version;
 u32 minor_version;
};

/*
 * A packed, machine-independent, on-disk representation of a version_number. Both fields are
 * stored in little-endian byte order.
 */

struct packed_version_number {
 __le32 major_version;
 __le32 minor_version;
} __packed;

/* The registry of component ids for use in headers */
#define VDO_SUPER_BLOCK 0
#define VDO_LAYOUT 1
#define VDO_RECOVERY_JOURNAL 2
#define VDO_SLAB_DEPOT 3
#define VDO_BLOCK_MAP 4
#define VDO_GEOMETRY_BLOCK 5

/* The header for versioned data stored on disk. */
struct header {
 u32 id; /* The component this is a header for */
 struct version_number version; /* The version of the data format */
 size_t size; /* The size of the data following this header */
};

/* A packed, machine-independent, on-disk representation of a component header. */
struct packed_header {
 __le32 id;
 struct packed_version_number version;
 __le64 size;
} __packed;

enum {
 VDO_GEOMETRY_BLOCK_LOCATION = 0,
 VDO_GEOMETRY_MAGIC_NUMBER_SIZE = 8,
 VDO_DEFAULT_GEOMETRY_BLOCK_VERSION = 5,
};

struct index_config {
 u32 mem;
 u32 unused;
 bool sparse;
} __packed;

enum volume_region_id {
 VDO_INDEX_REGION = 0,
 VDO_DATA_REGION = 1,
 VDO_VOLUME_REGION_COUNT,
};

struct volume_region {
 /* The ID of the region */
 enum volume_region_id id;
 /*
 * The absolute starting offset on the device. The region continues until the next region
 * begins.
 */

 physical_block_number_t start_block;
} __packed;

struct volume_geometry {
 /* For backwards compatibility */
 u32 unused;
 /* The nonce of this volume */
 nonce_t nonce;
 /* The uuid of this volume */
 uuid_t uuid;
 /* The block offset to be applied to bios */
 block_count_t bio_offset;
 /* The regions in ID order */
 struct volume_region regions[VDO_VOLUME_REGION_COUNT];
 /* The index config */
 struct index_config index_config;
} __packed;

/* This volume geometry struct is used for sizing only */
struct volume_geometry_4_0 {
 /* For backwards compatibility */
 u32 unused;
 /* The nonce of this volume */
 nonce_t nonce;
 /* The uuid of this volume */
 uuid_t uuid;
 /* The regions in ID order */
 struct volume_region regions[VDO_VOLUME_REGION_COUNT];
 /* The index config */
 struct index_config index_config;
} __packed;

extern const u8 VDO_GEOMETRY_MAGIC_NUMBER[VDO_GEOMETRY_MAGIC_NUMBER_SIZE + 1];

/**
 * DOC: Block map entries
 *
 * The entry for each logical block in the block map is encoded into five bytes, which saves space
 * in both the on-disk and in-memory layouts. It consists of the 36 low-order bits of a
 * physical_block_number_t (addressing 256 terabytes with a 4KB block size) and a 4-bit encoding of
 * a block_mapping_state.
 *
 * Of the 8 high bits of the 5-byte structure:
 *
 * Bits 7..4: The four highest bits of the 36-bit physical block number
 * Bits 3..0: The 4-bit block_mapping_state
 *
 * The following 4 bytes are the low order bytes of the physical block number, in little-endian
 * order.
 *
 * Conversion functions to and from a data location are provided.
 */

struct block_map_entry {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 unsigned mapping_state : 4;
 unsigned pbn_high_nibble : 4;
#else
 unsigned pbn_high_nibble : 4;
 unsigned mapping_state : 4;
#endif

 __le32 pbn_low_word;
} __packed;

struct block_map_page_header {
 __le64 nonce;
 __le64 pbn;

 /* May be non-zero on disk */
 u8 unused_long_word[8];

 /* Whether this page has been written twice to disk */
 bool initialized;

 /* Always zero on disk */
 u8 unused_byte1;

 /* May be non-zero on disk */
 u8 unused_byte2;
 u8 unused_byte3;
} __packed;

struct block_map_page {
 struct packed_version_number version;
 struct block_map_page_header header;
 struct block_map_entry entries[];
} __packed;

enum block_map_page_validity {
 VDO_BLOCK_MAP_PAGE_VALID,
 VDO_BLOCK_MAP_PAGE_INVALID,
 /* Valid page found in the wrong location on disk */
 VDO_BLOCK_MAP_PAGE_BAD,
};

struct block_map_state_2_0 {
 physical_block_number_t flat_page_origin;
 block_count_t flat_page_count;
 physical_block_number_t root_origin;
 block_count_t root_count;
} __packed;

struct boundary {
 page_number_t levels[VDO_BLOCK_MAP_TREE_HEIGHT];
};

extern const struct header VDO_BLOCK_MAP_HEADER_2_0;

/* The state of the recovery journal as encoded in the VDO super block. */
struct recovery_journal_state_7_0 {
 /* Sequence number to start the journal */
 sequence_number_t journal_start;
 /* Number of logical blocks used by VDO */
 block_count_t logical_blocks_used;
 /* Number of block map pages allocated */
 block_count_t block_map_data_blocks;
} __packed;

extern const struct header VDO_RECOVERY_JOURNAL_HEADER_7_0;

typedef u16 journal_entry_count_t;

/*
 * A recovery journal entry stores three physical locations: a data location that is the value of a
 * single mapping in the block map tree, and the two locations of the block map pages and slots
 * that are acquiring and releasing a reference to the location. The journal entry also stores an
 * operation code that says whether the mapping is for a logical block or for the block map tree
 * itself.
 */

struct recovery_journal_entry {
 struct block_map_slot slot;
 struct data_location mapping;
 struct data_location unmapping;
 enum journal_operation operation;
};

/* The packed, on-disk representation of a recovery journal entry. */
struct packed_recovery_journal_entry {
 /*
 * In little-endian bit order:
 * Bits 15..12: The four highest bits of the 36-bit physical block number of the block map
 * tree page
 * Bits 11..2: The 10-bit block map page slot number
 * Bit 1..0: The journal_operation of the entry (this actually only requires 1 bit, but
 *           it is convenient to keep the extra bit as part of this field.
 */

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 unsigned operation : 2;
 unsigned slot_low : 6;
 unsigned slot_high : 4;
 unsigned pbn_high_nibble : 4;
#else
 unsigned slot_low : 6;
 unsigned operation : 2;
 unsigned pbn_high_nibble : 4;
 unsigned slot_high : 4;
#endif

 /*
 * Bits 47..16: The 32 low-order bits of the block map page PBN, in little-endian byte
 * order
 */

 __le32 pbn_low_word;

 /*
 * Bits 87..48: The five-byte block map entry encoding the location that will be stored in
 * the block map page slot
 */

 struct block_map_entry mapping;

 /*
 * Bits 127..88: The five-byte block map entry encoding the location that was stored in the
 * block map page slot
 */

 struct block_map_entry unmapping;
} __packed;

/* The packed, on-disk representation of an old format recovery journal entry. */
struct packed_recovery_journal_entry_1 {
 /*
 * In little-endian bit order:
 * Bits 15..12: The four highest bits of the 36-bit physical block number of the block map
 *              tree page
 * Bits 11..2: The 10-bit block map page slot number
 * Bits 1..0: The 2-bit journal_operation of the entry
 *
 */

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 unsigned operation : 2;
 unsigned slot_low : 6;
 unsigned slot_high : 4;
 unsigned pbn_high_nibble : 4;
#else
 unsigned slot_low : 6;
 unsigned operation : 2;
 unsigned pbn_high_nibble : 4;
 unsigned slot_high : 4;
#endif

 /*
 * Bits 47..16: The 32 low-order bits of the block map page PBN, in little-endian byte
 * order
 */

 __le32 pbn_low_word;

 /*
 * Bits 87..48: The five-byte block map entry encoding the location that was or will be
 * stored in the block map page slot
 */

 struct block_map_entry block_map_entry;
} __packed;

enum journal_operation_1 {
 VDO_JOURNAL_DATA_DECREMENT = 0,
 VDO_JOURNAL_DATA_INCREMENT = 1,
 VDO_JOURNAL_BLOCK_MAP_DECREMENT = 2,
 VDO_JOURNAL_BLOCK_MAP_INCREMENT = 3,
} __packed;

struct recovery_block_header {
 sequence_number_t block_map_head; /* Block map head sequence number */
 sequence_number_t slab_journal_head; /* Slab journal head seq. number */
 sequence_number_t sequence_number; /* Sequence number for this block */
 nonce_t nonce; /* A given VDO instance's nonce */
 block_count_t logical_blocks_used; /* Logical blocks in use */
 block_count_t block_map_data_blocks; /* Allocated block map pages */
 journal_entry_count_t entry_count; /* Number of entries written */
 u8 check_byte; /* The protection check byte */
 u8 recovery_count; /* Number of recoveries completed */
 enum vdo_metadata_type metadata_type; /* Metadata type */
};

/*
 * The packed, on-disk representation of a recovery journal block header. All fields are kept in
 * little-endian byte order.
 */

struct packed_journal_header {
 /* Block map head 64-bit sequence number */
 __le64 block_map_head;

 /* Slab journal head 64-bit sequence number */
 __le64 slab_journal_head;

 /* The 64-bit sequence number for this block */
 __le64 sequence_number;

 /* A given VDO instance's 64-bit nonce */
 __le64 nonce;

 /* 8-bit metadata type (should always be one for the recovery journal) */
 u8 metadata_type;

 /* 16-bit count of the entries encoded in the block */
 __le16 entry_count;

 /* 64-bit count of the logical blocks used when this block was opened */
 __le64 logical_blocks_used;

 /* 64-bit count of the block map blocks used when this block was opened */
 __le64 block_map_data_blocks;

 /* The protection check byte */
 u8 check_byte;

 /* The number of recoveries completed */
 u8 recovery_count;
} __packed;

struct packed_journal_sector {
 /* The protection check byte */
 u8 check_byte;

 /* The number of recoveries completed */
 u8 recovery_count;

 /* The number of entries in this sector */
 u8 entry_count;

 /* Journal entries for this sector */
 struct packed_recovery_journal_entry entries[];
} __packed;

enum {
 /* The number of entries in each sector (except the last) when filled */
 RECOVERY_JOURNAL_ENTRIES_PER_SECTOR =
  ((VDO_SECTOR_SIZE - sizeof(struct packed_journal_sector)) /
   sizeof(struct packed_recovery_journal_entry)),
 RECOVERY_JOURNAL_ENTRIES_PER_BLOCK = RECOVERY_JOURNAL_ENTRIES_PER_SECTOR * 7,
 /* The number of entries in a v1 recovery journal block. */
 RECOVERY_JOURNAL_1_ENTRIES_PER_BLOCK = 311,
 /* The number of entries in each v1 sector (except the last) when filled */
 RECOVERY_JOURNAL_1_ENTRIES_PER_SECTOR =
  ((VDO_SECTOR_SIZE - sizeof(struct packed_journal_sector)) /
   sizeof(struct packed_recovery_journal_entry_1)),
 /* The number of entries in the last sector when a block is full */
 RECOVERY_JOURNAL_1_ENTRIES_IN_LAST_SECTOR =
  (RECOVERY_JOURNAL_1_ENTRIES_PER_BLOCK % RECOVERY_JOURNAL_1_ENTRIES_PER_SECTOR),
};

/* A type representing a reference count of a block. */
typedef u8 vdo_refcount_t;

/* The absolute position of an entry in a recovery journal or slab journal. */
struct journal_point {
 sequence_number_t sequence_number;
 journal_entry_count_t entry_count;
};

/* A packed, platform-independent encoding of a struct journal_point. */
struct packed_journal_point {
 /*
 * The packed representation is the little-endian 64-bit representation of the low-order 48
 * bits of the sequence number, shifted up 16 bits, or'ed with the 16-bit entry count.
 *
 * Very long-term, the top 16 bits of the sequence number may not always be zero, as this
 * encoding assumes--see BZ 1523240.
 */

 __le64 encoded_point;
} __packed;

/* Special vdo_refcount_t values. */
#define EMPTY_REFERENCE_COUNT 0
enum {
 MAXIMUM_REFERENCE_COUNT = 254,
 PROVISIONAL_REFERENCE_COUNT = 255,
};

enum {
 COUNTS_PER_SECTOR =
  ((VDO_SECTOR_SIZE - sizeof(struct packed_journal_point)) / sizeof(vdo_refcount_t)),
 COUNTS_PER_BLOCK = COUNTS_PER_SECTOR * VDO_SECTORS_PER_BLOCK,
};

/* The format of each sector of a reference_block on disk. */
struct packed_reference_sector {
 struct packed_journal_point commit_point;
 vdo_refcount_t counts[COUNTS_PER_SECTOR];
} __packed;

struct packed_reference_block {
 struct packed_reference_sector sectors[VDO_SECTORS_PER_BLOCK];
};

struct slab_depot_state_2_0 {
 struct slab_config slab_config;
 physical_block_number_t first_block;
 physical_block_number_t last_block;
 zone_count_t zone_count;
} __packed;

extern const struct header VDO_SLAB_DEPOT_HEADER_2_0;

/*
 * vdo_slab journal blocks may have one of two formats, depending upon whether or not any of the
 * entries in the block are block map increments. Since the steady state for a VDO is that all of
 * the necessary block map pages will be allocated, most slab journal blocks will have only data
 * entries. Such blocks can hold more entries, hence the two formats.
 */


/* A single slab journal entry */
struct slab_journal_entry {
 slab_block_number sbn;
 enum journal_operation operation;
 bool increment;
};

/* A single slab journal entry in its on-disk form */
typedef struct {
 u8 offset_low8;
 u8 offset_mid8;

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 unsigned offset_high7 : 7;
 unsigned increment : 1;
#else
 unsigned increment : 1;
 unsigned offset_high7 : 7;
#endif
} __packed packed_slab_journal_entry;

/* The unpacked representation of the header of a slab journal block */
struct slab_journal_block_header {
 /* Sequence number for head of journal */
 sequence_number_t head;
 /* Sequence number for this block */
 sequence_number_t sequence_number;
 /* The nonce for a given VDO instance */
 nonce_t nonce;
 /* Recovery journal point for last entry */
 struct journal_point recovery_point;
 /* Metadata type */
 enum vdo_metadata_type metadata_type;
 /* Whether this block contains block map increments */
 bool has_block_map_increments;
 /* The number of entries in the block */
 journal_entry_count_t entry_count;
};

/*
 * The packed, on-disk representation of a slab journal block header. All fields are kept in
 * little-endian byte order.
 */

struct packed_slab_journal_block_header {
 /* 64-bit sequence number for head of journal */
 __le64 head;
 /* 64-bit sequence number for this block */
 __le64 sequence_number;
 /* Recovery journal point for the last entry, packed into 64 bits */
 struct packed_journal_point recovery_point;
 /* The 64-bit nonce for a given VDO instance */
 __le64 nonce;
 /* 8-bit metadata type (should always be two, for the slab journal) */
 u8 metadata_type;
 /* Whether this block contains block map increments */
 bool has_block_map_increments;
 /* 16-bit count of the entries encoded in the block */
 __le16 entry_count;
} __packed;

enum {
 VDO_SLAB_JOURNAL_PAYLOAD_SIZE =
  VDO_BLOCK_SIZE - sizeof(struct packed_slab_journal_block_header),
 VDO_SLAB_JOURNAL_FULL_ENTRIES_PER_BLOCK = (VDO_SLAB_JOURNAL_PAYLOAD_SIZE * 8) / 25,
 VDO_SLAB_JOURNAL_ENTRY_TYPES_SIZE =
  ((VDO_SLAB_JOURNAL_FULL_ENTRIES_PER_BLOCK - 1) / 8) + 1,
 VDO_SLAB_JOURNAL_ENTRIES_PER_BLOCK =
  (VDO_SLAB_JOURNAL_PAYLOAD_SIZE / sizeof(packed_slab_journal_entry)),
};

/* The payload of a slab journal block which has block map increments */
struct full_slab_journal_entries {
 /* The entries themselves */
 packed_slab_journal_entry entries[VDO_SLAB_JOURNAL_FULL_ENTRIES_PER_BLOCK];
 /* The bit map indicating which entries are block map increments */
 u8 entry_types[VDO_SLAB_JOURNAL_ENTRY_TYPES_SIZE];
} __packed;

typedef union {
 /* Entries which include block map increments */
 struct full_slab_journal_entries full_entries;
 /* Entries which are only data updates */
 packed_slab_journal_entry entries[VDO_SLAB_JOURNAL_ENTRIES_PER_BLOCK];
 /* Ensure the payload fills to the end of the block */
 u8 space[VDO_SLAB_JOURNAL_PAYLOAD_SIZE];
} __packed slab_journal_payload;

struct packed_slab_journal_block {
 struct packed_slab_journal_block_header header;
 slab_journal_payload payload;
} __packed;

/* The offset of a slab journal tail block. */
typedef u8 tail_block_offset_t;

struct slab_summary_entry {
 /* Bits 7..0: The offset of the tail block within the slab journal */
 tail_block_offset_t tail_block_offset;

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 /* Bits 13..8: A hint about the fullness of the slab */
 unsigned int fullness_hint : 6;
 /* Bit 14: Whether the ref_counts must be loaded from the layer */
 unsigned int load_ref_counts : 1;
 /* Bit 15: The believed cleanliness of this slab */
 unsigned int is_dirty : 1;
#else
 /* Bit 15: The believed cleanliness of this slab */
 unsigned int is_dirty : 1;
 /* Bit 14: Whether the ref_counts must be loaded from the layer */
 unsigned int load_ref_counts : 1;
 /* Bits 13..8: A hint about the fullness of the slab */
 unsigned int fullness_hint : 6;
#endif
} __packed;

enum {
 VDO_SLAB_SUMMARY_FULLNESS_HINT_BITS = 6,
 VDO_SLAB_SUMMARY_ENTRIES_PER_BLOCK = VDO_BLOCK_SIZE / sizeof(struct slab_summary_entry),
 VDO_SLAB_SUMMARY_BLOCKS_PER_ZONE = MAX_VDO_SLABS / VDO_SLAB_SUMMARY_ENTRIES_PER_BLOCK,
 VDO_SLAB_SUMMARY_BLOCKS = VDO_SLAB_SUMMARY_BLOCKS_PER_ZONE * MAX_VDO_PHYSICAL_ZONES,
};

struct layout {
 physical_block_number_t start;
 block_count_t size;
 physical_block_number_t first_free;
 physical_block_number_t last_free;
 size_t num_partitions;
 struct partition *head;
};

struct partition {
 enum partition_id id; /* The id of this partition */
 physical_block_number_t offset; /* The offset into the layout of this partition */
 block_count_t count; /* The number of blocks in the partition */
 struct partition *next; /* A pointer to the next partition in the layout */
};

struct layout_3_0 {
 physical_block_number_t first_free;
 physical_block_number_t last_free;
 u8 partition_count;
} __packed;

struct partition_3_0 {
 enum partition_id id;
 physical_block_number_t offset;
 physical_block_number_t base; /* unused but retained for backwards compatibility */
 block_count_t count;
} __packed;

/*
 * The configuration of the VDO service.
 */

struct vdo_config {
 block_count_t logical_blocks; /* number of logical blocks */
 block_count_t physical_blocks; /* number of physical blocks */
 block_count_t slab_size; /* number of blocks in a slab */
 block_count_t recovery_journal_size; /* number of recovery journal blocks */
 block_count_t slab_journal_blocks; /* number of slab journal blocks */
};

/* This is the structure that captures the vdo fields saved as a super block component. */
struct vdo_component {
 enum vdo_state state;
 u64 complete_recoveries;
 u64 read_only_recoveries;
 struct vdo_config config;
 nonce_t nonce;
};

/*
 * A packed, machine-independent, on-disk representation of the vdo_config in the VDO component
 * data in the super block.
 */

struct packed_vdo_config {
 __le64 logical_blocks;
 __le64 physical_blocks;
 __le64 slab_size;
 __le64 recovery_journal_size;
 __le64 slab_journal_blocks;
} __packed;

/*
 * A packed, machine-independent, on-disk representation of version 41.0 of the VDO component data
 * in the super block.
 */

struct packed_vdo_component_41_0 {
 __le32 state;
 __le64 complete_recoveries;
 __le64 read_only_recoveries;
 struct packed_vdo_config config;
 __le64 nonce;
} __packed;

/*
 * The version of the on-disk format of a VDO volume. This should be incremented any time the
 * on-disk representation of any VDO structure changes. Changes which require only online upgrade
 * steps should increment the minor version. Changes which require an offline upgrade or which can
 * not be upgraded to at all should increment the major version and set the minor version to 0.
 */

extern const struct version_number VDO_VOLUME_VERSION_67_0;

enum {
 VDO_ENCODED_HEADER_SIZE = sizeof(struct packed_header),
 BLOCK_MAP_COMPONENT_ENCODED_SIZE =
  VDO_ENCODED_HEADER_SIZE + sizeof(struct block_map_state_2_0),
 RECOVERY_JOURNAL_COMPONENT_ENCODED_SIZE =
  VDO_ENCODED_HEADER_SIZE + sizeof(struct recovery_journal_state_7_0),
 SLAB_DEPOT_COMPONENT_ENCODED_SIZE =
  VDO_ENCODED_HEADER_SIZE + sizeof(struct slab_depot_state_2_0),
 VDO_PARTITION_COUNT = 4,
 VDO_LAYOUT_ENCODED_SIZE = (VDO_ENCODED_HEADER_SIZE +
       sizeof(struct layout_3_0) +
       (sizeof(struct partition_3_0) * VDO_PARTITION_COUNT)),
 VDO_SUPER_BLOCK_FIXED_SIZE = VDO_ENCODED_HEADER_SIZE + sizeof(u32),
 VDO_MAX_COMPONENT_DATA_SIZE = VDO_SECTOR_SIZE - VDO_SUPER_BLOCK_FIXED_SIZE,
 VDO_COMPONENT_ENCODED_SIZE =
  (sizeof(struct packed_version_number) + sizeof(struct packed_vdo_component_41_0)),
 VDO_COMPONENT_DATA_OFFSET = VDO_ENCODED_HEADER_SIZE,
 VDO_COMPONENT_DATA_SIZE = (sizeof(u32) +
       sizeof(struct packed_version_number) +
       VDO_COMPONENT_ENCODED_SIZE +
       VDO_LAYOUT_ENCODED_SIZE +
       RECOVERY_JOURNAL_COMPONENT_ENCODED_SIZE +
       SLAB_DEPOT_COMPONENT_ENCODED_SIZE +
       BLOCK_MAP_COMPONENT_ENCODED_SIZE),
};

/* The entirety of the component data encoded in the VDO super block. */
struct vdo_component_states {
 /* For backwards compatibility */
 u32 unused;

 /* The VDO volume version */
 struct version_number volume_version;

 /* Components */
 struct vdo_component vdo;
 struct block_map_state_2_0 block_map;
 struct recovery_journal_state_7_0 recovery_journal;
 struct slab_depot_state_2_0 slab_depot;

 /* Our partitioning of the underlying storage */
 struct layout layout;
};

/**
 * vdo_are_same_version() - Check whether two version numbers are the same.
 * @version_a: The first version.
 * @version_b: The second version.
 *
 * Return: true if the two versions are the same.
 */

static inline bool vdo_are_same_version(struct version_number version_a,
     struct version_number version_b)
{
 return ((version_a.major_version == version_b.major_version) &&
  (version_a.minor_version == version_b.minor_version));
}

/**
 * vdo_is_upgradable_version() - Check whether an actual version is upgradable to an expected
 *                               version.
 * @expected_version: The expected version.
 * @actual_version: The version being validated.
 *
 * An actual version is upgradable if its major number is expected but its minor number differs,
 * and the expected version's minor number is greater than the actual version's minor number.
 *
 * Return: true if the actual version is upgradable.
 */

static inline bool vdo_is_upgradable_version(struct version_number expected_version,
          struct version_number actual_version)
{
 return ((expected_version.major_version == actual_version.major_version) &&
  (expected_version.minor_version > actual_version.minor_version));
}

int __must_check vdo_validate_header(const struct header *expected_header,
         const struct header *actual_header, bool exact_size,
         const char *component_name);

void vdo_encode_header(u8 *buffer, size_t *offset, const struct header *header);
void vdo_decode_header(u8 *buffer, size_t *offset, struct header *header);

/**
 * vdo_pack_version_number() - Convert a version_number to its packed on-disk representation.
 * @version: The version number to convert.
 *
 * Return: the platform-independent representation of the version
 */

static inline struct packed_version_number vdo_pack_version_number(struct version_number version)
{
 return (struct packed_version_number) {
  .major_version = __cpu_to_le32(version.major_version),
  .minor_version = __cpu_to_le32(version.minor_version),
 };
}

/**
 * vdo_unpack_version_number() - Convert a packed_version_number to its native in-memory
 *                               representation.
 * @version: The version number to convert.
 *
 * Return: The platform-independent representation of the version.
 */

static inline struct version_number vdo_unpack_version_number(struct packed_version_number version)
{
 return (struct version_number) {
  .major_version = __le32_to_cpu(version.major_version),
  .minor_version = __le32_to_cpu(version.minor_version),
 };
}

/**
 * vdo_pack_header() - Convert a component header to its packed on-disk representation.
 * @header: The header to convert.
 *
 * Return: the platform-independent representation of the header
 */

static inline struct packed_header vdo_pack_header(const struct header *header)
{
 return (struct packed_header) {
  .id = __cpu_to_le32(header->id),
  .version = vdo_pack_version_number(header->version),
  .size = __cpu_to_le64(header->size),
 };
}

/**
 * vdo_unpack_header() - Convert a packed_header to its native in-memory representation.
 * @header: The header to convert.
 *
 * Return: The platform-independent representation of the version.
 */

static inline struct header vdo_unpack_header(const struct packed_header *header)
{
 return (struct header) {
  .id = __le32_to_cpu(header->id),
  .version = vdo_unpack_version_number(header->version),
  .size = __le64_to_cpu(header->size),
 };
}

/**
 * vdo_get_index_region_start() - Get the start of the index region from a geometry.
 * @geometry: The geometry.
 *
 * Return: The start of the index region.
 */

static inline physical_block_number_t __must_check
vdo_get_index_region_start(struct volume_geometry geometry)
{
 return geometry.regions[VDO_INDEX_REGION].start_block;
}

/**
 * vdo_get_data_region_start() - Get the start of the data region from a geometry.
 * @geometry: The geometry.
 *
 * Return: The start of the data region.
 */

static inline physical_block_number_t __must_check
vdo_get_data_region_start(struct volume_geometry geometry)
{
 return geometry.regions[VDO_DATA_REGION].start_block;
}

/**
 * vdo_get_index_region_size() - Get the size of the index region from a geometry.
 * @geometry: The geometry.
 *
 * Return: The size of the index region.
 */

static inline physical_block_number_t __must_check
vdo_get_index_region_size(struct volume_geometry geometry)
{
 return vdo_get_data_region_start(geometry) -
  vdo_get_index_region_start(geometry);
}

int __must_check vdo_parse_geometry_block(unsigned char *block,
       struct volume_geometry *geometry);

static inline bool vdo_is_state_compressed(const enum block_mapping_state mapping_state)
{
 return (mapping_state > VDO_MAPPING_STATE_UNCOMPRESSED);
}

static inline struct block_map_entry
vdo_pack_block_map_entry(physical_block_number_t pbn, enum block_mapping_state mapping_state)
{
 return (struct block_map_entry) {
  .mapping_state = (mapping_state & 0x0F),
  .pbn_high_nibble = ((pbn >> 32) & 0x0F),
  .pbn_low_word = __cpu_to_le32(pbn & UINT_MAX),
 };
}

static inline struct data_location vdo_unpack_block_map_entry(const struct block_map_entry *entry)
{
 physical_block_number_t low32 = __le32_to_cpu(entry->pbn_low_word);
 physical_block_number_t high4 = entry->pbn_high_nibble;

 return (struct data_location) {
  .pbn = ((high4 << 32) | low32),
  .state = entry->mapping_state,
 };
}

static inline bool vdo_is_mapped_location(const struct data_location *location)
{
 return (location->state != VDO_MAPPING_STATE_UNMAPPED);
}

static inline bool vdo_is_valid_location(const struct data_location *location)
{
 if (location->pbn == VDO_ZERO_BLOCK)
  return !vdo_is_state_compressed(location->state);
 else
  return vdo_is_mapped_location(location);
}

static inline physical_block_number_t __must_check
vdo_get_block_map_page_pbn(const struct block_map_page *page)
{
 return __le64_to_cpu(page->header.pbn);
}

struct block_map_page *vdo_format_block_map_page(void *buffer, nonce_t nonce,
       physical_block_number_t pbn,
       bool initialized);

enum block_map_page_validity __must_check vdo_validate_block_map_page(struct block_map_page *page,
              nonce_t nonce,
              physical_block_number_t pbn);

static inline page_count_t vdo_compute_block_map_page_count(block_count_t entries)
{
 return DIV_ROUND_UP(entries, VDO_BLOCK_MAP_ENTRIES_PER_PAGE);
}

block_count_t __must_check vdo_compute_new_forest_pages(root_count_t root_count,
       struct boundary *old_sizes,
       block_count_t entries,
       struct boundary *new_sizes);

/**
 * vdo_pack_recovery_journal_entry() - Return the packed, on-disk representation of a recovery
 *                                     journal entry.
 * @entry: The journal entry to pack.
 *
 * Return: The packed representation of the journal entry.
 */

static inline struct packed_recovery_journal_entry
vdo_pack_recovery_journal_entry(const struct recovery_journal_entry *entry)
{
 return (struct packed_recovery_journal_entry) {
  .operation = entry->operation,
  .slot_low = entry->slot.slot & 0x3F,
  .slot_high = (entry->slot.slot >> 6) & 0x0F,
  .pbn_high_nibble = (entry->slot.pbn >> 32) & 0x0F,
  .pbn_low_word = __cpu_to_le32(entry->slot.pbn & UINT_MAX),
  .mapping = vdo_pack_block_map_entry(entry->mapping.pbn,
          entry->mapping.state),
  .unmapping = vdo_pack_block_map_entry(entry->unmapping.pbn,
            entry->unmapping.state),
 };
}

/**
 * vdo_unpack_recovery_journal_entry() - Unpack the on-disk representation of a recovery journal
 *                                       entry.
 * @entry: The recovery journal entry to unpack.
 *
 * Return: The unpacked entry.
 */

static inline struct recovery_journal_entry
vdo_unpack_recovery_journal_entry(const struct packed_recovery_journal_entry *entry)
{
 physical_block_number_t low32 = __le32_to_cpu(entry->pbn_low_word);
 physical_block_number_t high4 = entry->pbn_high_nibble;

 return (struct recovery_journal_entry) {
  .operation = entry->operation,
  .slot = {
   .pbn = ((high4 << 32) | low32),
   .slot = (entry->slot_low | (entry->slot_high << 6)),
  },
  .mapping = vdo_unpack_block_map_entry(&entry->mapping),
  .unmapping = vdo_unpack_block_map_entry(&entry->unmapping),
 };
}

const char * __must_check vdo_get_journal_operation_name(enum journal_operation operation);

/**
 * vdo_is_valid_recovery_journal_sector() - Determine whether the header of the given sector could
 *                                          describe a valid sector for the given journal block
 *                                          header.
 * @header: The unpacked block header to compare against.
 * @sector: The packed sector to check.
 * @sector_number: The number of the sector being checked.
 *
 * Return: true if the sector matches the block header.
 */

static inline bool __must_check
vdo_is_valid_recovery_journal_sector(const struct recovery_block_header *header,
         const struct packed_journal_sector *sector,
         u8 sector_number)
{
 if ((header->check_byte != sector->check_byte) ||
     (header->recovery_count != sector->recovery_count))
  return false;

 if (header->metadata_type == VDO_METADATA_RECOVERY_JOURNAL_2)
  return sector->entry_count <= RECOVERY_JOURNAL_ENTRIES_PER_SECTOR;

 if (sector_number == 7)
  return sector->entry_count <= RECOVERY_JOURNAL_1_ENTRIES_IN_LAST_SECTOR;

 return sector->entry_count <= RECOVERY_JOURNAL_1_ENTRIES_PER_SECTOR;
}

/**
 * vdo_compute_recovery_journal_block_number() - Compute the physical block number of the recovery
 *                                               journal block which would have a given sequence
 *                                               number.
 * @journal_size: The size of the journal.
 * @sequence_number: The sequence number.
 *
 * Return: The pbn of the journal block which would the specified sequence number.
 */

static inline physical_block_number_t __must_check
vdo_compute_recovery_journal_block_number(block_count_t journal_size,
       sequence_number_t sequence_number)
{
 /*
 * Since journal size is a power of two, the block number modulus can just be extracted
 * from the low-order bits of the sequence.
 */

 return (sequence_number & (journal_size - 1));
}

/**
 * vdo_get_journal_block_sector() - Find the recovery journal sector from the block header and
 *                                  sector number.
 * @header: The header of the recovery journal block.
 * @sector_number: The index of the sector (1-based).
 *
 * Return: A packed recovery journal sector.
 */

static inline struct packed_journal_sector * __must_check
vdo_get_journal_block_sector(struct packed_journal_header *header, int sector_number)
{
 char *sector_data = ((char *) header) + (VDO_SECTOR_SIZE * sector_number);

 return (struct packed_journal_sector *) sector_data;
}

/**
 * vdo_pack_recovery_block_header() - Generate the packed representation of a recovery block
 *                                    header.
 * @header: The header containing the values to encode.
 * @packed: The header into which to pack the values.
 */

static inline void vdo_pack_recovery_block_header(const struct recovery_block_header *header,
        struct packed_journal_header *packed)
{
 *packed = (struct packed_journal_header) {
  .block_map_head = __cpu_to_le64(header->block_map_head),
  .slab_journal_head = __cpu_to_le64(header->slab_journal_head),
  .sequence_number = __cpu_to_le64(header->sequence_number),
  .nonce = __cpu_to_le64(header->nonce),
  .logical_blocks_used = __cpu_to_le64(header->logical_blocks_used),
  .block_map_data_blocks = __cpu_to_le64(header->block_map_data_blocks),
  .entry_count = __cpu_to_le16(header->entry_count),
  .check_byte = header->check_byte,
  .recovery_count = header->recovery_count,
  .metadata_type = header->metadata_type,
 };
}

/**
 * vdo_unpack_recovery_block_header() - Decode the packed representation of a recovery block
 *                                      header.
 * @packed: The packed header to decode.
 *
 * Return: The unpacked header.
 */

static inline struct recovery_block_header
vdo_unpack_recovery_block_header(const struct packed_journal_header *packed)
{
 return (struct recovery_block_header) {
  .block_map_head = __le64_to_cpu(packed->block_map_head),
  .slab_journal_head = __le64_to_cpu(packed->slab_journal_head),
  .sequence_number = __le64_to_cpu(packed->sequence_number),
  .nonce = __le64_to_cpu(packed->nonce),
  .logical_blocks_used = __le64_to_cpu(packed->logical_blocks_used),
  .block_map_data_blocks = __le64_to_cpu(packed->block_map_data_blocks),
  .entry_count = __le16_to_cpu(packed->entry_count),
  .check_byte = packed->check_byte,
  .recovery_count = packed->recovery_count,
  .metadata_type = packed->metadata_type,
 };
}

/**
 * vdo_compute_slab_count() - Compute the number of slabs a depot with given parameters would have.
 * @first_block: PBN of the first data block.
 * @last_block: PBN of the last data block.
 * @slab_size_shift: Exponent for the number of blocks per slab.
 *
 * Return: The number of slabs.
 */

static inline slab_count_t vdo_compute_slab_count(physical_block_number_t first_block,
        physical_block_number_t last_block,
        unsigned int slab_size_shift)
{
 return (slab_count_t) ((last_block - first_block) >> slab_size_shift);
}

int __must_check vdo_configure_slab_depot(const struct partition *partition,
       struct slab_config slab_config,
       zone_count_t zone_count,
       struct slab_depot_state_2_0 *state);

int __must_check vdo_configure_slab(block_count_t slab_size,
        block_count_t slab_journal_blocks,
        struct slab_config *slab_config);

/**
 * vdo_get_saved_reference_count_size() - Get the number of blocks required to save a reference
 *                                        counts state covering the specified number of data
 *                                        blocks.
 * @block_count: The number of physical data blocks that can be referenced.
 *
 * Return: The number of blocks required to save reference counts with the given block count.
 */

static inline block_count_t vdo_get_saved_reference_count_size(block_count_t block_count)
{
 return DIV_ROUND_UP(block_count, COUNTS_PER_BLOCK);
}

/**
 * vdo_get_slab_journal_start_block() - Get the physical block number of the start of the slab
 *                                      journal relative to the start block allocator partition.
 * @slab_config: The slab configuration of the VDO.
 * @origin: The first block of the slab.
 */

static inline physical_block_number_t __must_check
vdo_get_slab_journal_start_block(const struct slab_config *slab_config,
     physical_block_number_t origin)
{
 return origin + slab_config->data_blocks + slab_config->reference_count_blocks;
}

/**
 * vdo_advance_journal_point() - Move the given journal point forward by one entry.
 * @point: The journal point to adjust.
 * @entries_per_block: The number of entries in one full block.
 */

static inline void vdo_advance_journal_point(struct journal_point *point,
          journal_entry_count_t entries_per_block)
{
 point->entry_count++;
 if (point->entry_count == entries_per_block) {
  point->sequence_number++;
  point->entry_count = 0;
 }
}

/**
 * vdo_before_journal_point() - Check whether the first point precedes the second point.
 * @first: The first journal point.
 * @second: The second journal point.
 *
 * Return: true if the first point precedes the second point.
 */

static inline bool vdo_before_journal_point(const struct journal_point *first,
         const struct journal_point *second)
{
 return ((first->sequence_number < second->sequence_number) ||
  ((first->sequence_number == second->sequence_number) &&
   (first->entry_count < second->entry_count)));
}

/**
 * vdo_pack_journal_point() - Encode the journal location represented by a
 *                            journal_point into a packed_journal_point.
 * @unpacked: The unpacked input point.
 * @packed: The packed output point.
 */

static inline void vdo_pack_journal_point(const struct journal_point *unpacked,
       struct packed_journal_point *packed)
{
 packed->encoded_point =
  __cpu_to_le64((unpacked->sequence_number << 16) | unpacked->entry_count);
}

/**
 * vdo_unpack_journal_point() - Decode the journal location represented by a packed_journal_point
 *                              into a journal_point.
 * @packed: The packed input point.
 * @unpacked: The unpacked output point.
 */

static inline void vdo_unpack_journal_point(const struct packed_journal_point *packed,
         struct journal_point *unpacked)
{
 u64 native = __le64_to_cpu(packed->encoded_point);

 unpacked->sequence_number = (native >> 16);
 unpacked->entry_count = (native & 0xffff);
}

/**
 * vdo_pack_slab_journal_block_header() - Generate the packed representation of a slab block
 *                                        header.
 * @header: The header containing the values to encode.
 * @packed: The header into which to pack the values.
 */

static inline void
vdo_pack_slab_journal_block_header(const struct slab_journal_block_header *header,
       struct packed_slab_journal_block_header *packed)
{
 packed->head = __cpu_to_le64(header->head);
 packed->sequence_number = __cpu_to_le64(header->sequence_number);
 packed->nonce = __cpu_to_le64(header->nonce);
 packed->entry_count = __cpu_to_le16(header->entry_count);
 packed->metadata_type = header->metadata_type;
 packed->has_block_map_increments = header->has_block_map_increments;

 vdo_pack_journal_point(&header->recovery_point, &packed->recovery_point);
}

/**
 * vdo_unpack_slab_journal_block_header() - Decode the packed representation of a slab block
 *                                          header.
 * @packed: The packed header to decode.
 * @header: The header into which to unpack the values.
 */

static inline void
vdo_unpack_slab_journal_block_header(const struct packed_slab_journal_block_header *packed,
         struct slab_journal_block_header *header)
{
 *header = (struct slab_journal_block_header) {
  .head = __le64_to_cpu(packed->head),
  .sequence_number = __le64_to_cpu(packed->sequence_number),
  .nonce = __le64_to_cpu(packed->nonce),
  .entry_count = __le16_to_cpu(packed->entry_count),
  .metadata_type = packed->metadata_type,
  .has_block_map_increments = packed->has_block_map_increments,
 };
 vdo_unpack_journal_point(&packed->recovery_point, &header->recovery_point);
}

/**
 * vdo_pack_slab_journal_entry() - Generate the packed encoding of a slab journal entry.
 * @packed: The entry into which to pack the values.
 * @sbn: The slab block number of the entry to encode.
 * @is_increment: The increment flag.
 */

static inline void vdo_pack_slab_journal_entry(packed_slab_journal_entry *packed,
            slab_block_number sbn, bool is_increment)
{
 packed->offset_low8 = (sbn & 0x0000FF);
 packed->offset_mid8 = (sbn & 0x00FF00) >> 8;
 packed->offset_high7 = (sbn & 0x7F0000) >> 16;
 packed->increment = is_increment ? 1 : 0;
}

/**
 * vdo_unpack_slab_journal_entry() - Decode the packed representation of a slab journal entry.
 * @packed: The packed entry to decode.
 *
 * Return: The decoded slab journal entry.
 */

static inline struct slab_journal_entry __must_check
vdo_unpack_slab_journal_entry(const packed_slab_journal_entry *packed)
{
 struct slab_journal_entry entry;

 entry.sbn = packed->offset_high7;
 entry.sbn <<= 8;
 entry.sbn |= packed->offset_mid8;
 entry.sbn <<= 8;
 entry.sbn |= packed->offset_low8;
 entry.operation = VDO_JOURNAL_DATA_REMAPPING;
 entry.increment = packed->increment;
 return entry;
}

struct slab_journal_entry __must_check
vdo_decode_slab_journal_entry(struct packed_slab_journal_block *block,
         journal_entry_count_t entry_count);

/**
 * vdo_get_slab_summary_hint_shift() - Compute the shift for slab summary hints.
 * @slab_size_shift: Exponent for the number of blocks per slab.
 *
 * Return: The hint shift.
 */

static inline u8 __must_check vdo_get_slab_summary_hint_shift(unsigned int slab_size_shift)
{
 return ((slab_size_shift > VDO_SLAB_SUMMARY_FULLNESS_HINT_BITS) ?
  (slab_size_shift - VDO_SLAB_SUMMARY_FULLNESS_HINT_BITS) :
  0);
}

int __must_check vdo_initialize_layout(block_count_t size,
           physical_block_number_t offset,
           block_count_t block_map_blocks,
           block_count_t journal_blocks,
           block_count_t summary_blocks,
           struct layout *layout);

void vdo_uninitialize_layout(struct layout *layout);

int __must_check vdo_get_partition(struct layout *layout, enum partition_id id,
       struct partition **partition_ptr);

struct partition * __must_check vdo_get_known_partition(struct layout *layout,
       enum partition_id id);

int vdo_validate_config(const struct vdo_config *config,
   block_count_t physical_block_count,
   block_count_t logical_block_count);

void vdo_destroy_component_states(struct vdo_component_states *states);

int __must_check vdo_decode_component_states(u8 *buffer,
          struct volume_geometry *geometry,
          struct vdo_component_states *states);

int __must_check vdo_validate_component_states(struct vdo_component_states *states,
            nonce_t geometry_nonce,
            block_count_t physical_size,
            block_count_t logical_size);

void vdo_encode_super_block(u8 *buffer, struct vdo_component_states *states);
int __must_check vdo_decode_super_block(u8 *buffer);

/* We start with 0L and postcondition with ~0L to match our historical usage in userspace. */
static inline u32 vdo_crc32(const void *buf, unsigned long len)
{
 return (crc32(0L, buf, len) ^ ~0L);
}

#endif /* VDO_ENCODINGS_H */

Messung V0.5
C=92 H=99 G=95

¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.