/* 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;