linux/drivers/md/dm-vdo/dm-vdo-target.c

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

#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device-mapper.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>

#include "admin-state.h"
#include "block-map.h"
#include "completion.h"
#include "constants.h"
#include "data-vio.h"
#include "dedupe.h"
#include "dump.h"
#include "encodings.h"
#include "errors.h"
#include "flush.h"
#include "io-submitter.h"
#include "logger.h"
#include "memory-alloc.h"
#include "message-stats.h"
#include "recovery-journal.h"
#include "repair.h"
#include "slab-depot.h"
#include "status-codes.h"
#include "string-utils.h"
#include "thread-device.h"
#include "thread-registry.h"
#include "thread-utils.h"
#include "types.h"
#include "vdo.h"
#include "vio.h"

enum admin_phases {};

static const char * const ADMIN_PHASE_NAMES[] =;

/* If we bump this, update the arrays below */
#define TABLE_VERSION

/* arrays for handling different table versions */
static const u8 REQUIRED_ARGC[] =;
/* pool name no longer used. only here for verification of older versions */
static const u8 POOL_NAME_ARG_INDEX[] =;

/*
 * Track in-use instance numbers using a flat bit array.
 *
 * O(n) run time isn't ideal, but if we have 1000 VDO devices in use simultaneously we still only
 * need to scan 16 words, so it's not likely to be a big deal compared to other resource usage.
 */

/*
 * This minimum size for the bit array creates a numbering space of 0-999, which allows
 * successive starts of the same volume to have different instance numbers in any
 * reasonably-sized test. Changing instances on restart allows vdoMonReport to detect that
 * the ephemeral stats have reset to zero.
 */
#define BIT_COUNT_MINIMUM
/* Grow the bit array by this many bits when needed */
#define BIT_COUNT_INCREMENT

struct instance_tracker {};

static DEFINE_MUTEX(instances_lock);
static struct instance_tracker instances;

/**
 * free_device_config() - Free a device config created by parse_device_config().
 * @config: The config to free.
 */
static void free_device_config(struct device_config *config)
{}

/**
 * get_version_number() - Decide the version number from argv.
 *
 * @argc: The number of table values.
 * @argv: The array of table values.
 * @error_ptr: A pointer to return a error string in.
 * @version_ptr: A pointer to return the version.
 *
 * Return: VDO_SUCCESS or an error code.
 */
static int get_version_number(int argc, char **argv, char **error_ptr,
			      unsigned int *version_ptr)
{}

/* Free a list of non-NULL string pointers, and then the list itself. */
static void free_string_array(char **string_array)
{}

/*
 * Split the input string into substrings, separated at occurrences of the indicated character,
 * returning a null-terminated list of string pointers.
 *
 * The string pointers and the pointer array itself should both be freed with vdo_free() when no
 * longer needed. This can be done with vdo_free_string_array (below) if the pointers in the array
 * are not changed. Since the array and copied strings are allocated by this function, it may only
 * be used in contexts where allocation is permitted.
 *
 * Empty substrings are not ignored; that is, returned substrings may be empty strings if the
 * separator occurs twice in a row.
 */
static int split_string(const char *string, char separator, char ***substring_array_ptr)
{}

/*
 * Join the input substrings into one string, joined with the indicated character, returning a
 * string. array_length is a bound on the number of valid elements in substring_array, in case it
 * is not NULL-terminated.
 */
static int join_strings(char **substring_array, size_t array_length, char separator,
			char **string_ptr)
{}

/**
 * parse_bool() - Parse a two-valued option into a bool.
 * @bool_str: The string value to convert to a bool.
 * @true_str: The string value which should be converted to true.
 * @false_str: The string value which should be converted to false.
 * @bool_ptr: A pointer to return the bool value in.
 *
 * Return: VDO_SUCCESS or an error if bool_str is neither true_str nor false_str.
 */
static inline int __must_check parse_bool(const char *bool_str, const char *true_str,
					  const char *false_str, bool *bool_ptr)
{}

/**
 * process_one_thread_config_spec() - Process one component of a thread parameter configuration
 *				      string and update the configuration data structure.
 * @thread_param_type: The type of thread specified.
 * @count: The thread count requested.
 * @config: The configuration data structure to update.
 *
 * If the thread count requested is invalid, a message is logged and -EINVAL returned. If the
 * thread name is unknown, a message is logged but no error is returned.
 *
 * Return: VDO_SUCCESS or -EINVAL
 */
