linux/drivers/md/dm-vdo/slab-depot.h

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

#ifndef VDO_SLAB_DEPOT_H
#define VDO_SLAB_DEPOT_H

#include <linux/atomic.h>
#include <linux/dm-kcopyd.h>
#include <linux/list.h>

#include "numeric.h"

#include "admin-state.h"
#include "completion.h"
#include "data-vio.h"
#include "encodings.h"
#include "physical-zone.h"
#include "priority-table.h"
#include "recovery-journal.h"
#include "statistics.h"
#include "types.h"
#include "vio.h"
#include "wait-queue.h"

/*
 * A slab_depot is responsible for managing all of the slabs and block allocators of a VDO. It has
 * a single array of slabs in order to eliminate the need for additional math in order to compute
 * which physical zone a PBN is in. It also has a block_allocator per zone.
 *
 * Each physical zone has a single dedicated queue and thread for performing all updates to the
 * slabs assigned to that zone. The concurrency guarantees of this single-threaded model allow the
 * code to omit more fine-grained locking for the various slab structures. Each physical zone
 * maintains a separate copy of the slab summary to remove the need for explicit locking on that
 * structure as well.
 *
 * Load operations must be performed on the admin thread. Normal operations, such as allocations
 * and reference count updates, must be performed on the appropriate physical zone thread. Requests
 * from the recovery journal to commit slab journal tail blocks must be scheduled from the recovery
 * journal thread to run on the appropriate physical zone thread. Save operations must be launched
 * from the same admin thread as the original load operation.
 */

enum {};

/*
 * Represents the possible status of a block.
 */
enum reference_status {};

struct vdo_slab;

struct journal_lock {};

struct slab_journal {};

/*
 * Reference_block structure
 *
 * Blocks are used as a proxy, permitting saves of partial refcounts.
 */
struct reference_block {};

/* The search_cursor represents the saved position of a free block search. */
struct search_cursor {};

enum slab_rebuild_status {};

/*
 * This is the type declaration for the vdo_slab type. A vdo_slab currently consists of a run of
 * 2^23 data blocks, but that will soon change to dedicate a small number of those blocks for
 * metadata storage for the reference counts and slab journal for the slab.
 *
 * A reference count is maintained for each physical block number. The vast majority of blocks have
 * a very small reference count (usually 0 or 1). For references less than or equal to MAXIMUM_REFS
 * (254) the reference count is stored in counters[pbn].
 */
struct vdo_slab {};

enum block_allocator_drain_step {};

struct slab_scrubber {};

/* A sub-structure for applying actions in parallel to all an allocator's slabs. */
struct slab_actor {};

/* A slab_iterator is a structure for iterating over a set of slabs. */
struct slab_iterator {};

/*
 * The slab_summary provides hints during load and recovery about the state of the slabs in order
 * to avoid the need to read the slab journals in their entirety before a VDO can come online.
 *
 * The information in the summary for each slab includes the rough number of free blocks (which is
 * used to prioritize scrubbing), the cleanliness of a slab (so that clean slabs containing free
 * space will be used on restart), and the location of the tail block of the slab's journal.
 *
 * The slab_summary has its own partition at the end of the volume which is sized to allow for a
 * complete copy of the summary for each of up to 16 physical zones.
 *
 * During resize, the slab_summary moves its backing partition and is saved once moved; the
 * slab_summary is not permitted to overwrite the previous recovery journal space.
 *
 * The slab_summary does not have its own version information, but relies on the VDO volume version
 * number.
 */

/*
 * A slab status is a very small structure for use in determining the ordering of slabs in the
 * scrubbing process.
 */
struct slab_status {};

struct slab_summary_block {};

/*
 * The statistics for all the slab summary zones owned by this slab summary. These fields are all
 * mutated only by their physical zone threads, but are read by other threads when gathering
 * statistics for the entire depot.
 */
struct atomic_slab_summary_statistics {};

struct block_allocator {};

enum slab_depot_load_type {};

struct slab_depot {};

struct reference_updater;

bool __must_check vdo_attempt_replay_into_slab(struct vdo_slab *slab,
					       physical_block_number_t pbn,
					       enum journal_operation operation,
					       bool increment,
					       struct journal_point *recovery_point,
					       struct vdo_completion *parent);

int __must_check vdo_adjust_reference_count_for_rebuild(struct slab_depot *depot,
							physical_block_number_t pbn,
							enum journal_operation operation);

static inline struct block_allocator *vdo_as_block_allocator(struct vdo_completion *completion)
{}

int __must_check vdo_acquire_provisional_reference(struct vdo_slab *slab,
						   physical_block_number_t pbn,
						   struct pbn_lock *lock);

int __must_check vdo_allocate_block(struct block_allocator *allocator,
				    physical_block_number_t *block_number_ptr);

int vdo_enqueue_clean_slab_waiter(struct block_allocator *allocator,
				  struct vdo_waiter *waiter);

void vdo_modify_reference_count(struct vdo_completion *completion,
				struct reference_updater *updater);

int __must_check vdo_release_block_reference(struct block_allocator *allocator,
					     physical_block_number_t pbn);

void vdo_notify_slab_journals_are_recovered(struct vdo_completion *completion);

void vdo_dump_block_allocator(const struct block_allocator *allocator);

int __must_check vdo_decode_slab_depot(struct slab_depot_state_2_0 state,
				       struct vdo *vdo,
				       struct partition *summary_partition,
				       struct slab_depot **depot_ptr);

void vdo_free_slab_depot(struct slab_depot *depot);

struct slab_depot_state_2_0 __must_check vdo_record_slab_depot(const struct slab_depot *depot);

int __must_check vdo_allocate_reference_counters(struct slab_depot *depot);

struct vdo_slab * __must_check vdo_get_slab(const struct slab_depot *depot,
					    physical_block_number_t pbn);

u8 __must_check vdo_get_increment_limit(struct slab_depot *depot,
					physical_block_number_t pbn);

bool __must_check vdo_is_physical_data_block(const struct slab_depot *depot,
					     physical_block_number_t pbn);

block_count_t __must_check vdo_get_slab_depot_allocated_blocks(const struct slab_depot *depot);

block_count_t __must_check vdo_get_slab_depot_data_blocks(const struct slab_depot *depot);

void vdo_get_slab_depot_statistics(const struct slab_depot *depot,
				   struct vdo_statistics *stats);

void vdo_load_slab_depot(struct slab_depot *depot,
			 const struct admin_state_code *operation,
			 struct vdo_completion *parent, void *context);

void vdo_prepare_slab_depot_to_allocate(struct slab_depot *depot,
					enum slab_depot_load_type load_type,
					struct vdo_completion *parent);

void vdo_update_slab_depot_size(struct slab_depot *depot);

int __must_check vdo_prepare_to_grow_slab_depot(struct slab_depot *depot,
						const struct partition *partition);

void vdo_use_new_slabs(struct slab_depot *depot, struct vdo_completion *parent);

void vdo_abandon_new_slabs(struct slab_depot *depot);

void vdo_drain_slab_depot(struct slab_depot *depot,
			  const struct admin_state_code *operation,
			  struct vdo_completion *parent);

void vdo_resume_slab_depot(struct slab_depot *depot, struct vdo_completion *parent);

void vdo_commit_oldest_slab_journal_tail_blocks(struct slab_depot *depot,
						sequence_number_t recovery_block_number);

void vdo_scrub_all_unrecovered_slabs(struct slab_depot *depot,
				     struct vdo_completion *parent);

void vdo_dump_slab_depot(const struct slab_depot *depot);

#endif /* VDO_SLAB_DEPOT_H */