/* 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 { … }; /* * A packed, machine-independent, on-disk representation of a version_number. Both fields are * stored in little-endian byte order. */ struct packed_version_number { … } __packed; /* The registry of component ids for use in headers */ #define VDO_SUPER_BLOCK … #define VDO_LAYOUT … #define VDO_RECOVERY_JOURNAL … #define VDO_SLAB_DEPOT … #define VDO_BLOCK_MAP … #define VDO_GEOMETRY_BLOCK … /* The header for versioned data stored on disk. */ struct header { … }; /* A packed, machine-independent, on-disk representation of a component header. */ struct packed_header { … } __packed; enum { … }; struct index_config { … } __packed; enum volume_region_id { … }; struct volume_region { … } __packed; struct volume_geometry { … } __packed; /* This volume geometry struct is used for sizing only */ struct volume_geometry_4_0 { … } __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 { … } __packed; struct block_map_page_header { … } __packed; struct block_map_page { … } __packed; enum block_map_page_validity { … }; struct block_map_state_2_0 { … } __packed; struct boundary { … }; 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 { … } __packed; extern const struct header VDO_RECOVERY_JOURNAL_HEADER_7_0; 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 { … }; /* The packed, on-disk representation of a recovery journal entry. */ struct packed_recovery_journal_entry { … } __packed; /* The packed, on-disk representation of an old format recovery journal entry. */ struct packed_recovery_journal_entry_1 { … } __packed; enum journal_operation_1 { … } __packed; struct recovery_block_header { … }; /* * The packed, on-disk representation of a recovery journal block header. All fields are kept in * little-endian byte order. */ struct packed_journal_header { … } __packed; struct packed_journal_sector { … } __packed; enum { … }; /* A type representing a reference count of a block. */ vdo_refcount_t; /* The absolute position of an entry in a recovery journal or slab journal. */ struct journal_point { … }; /* A packed, platform-independent encoding of a struct journal_point. */ struct packed_journal_point { … } __packed; /* Special vdo_refcount_t values. */ #define EMPTY_REFERENCE_COUNT … enum { … }; enum { … }; /* The format of each sector of a reference_block on disk. */ struct packed_reference_sector { … } __packed; struct packed_reference_block { … }; struct slab_depot_state_2_0 { … } __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 { … }; /* A single slab journal entry in its on-disk form */ packed_slab_journal_entry; /* The unpacked representation of the header of a slab journal block */ struct slab_journal_block_header { … }; /* * 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 { … } __packed; enum { … }; /* The payload of a slab journal block which has block map increments */ struct full_slab_journal_entries { … } __packed; slab_journal_payload; struct packed_slab_journal_block { … } __packed; /* The offset of a slab journal tail block. */ tail_block_offset_t; struct slab_summary_entry { … } __packed; enum { … }; struct layout { … }; struct partition { … }; struct layout_3_0 { … } __packed; struct partition_3_0 { … } __packed; /* * The configuration of the VDO service. */ struct vdo_config { … }; /* This is the structure that captures the vdo fields saved as a super block component. */ struct vdo_component { … }; /* * A packed, machine-independent, on-disk representation of the vdo_config in the VDO component * data in the super block. */ struct packed_vdo_config { … } __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 { … } __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 { … }; /* The entirety of the component data encoded in the VDO super block. */ struct vdo_component_states { … }; /** * 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) { … } /** * 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) { … } 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } 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) { … } static inline struct block_map_entry vdo_pack_block_map_entry(physical_block_number_t pbn, enum block_mapping_state mapping_state) { … } static inline struct data_location vdo_unpack_block_map_entry(const struct block_map_entry *entry) { … } static inline bool vdo_is_mapped_location(const struct data_location *location) { … } static inline bool vdo_is_valid_location(const struct data_location *location) { … } static inline physical_block_number_t __must_check vdo_get_block_map_page_pbn(const struct block_map_page *page) { … } 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) { … } 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) { … } /** * 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) { … } 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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) { … } /** * 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 __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) { … } 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) { … } #endif /* VDO_ENCODINGS_H */