static int process_one_thread_config_spec(const char *thread_param_type,
					  unsigned int count,
					  struct thread_count_config *config)
{}

/**
 * parse_one_thread_config_spec() - Parse one component of a thread parameter configuration string
 *				    and update the configuration data structure.
 * @spec: The thread parameter specification string.
 * @config: The configuration data to be updated.
 */
static int parse_one_thread_config_spec(const char *spec,
					struct thread_count_config *config)
{}

/**
 * parse_thread_config_string() - Parse the configuration string passed and update the specified
 *				  counts and other parameters of various types of threads to be
 *				  created.
 * @string: Thread parameter configuration string.
 * @config: The thread configuration data to update.
 *
 * The configuration string should contain one or more comma-separated specs of the form
 * "typename=number"; the supported type names are "cpu", "ack", "bio", "bioRotationInterval",
 * "logical", "physical", and "hash".
 *
 * If an error occurs during parsing of a single key/value pair, we deem it serious enough to stop
 * further parsing.
 *
 * This function can't set the "reason" value the caller wants to pass back, because we'd want to
 * format it to say which field was invalid, and we can't allocate the "reason" strings
 * dynamically. So if an error occurs, we'll log the details and pass back an error.
 *
 * Return: VDO_SUCCESS or -EINVAL or -ENOMEM
 */
static int parse_thread_config_string(const char *string,
				      struct thread_count_config *config)
{}

/**
 * process_one_key_value_pair() - Process one component of an optional parameter string and update
 *				  the configuration data structure.
 * @key: The optional parameter key name.
 * @value: The optional parameter value.
 * @config: The configuration data structure to update.
 *
 * If the value requested is invalid, a message is logged and -EINVAL returned. If the key is
 * unknown, a message is logged but no error is returned.
 *
 * Return: VDO_SUCCESS or -EINVAL
 */
static int process_one_key_value_pair(const char *key, unsigned int value,
				      struct device_config *config)
{}

/**
 * parse_one_key_value_pair() - Parse one key/value pair and update the configuration data
 *				structure.
 * @key: The optional key name.
 * @value: The optional value.
 * @config: The configuration data to be updated.
 *
 * Return: VDO_SUCCESS or error.
 */
static int parse_one_key_value_pair(const char *key, const char *value,
				    struct device_config *config)
{}

/**
 * parse_key_value_pairs() - Parse all key/value pairs from a list of arguments.
 * @argc: The total number of arguments in list.
 * @argv: The list of key/value pairs.
 * @config: The device configuration data to update.
 *
 * If an error occurs during parsing of a single key/value pair, we deem it serious enough to stop
 * further parsing.
 *
 * This function can't set the "reason" value the caller wants to pass back, because we'd want to
 * format it to say which field was invalid, and we can't allocate the "reason" strings
 * dynamically. So if an error occurs, we'll log the details and return the error.
 *
 * Return: VDO_SUCCESS or error
 */
static int parse_key_value_pairs(int argc, char **argv, struct device_config *config)
{}

/**
 * parse_optional_arguments() - Parse the configuration string passed in for optional arguments.
 * @arg_set: The structure holding the arguments to parse.
 * @error_ptr: Pointer to a buffer to hold the error string.
 * @config: Pointer to device configuration data to update.
 *
 * For V0/V1 configurations, there will only be one optional parameter; the thread configuration.
 * The configuration string should contain one or more comma-separated specs of the form
 * "typename=number"; the supported type names are "cpu", "ack", "bio", "bioRotationInterval",
 * "logical", "physical", and "hash".
 *
 * For V2 configurations and beyond, there could be any number of arguments. They should contain
 * one or more key/value pairs separated by a space.
 *
 * Return: VDO_SUCCESS or error
 */
static int parse_optional_arguments(struct dm_arg_set *arg_set, char **error_ptr,
				    struct device_config *config)
{}

/**
 * handle_parse_error() - Handle a parsing error.
 * @config: The config to free.
 * @error_ptr: A place to store a constant string about the error.
 * @error_str: A constant string to store in error_ptr.
 */
static void handle_parse_error(struct device_config *config, char **error_ptr,
			       char *error_str)
{}

