// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2023 Red Hat */ #include "encodings.h" #include <linux/log2.h> #include "logger.h" #include "memory-alloc.h" #include "permassert.h" #include "constants.h" #include "status-codes.h" #include "types.h" /** The maximum logical space is 4 petabytes, which is 1 terablock. */ static const block_count_t MAXIMUM_VDO_LOGICAL_BLOCKS = …; /** The maximum physical space is 256 terabytes, which is 64 gigablocks. */ static const block_count_t MAXIMUM_VDO_PHYSICAL_BLOCKS = …; struct geometry_block { … } __packed; static const struct header GEOMETRY_BLOCK_HEADER_5_0 = …; static const struct header GEOMETRY_BLOCK_HEADER_4_0 = …; const u8 VDO_GEOMETRY_MAGIC_NUMBER[VDO_GEOMETRY_MAGIC_NUMBER_SIZE + 1] = …; #define PAGE_HEADER_4_1_SIZE … static const struct version_number BLOCK_MAP_4_1 = …; const struct header VDO_BLOCK_MAP_HEADER_2_0 = …; const struct header VDO_RECOVERY_JOURNAL_HEADER_7_0 = …; const struct header VDO_SLAB_DEPOT_HEADER_2_0 = …; static const struct header VDO_LAYOUT_HEADER_3_0 = …; static const enum partition_id REQUIRED_PARTITIONS[] = …; /* * The current version for the data encoded in the super block. This must be changed any time there * is a change to encoding of the component data of any VDO component. */ static const struct version_number VDO_COMPONENT_DATA_41_0 = …; const struct version_number VDO_VOLUME_VERSION_67_0 = …; static const struct header SUPER_BLOCK_HEADER_12_0 = …; /** * validate_version() - Check whether a version matches an expected version. * @expected_version: The expected version. * @actual_version: The version being validated. * @component_name: The name of the component or the calling function (for error logging). * * Logs an error describing a mismatch. * * Return: VDO_SUCCESS if the versions are the same, * VDO_UNSUPPORTED_VERSION if the versions don't match. */ static int __must_check validate_version(struct version_number expected_version, struct version_number actual_version, const char *component_name) { … } /** * vdo_validate_header() - Check whether a header matches expectations. * @expected_header: The expected header. * @actual_header: The header being validated. * @exact_size: If true, the size fields of the two headers must be the same, otherwise it is * required that actual_header.size >= expected_header.size. * @name: The name of the component or the calling function (for error logging). * * Logs an error describing the first mismatch found. * * Return: VDO_SUCCESS if the header meets expectations, * VDO_INCORRECT_COMPONENT if the component ids don't match, * VDO_UNSUPPORTED_VERSION if the versions or sizes don't match. */ int vdo_validate_header(const struct header *expected_header, const struct header *actual_header, bool exact_size, const char *name) { … } static void encode_version_number(u8 *buffer, size_t *offset, struct version_number version) { … } void vdo_encode_header(u8 *buffer, size_t *offset, const struct header *header) { … } static void decode_version_number(u8 *buffer, size_t *offset, struct version_number *version) { … } void vdo_decode_header(u8 *buffer, size_t *offset, struct header *header) { … } /** * decode_volume_geometry() - Decode the on-disk representation of a volume geometry from a buffer. * @buffer: A buffer to decode from. * @offset: The offset in the buffer at which to decode. * @geometry: The structure to receive the decoded fields. * @version: The geometry block version to decode. */ static void decode_volume_geometry(u8 *buffer, size_t *offset, struct volume_geometry *geometry, u32 version) { … } /** * vdo_parse_geometry_block() - Decode and validate an encoded geometry block. * @block: The encoded geometry block. * @geometry: The structure to receive the decoded fields. */ int __must_check vdo_parse_geometry_block(u8 *block, struct volume_geometry *geometry) { … } 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 vdo_validate_block_map_page(struct block_map_page *page, nonce_t nonce, physical_block_number_t pbn) { … } static int decode_block_map_state_2_0(u8 *buffer, size_t *offset, struct block_map_state_2_0 *state) { … } static void encode_block_map_state_2_0(u8 *buffer, size_t *offset, struct block_map_state_2_0 state) { … } /** * vdo_compute_new_forest_pages() - Compute the number of pages which must be allocated at each * level in order to grow the forest to a new number of entries. * @entries: The new number of entries the block map must address. * * Return: The total number of non-leaf pages required. */ block_count_t vdo_compute_new_forest_pages(root_count_t root_count, struct boundary *old_sizes, block_count_t entries, struct boundary *new_sizes) { … } /** * encode_recovery_journal_state_7_0() - Encode the state of a recovery journal. * * Return: VDO_SUCCESS or an error code. */ static void encode_recovery_journal_state_7_0(u8 *buffer, size_t *offset, struct recovery_journal_state_7_0 state) { … } /** * decode_recovery_journal_state_7_0() - Decode the state of a recovery journal saved in a buffer. * @buffer: The buffer containing the saved state. * @state: A pointer to a recovery journal state to hold the result of a successful decode. * * Return: VDO_SUCCESS or an error code. */ static int __must_check decode_recovery_journal_state_7_0(u8 *buffer, size_t *offset, struct recovery_journal_state_7_0 *state) { … } /** * vdo_get_journal_operation_name() - Get the name of a journal operation. * @operation: The operation to name. * * Return: The name of the operation. */ const char *vdo_get_journal_operation_name(enum journal_operation operation) { … } /** * encode_slab_depot_state_2_0() - Encode the state of a slab depot into a buffer. */ static void encode_slab_depot_state_2_0(u8 *buffer, size_t *offset, struct slab_depot_state_2_0 state) { … } /** * decode_slab_depot_state_2_0() - Decode slab depot component state version 2.0 from a buffer. * * Return: VDO_SUCCESS or an error code. */ static int decode_slab_depot_state_2_0(u8 *buffer, size_t *offset, struct slab_depot_state_2_0 *state) { … } /** * vdo_configure_slab_depot() - Configure the slab depot. * @partition: The slab depot partition * @slab_config: The configuration of a single slab. * @zone_count: The number of zones the depot will use. * @state: The state structure to be configured. * * Configures the slab_depot for the specified storage capacity, finding the number of data blocks * that will fit and still leave room for the depot metadata, then return the saved state for that * configuration. * * Return: VDO_SUCCESS or an error code. */ int 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) { … } /** * vdo_configure_slab() - Measure and initialize the configuration to use for each slab. * @slab_size: The number of blocks per slab. * @slab_journal_blocks: The number of blocks for the slab journal. * @slab_config: The slab configuration to initialize. * * Return: VDO_SUCCESS or an error code. */ int vdo_configure_slab(block_count_t slab_size, block_count_t slab_journal_blocks, struct slab_config *slab_config) { … } /** * vdo_decode_slab_journal_entry() - Decode a slab journal entry. * @block: The journal block holding the entry. * @entry_count: The number of the entry. * * Return: The decoded entry. */ struct slab_journal_entry vdo_decode_slab_journal_entry(struct packed_slab_journal_block *block, journal_entry_count_t entry_count) { … } /** * allocate_partition() - Allocate a partition and add it to a layout. * @layout: The layout containing the partition. * @id: The id of the partition. * @offset: The offset into the layout at which the partition begins. * @size: The size of the partition in blocks. * * Return: VDO_SUCCESS or an error. */ static int allocate_partition(struct layout *layout, u8 id, physical_block_number_t offset, block_count_t size) { … } /** * make_partition() - Create a new partition from the beginning or end of the unused space in a * layout. * @layout: The layout. * @id: The id of the partition to make. * @size: The number of blocks to carve out; if 0, all remaining space will be used. * @beginning: True if the partition should start at the beginning of the unused space. * * Return: A success or error code, particularly VDO_NO_SPACE if there are fewer than size blocks * remaining. */ static int __must_check make_partition(struct layout *layout, enum partition_id id, block_count_t size, bool beginning) { … } /** * vdo_initialize_layout() - Lay out the partitions of a vdo. * @size: The entire size of the vdo. * @origin: The start of the layout on the underlying storage in blocks. * @block_map_blocks: The size of the block map partition. * @journal_blocks: The size of the journal partition. * @summary_blocks: The size of the slab summary partition. * @layout: The layout to initialize. * * Return: VDO_SUCCESS or an error. */ int 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) { … } /** * vdo_uninitialize_layout() - Clean up a layout. * @layout: The layout to clean up. * * All partitions created by this layout become invalid pointers. */ void vdo_uninitialize_layout(struct layout *layout) { … } /** * vdo_get_partition() - Get a partition by id. * @layout: The layout from which to get a partition. * @id: The id of the partition. * @partition_ptr: A pointer to hold the partition. * * Return: VDO_SUCCESS or an error. */ int vdo_get_partition(struct layout *layout, enum partition_id id, struct partition **partition_ptr) { … } /** * vdo_get_known_partition() - Get a partition by id from a validated layout. * @layout: The layout from which to get a partition. * @id: The id of the partition. * * Return: the partition */ struct partition *vdo_get_known_partition(struct layout *layout, enum partition_id id) { … } static void encode_layout(u8 *buffer, size_t *offset, const struct layout *layout) { … } static int decode_layout(u8 *buffer, size_t *offset, physical_block_number_t start, block_count_t size, struct layout *layout) { … } /** * pack_vdo_config() - Convert a vdo_config to its packed on-disk representation. * @config: The vdo config to convert. * * Return: The platform-independent representation of the config. */ static struct packed_vdo_config pack_vdo_config(struct vdo_config config) { … } /** * pack_vdo_component() - Convert a vdo_component to its packed on-disk representation. * @component: The VDO component data to convert. * * Return: The platform-independent representation of the component. */ static struct packed_vdo_component_41_0 pack_vdo_component(const struct vdo_component component) { … } static void encode_vdo_component(u8 *buffer, size_t *offset, struct vdo_component component) { … } /** * unpack_vdo_config() - Convert a packed_vdo_config to its native in-memory representation. * @config: The packed vdo config to convert. * * Return: The native in-memory representation of the vdo config. */ static struct vdo_config unpack_vdo_config(struct packed_vdo_config config) { … } /** * unpack_vdo_component_41_0() - Convert a packed_vdo_component_41_0 to its native in-memory * representation. * @component: The packed vdo component data to convert. * * Return: The native in-memory representation of the component. */ static struct vdo_component unpack_vdo_component_41_0(struct packed_vdo_component_41_0 component) { … } /** * decode_vdo_component() - Decode the component data for the vdo itself out of the super block. * * Return: VDO_SUCCESS or an error. */ static int decode_vdo_component(u8 *buffer, size_t *offset, struct vdo_component *component) { … } /** * vdo_validate_config() - Validate constraints on a VDO config. * @config: The VDO config. * @physical_block_count: The minimum block count of the underlying storage. * @logical_block_count: The expected logical size of the VDO, or 0 if the logical size may be * unspecified. * * Return: A success or error code. */ int vdo_validate_config(const struct vdo_config *config, block_count_t physical_block_count, block_count_t logical_block_count) { … } /** * vdo_destroy_component_states() - Clean up any allocations in a vdo_component_states. * @states: The component states to destroy. */ void vdo_destroy_component_states(struct vdo_component_states *states) { … } /** * decode_components() - Decode the components now that we know the component data is a version we * understand. * @buffer: The buffer being decoded. * @offset: The offset to start decoding from. * @geometry: The vdo geometry * @states: An object to hold the successfully decoded state. * * Return: VDO_SUCCESS or an error. */ static int __must_check decode_components(u8 *buffer, size_t *offset, struct volume_geometry *geometry, struct vdo_component_states *states) { … } /** * vdo_decode_component_states() - Decode the payload of a super block. * @buffer: The buffer containing the encoded super block contents. * @geometry: The vdo geometry * @states: A pointer to hold the decoded states. * * Return: VDO_SUCCESS or an error. */ int vdo_decode_component_states(u8 *buffer, struct volume_geometry *geometry, struct vdo_component_states *states) { … } /** * vdo_validate_component_states() - Validate the decoded super block configuration. * @states: The state decoded from the super block. * @geometry_nonce: The nonce from the geometry block. * @physical_size: The minimum block count of the underlying storage. * @logical_size: The expected logical size of the VDO, or 0 if the logical size may be * unspecified. * * Return: VDO_SUCCESS or an error if the configuration is invalid. */ int vdo_validate_component_states(struct vdo_component_states *states, nonce_t geometry_nonce, block_count_t physical_size, block_count_t logical_size) { … } /** * vdo_encode_component_states() - Encode the state of all vdo components in the super block. */ static void vdo_encode_component_states(u8 *buffer, size_t *offset, const struct vdo_component_states *states) { … } /** * vdo_encode_super_block() - Encode a super block into its on-disk representation. */ void vdo_encode_super_block(u8 *buffer, struct vdo_component_states *states) { … } /** * vdo_decode_super_block() - Decode a super block from its on-disk representation. */ int vdo_decode_super_block(u8 *buffer) { … }