linux/drivers/md/dm-vdo/block-map.h

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

#ifndef VDO_BLOCK_MAP_H
#define VDO_BLOCK_MAP_H

#include <linux/list.h>

#include "numeric.h"

#include "admin-state.h"
#include "completion.h"
#include "encodings.h"
#include "int-map.h"
#include "statistics.h"
#include "types.h"
#include "vio.h"
#include "wait-queue.h"

/*
 * The block map is responsible for tracking all the logical to physical mappings of a VDO. It
 * consists of a collection of 60 radix trees gradually allocated as logical addresses are used.
 * Each tree is assigned to a logical zone such that it is easy to compute which zone must handle
 * each logical address. Each logical zone also has a dedicated portion of the leaf page cache.
 *
 * Each logical zone has a single dedicated queue and thread for performing all updates to the
 * radix trees assigned to that zone. The concurrency guarantees of this single-threaded model
 * allow the code to omit more fine-grained locking for the block map structures.
 *
 * Load operations must be performed on the admin thread. Normal operations, such as reading and
 * updating mappings, must be performed on the appropriate logical zone thread. Save operations
 * must be launched from the same admin thread as the original load operation.
 */

enum {};

/*
 * Generation counter for page references.
 */
vdo_page_generation;

extern const struct block_map_entry UNMAPPED_BLOCK_MAP_ENTRY;

/* The VDO Page Cache abstraction. */
struct vdo_page_cache {};

/*
 * The state of a page buffer. If the page buffer is free no particular page is bound to it,
 * otherwise the page buffer is bound to particular page whose absolute pbn is in the pbn field. If
 * the page is resident or dirty the page data is stable and may be accessed. Otherwise the page is
 * in flight (incoming or outgoing) and its data should not be accessed.
 *
 * @note Update the static data in get_page_state_name() if you change this enumeration.
 */
enum vdo_page_buffer_state {} __packed;

/*
 * The write status of page
 */
enum vdo_page_write_status {} __packed;

/* Per-page-slot information. */
struct page_info {};

/*
 * A completion awaiting a specific page. Also a live reference into the page once completed, until
 * freed.
 */
struct vdo_page_completion {};

struct forest;

struct tree_page {};

enum block_map_page_type {};

dirty_era_t;

struct dirty_lists {};

struct block_map_zone {};

struct block_map {};

/**
 * typedef vdo_entry_callback_fn - A function to be called for each allocated PBN when traversing
 *                                 the forest.
 * @pbn: A PBN of a tree node.
 * @completion: The parent completion of the traversal.
 *
 * Return: VDO_SUCCESS or an error.
 */
vdo_entry_callback_fn;

static inline struct vdo_page_completion *as_vdo_page_completion(struct vdo_completion *completion)
{}

void vdo_release_page_completion(struct vdo_completion *completion);

void vdo_get_page(struct vdo_page_completion *page_completion,
		  struct block_map_zone *zone, physical_block_number_t pbn,
		  bool writable, void *parent, vdo_action_fn callback,
		  vdo_action_fn error_handler, bool requeue);

void vdo_request_page_write(struct vdo_completion *completion);

int __must_check vdo_get_cached_page(struct vdo_completion *completion,
				     struct block_map_page **page_ptr);

int __must_check vdo_invalidate_page_cache(struct vdo_page_cache *cache);

static inline struct block_map_page * __must_check
vdo_as_block_map_page(struct tree_page *tree_page)
{}

bool vdo_copy_valid_page(char *buffer, nonce_t nonce,
			 physical_block_number_t pbn,
			 struct block_map_page *page);

void vdo_find_block_map_slot(struct data_vio *data_vio);

physical_block_number_t vdo_find_block_map_page_pbn(struct block_map *map,
						    page_number_t page_number);

void vdo_write_tree_page(struct tree_page *page, struct block_map_zone *zone);

void vdo_traverse_forest(struct block_map *map, vdo_entry_callback_fn callback,
			 struct vdo_completion *completion);

int __must_check vdo_decode_block_map(struct block_map_state_2_0 state,
				      block_count_t logical_blocks, struct vdo *vdo,
				      struct recovery_journal *journal, nonce_t nonce,
				      page_count_t cache_size, block_count_t maximum_age,
				      struct block_map **map_ptr);

void vdo_drain_block_map(struct block_map *map, const struct admin_state_code *operation,
			 struct vdo_completion *parent);

void vdo_resume_block_map(struct block_map *map, struct vdo_completion *parent);

int __must_check vdo_prepare_to_grow_block_map(struct block_map *map,
					       block_count_t new_logical_blocks);

void vdo_grow_block_map(struct block_map *map, struct vdo_completion *parent);

void vdo_abandon_block_map_growth(struct block_map *map);

void vdo_free_block_map(struct block_map *map);

struct block_map_state_2_0 __must_check vdo_record_block_map(const struct block_map *map);

void vdo_initialize_block_map_from_journal(struct block_map *map,
					   struct recovery_journal *journal);

zone_count_t vdo_compute_logical_zone(struct data_vio *data_vio);

void vdo_advance_block_map_era(struct block_map *map,
			       sequence_number_t recovery_block_number);

void vdo_update_block_map_page(struct block_map_page *page, struct data_vio *data_vio,
			       physical_block_number_t pbn,
			       enum block_mapping_state mapping_state,
			       sequence_number_t *recovery_lock);

void vdo_get_mapped_block(struct data_vio *data_vio);

void vdo_put_mapped_block(struct data_vio *data_vio);

struct block_map_statistics __must_check vdo_get_block_map_statistics(struct block_map *map);

/**
 * vdo_convert_maximum_age() - Convert the maximum age to reflect the new recovery journal format
 * @age: The configured maximum age
 *
 * Return: The converted age
 *
 * In the old recovery journal format, each journal block held 311 entries, and every write bio
 * made two entries. The old maximum age was half the usable journal length. In the new format,
 * each block holds only 217 entries, but each bio only makes one entry. We convert the configured
 * age so that the number of writes in a block map era is the same in the old and new formats. This
 * keeps the bound on the amount of work required to recover the block map from the recovery
 * journal the same across the format change. It also keeps the amortization of block map page
 * writes to write bios the same.
 */
static inline block_count_t vdo_convert_maximum_age(block_count_t age)
{}

#endif /* VDO_BLOCK_MAP_H */