/**
 * parse_device_config() - Convert the dmsetup table into a struct device_config.
 * @argc: The number of table values.
 * @argv: The array of table values.
 * @ti: The target structure for this table.
 * @config_ptr: A pointer to return the allocated config.
 *
 * Return: VDO_SUCCESS or an error code.
 */
static int parse_device_config(int argc, char **argv, struct dm_target *ti,
			       struct device_config **config_ptr)
{}

static struct vdo *get_vdo_for_target(struct dm_target *ti)
{}


static int vdo_map_bio(struct dm_target *ti, struct bio *bio)
{}

static void vdo_io_hints(struct dm_target *ti, struct queue_limits *limits)
{}

static int vdo_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn,
			       void *data)
{}

/*
 * Status line is:
 *    <device> <operating mode> <in recovery> <index state> <compression state>
 *    <used physical blocks> <total physical blocks>
 */

static void vdo_status(struct dm_target *ti, status_type_t status_type,
		       unsigned int status_flags, char *result, unsigned int maxlen)
{}

static block_count_t __must_check get_underlying_device_block_count(const struct vdo *vdo)
{}

static int __must_check process_vdo_message_locked(struct vdo *vdo, unsigned int argc,
						   char **argv)
{}

/*
 * If the message is a dump, just do it. Otherwise, check that no other message is being processed,
 * and only proceed if so.
 * Returns -EBUSY if another message is being processed
 */
static int __must_check process_vdo_message(struct vdo *vdo, unsigned int argc,
					    char **argv)
{}

static int vdo_message(struct dm_target *ti, unsigned int argc, char **argv,
		       char *result_buffer, unsigned int maxlen)
{}

static void configure_target_capabilities(struct dm_target *ti)
{}

/*
 * Implements vdo_filter_fn.
 */
static bool vdo_uses_device(struct vdo *vdo, const void *context)
{}

/**
 * get_thread_id_for_phase() - Get the thread id for the current phase of the admin operation in
 *                             progress.
 */
static thread_id_t __must_check get_thread_id_for_phase(struct vdo *vdo)
{}

static struct vdo_completion *prepare_admin_completion(struct vdo *vdo,
						       vdo_action_fn callback,
						       vdo_action_fn error_handler)
{}

/**
 * advance_phase() - Increment the phase of the current admin operation and prepare the admin
 *                   completion to run on the thread for the next phase.
 * @vdo: The on which an admin operation is being performed
 *
 * Return: The current phase
 */
static u32 advance_phase(struct vdo *vdo)
{}

/*
 * Perform an administrative operation (load, suspend, grow logical, or grow physical). This method
 * should not be called from vdo threads.
 */
static int perform_admin_operation(struct vdo *vdo, u32 starting_phase,
				   vdo_action_fn callback, vdo_action_fn error_handler,
				   const char *type)
{}

/* Assert that we are operating on the correct thread for the current phase. */
static void assert_admin_phase_thread(struct vdo *vdo, const char *what)
{}

/**
 * finish_operation_callback() - Callback to finish an admin operation.
 * @completion: The admin_completion.
 */
static void finish_operation_callback(struct vdo_completion *completion)
{}

/**
 * decode_from_super_block() - Decode the VDO state from the super block and validate that it is
 *                             correct.
 * @vdo: The vdo being loaded.
 *
 * On error from this method, the component states must be destroyed explicitly. If this method
 * returns successfully, the component states must not be destroyed.
 *
 * Return: VDO_SUCCESS or an error.
 */
static int __must_check decode_from_super_block(struct vdo *vdo)
{}

/**
 * decode_vdo() - Decode the component data portion of a super block and fill in the corresponding
 *                portions of the vdo being loaded.
 * @vdo: The vdo being loaded.
 *
 * This will also allocate the recovery journal and slab depot. If this method is called with an
 * asynchronous layer (i.e. a thread config which specifies at least one base thread), the block
 * map and packer will be constructed as well.
 *
 * Return: VDO_SUCCESS or an error.
 */
static int __must_check decode_vdo(struct vdo *vdo)
{}

/**
 * pre_load_callback() - Callback to initiate a pre-load, registered in vdo_initialize().
 * @completion: The admin completion.
 */
static void pre_load_callback(struct vdo_completion *completion)
{}

static void release_instance(unsigned int instance)
{}

static void set_device_config(struct dm_target *ti, struct vdo *vdo,
			      struct device_config *config)
{}

static int vdo_initialize(struct dm_target *ti, unsigned int instance,
			  struct device_config *config)
{}

/* Implements vdo_filter_fn. */
static bool __must_check vdo_is_named(struct vdo *vdo, const void *context)
{}

/**
 * get_bit_array_size() - Return the number of bytes needed to store a bit array of the specified
 *                        capacity in an array of unsigned longs.
 * @bit_count: The number of bits the array must hold.
 *
 * Return: the number of bytes needed for the array representation.
 */
static size_t get_bit_array_size(unsigned int bit_count)
{}

/**
 * grow_bit_array() - Re-allocate the bitmap word array so there will more instance numbers that
 *                    can be allocated.
 *
 * Since the array is initially NULL, this also initializes the array the first time we allocate an
 * instance number.
 *
 * Return: VDO_SUCCESS or an error code from the allocation
 */
static int grow_bit_array(void)
{}

/**
 * allocate_instance() - Allocate an instance number.
 * @instance_ptr: A point to hold the instance number
 *
 * Return: VDO_SUCCESS or an error code
 *
 * This function must be called while holding the instances lock.
 */
static int allocate_instance(unsigned int *instance_ptr)
{}

static int construct_new_vdo_registered(struct dm_target *ti, unsigned int argc,
					char **argv, unsigned int instance)
{}

static int construct_new_vdo(struct dm_target *ti, unsigned int argc, char **argv)
{}

/**
 * check_may_grow_physical() - Callback to check that we're not in recovery mode, used in
 *                             vdo_prepare_to_grow_physical().
 * @completion: The admin completion.
 */
static void check_may_grow_physical(struct vdo_completion *completion)
{}

static block_count_t get_partition_size(struct layout *layout, enum partition_id id)
{}

/**
 * grow_layout() - Make the layout for growing a vdo.
 * @vdo: The vdo preparing to grow.
 * @old_size: The current size of the vdo.
 * @new_size: The size to which the vdo will be grown.
 *
 * Return: VDO_SUCCESS or an error code.
 */
static int grow_layout(struct vdo *vdo, block_count_t old_size, block_count_t new_size)
{}

static int prepare_to_grow_physical(struct vdo *vdo, block_count_t new_physical_blocks)
{}

/**
 * validate_new_device_config() - Check whether a new device config represents a valid modification
 *				  to an existing config.
 * @to_validate: The new config to validate.
 * @config: The existing config.
 * @may_grow: Set to true if growing the logical and physical size of the vdo is currently
 *	      permitted.
 * @error_ptr: A pointer to hold the reason for any error.
 *
 * Return: VDO_SUCCESS or an error.
 */
static int validate_new_device_config(struct device_config *to_validate,
				      struct device_config *config, bool may_grow,
				      char **error_ptr)
{}

static int prepare_to_modify(struct dm_target *ti, struct device_config *config,
			     struct vdo *vdo)
{}

static int update_existing_vdo(const char *device_name, struct dm_target *ti,
			       unsigned int argc, char **argv, struct vdo *vdo)
{}

static int vdo_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{}

static void vdo_dtr(struct dm_target *ti)
{}

static void vdo_presuspend(struct dm_target *ti)
{}

/**
 * write_super_block_for_suspend() - Update the VDO state and save the super block.
 * @completion: The admin completion
 */
static void write_super_block_for_suspend(struct vdo_completion *completion)
{}

/**
 * suspend_callback() - Callback to initiate a suspend, registered in vdo_postsuspend().
 * @completion: The sub-task completion.
 */
static void suspend_callback(struct vdo_completion *completion)
{}

static void vdo_postsuspend(struct dm_target *ti)
{}

/**
 * was_new() - Check whether the vdo was new when it was loaded.
 * @vdo: The vdo to query.
 *
 * Return: true if the vdo was new.
 */
static bool was_new(const struct vdo *vdo)
{}

/**
 * requires_repair() - Check whether a vdo requires recovery or rebuild.
 * @vdo: The vdo to query.
 *
 * Return: true if the vdo must be repaired.
 */
static bool __must_check requires_repair(const struct vdo *vdo)
{}

/**
 * get_load_type() - Determine how the slab depot was loaded.
 * @vdo: The vdo.
 *
 * Return: How the depot was loaded.
 */
static enum slab_depot_load_type get_load_type(struct vdo *vdo)
{}

/**
 * load_callback() - Callback to do the destructive parts of loading a VDO.
 * @completion: The sub-task completion.
 */
static void load_callback(struct vdo_completion *completion)
{}

/**
 * handle_load_error() - Handle an error during the load operation.
 * @completion: The admin completion.
 *
 * If at all possible, brings the vdo online in read-only mode. This handler is registered in
 * vdo_preresume_registered().
 */
static void handle_load_error(struct vdo_completion *completion)
{}

/**
 * write_super_block_for_resume() - Update the VDO state and save the super block.
 * @completion: The admin completion
 */
static void write_super_block_for_resume(struct vdo_completion *completion)
{}

/**
 * resume_callback() - Callback to resume a VDO.
 * @completion: The admin completion.
 */
static void resume_callback(struct vdo_completion *completion)
{}

/**
 * grow_logical_callback() - Callback to initiate a grow logical.
 * @completion: The admin completion.
 *
 * Registered in perform_grow_logical().
 */
static void grow_logical_callback(struct vdo_completion *completion)
{}

/**
 * handle_logical_growth_error() - Handle an error during the grow physical process.
 * @completion: The admin completion.
 */
static void handle_logical_growth_error(struct vdo_completion *completion)
{}

/**
 * perform_grow_logical() - Grow the logical size of the vdo.
 * @vdo: The vdo to grow.
 * @new_logical_blocks: The size to which the vdo should be grown.
 *
 * Context: This method may only be called when the vdo has been suspended and must not be called
 * from a base thread.
 *
 * Return: VDO_SUCCESS or an error.
 */
static int perform_grow_logical(struct vdo *vdo, block_count_t new_logical_blocks)
{}

static void copy_callback(int read_err, unsigned long write_err, void *context)
{}

static void partition_to_region(struct partition *partition, struct vdo *vdo,
				struct dm_io_region *region)
{}

/**
 * copy_partition() - Copy a partition from the location specified in the current layout to that in
 *                    the next layout.
 * @vdo: The vdo preparing to grow.
 * @id: The ID of the partition to copy.
 * @parent: The completion to notify when the copy is complete.
 */
static void copy_partition(struct vdo *vdo, enum partition_id id,
			   struct vdo_completion *parent)
{}

/**
 * grow_physical_callback() - Callback to initiate a grow physical.
 * @completion: The admin completion.
 *
 * Registered in perform_grow_physical().
 */
static void grow_physical_callback(struct vdo_completion *completion)
{}

/**
 * handle_physical_growth_error() - Handle an error during the grow physical process.
 * @completion: The sub-task completion.
 */
static void handle_physical_growth_error(struct vdo_completion *completion)
{}

/**
 * perform_grow_physical() - Grow the physical size of the vdo.
 * @vdo: The vdo to resize.
 * @new_physical_blocks: The new physical size in blocks.
 *
 * Context: This method may only be called when the vdo has been suspended and must not be called
 * from a base thread.
 *
 * Return: VDO_SUCCESS or an error.
 */
static int perform_grow_physical(struct vdo *vdo, block_count_t new_physical_blocks)
{}

/**
 * apply_new_vdo_configuration() - Attempt to make any configuration changes from the table being
 *                                 resumed.
 * @vdo: The vdo being resumed.
 * @config: The new device configuration derived from the table with which the vdo is being
 *          resumed.
 *
 * Return: VDO_SUCCESS or an error.
 */
static int __must_check apply_new_vdo_configuration(struct vdo *vdo,
						    struct device_config *config)
{}

static int vdo_preresume_registered(struct dm_target *ti, struct vdo *vdo)
{}

static int vdo_preresume(struct dm_target *ti)
{}

static void vdo_resume(struct dm_target *ti)
{}

/*
 * If anything changes that affects how user tools will interact with vdo, update the version
 * number and make sure documentation about the change is complete so tools can properly update
 * their management code.
 */
static struct target_type vdo_target_bio =;

static bool dm_registered;

static void vdo_module_destroy(void)
{}

static int __init vdo_init(void)
{}

static void __exit vdo_exit(void)
{}

module_init();
module_exit(vdo_exit);

module_param_named(log_level, vdo_log_level, uint, 0644);
MODULE_PARM_DESC();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();