linux/drivers/md/dm-ioctl.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
 * Copyright (C) 2004 - 2006 Red Hat, Inc. All rights reserved.
 *
 * This file is released under the GPL.
 */

#include "dm-core.h"
#include "dm-ima.h"
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/miscdevice.h>
#include <linux/sched/mm.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/slab.h>
#include <linux/rbtree.h>
#include <linux/dm-ioctl.h>
#include <linux/hdreg.h>
#include <linux/compat.h>
#include <linux/nospec.h>

#include <linux/uaccess.h>
#include <linux/ima.h>

#define DM_MSG_PREFIX
#define DM_DRIVER_EMAIL

struct dm_file {};

/*
 *---------------------------------------------------------------
 * The ioctl interface needs to be able to look up devices by
 * name or uuid.
 *---------------------------------------------------------------
 */
struct hash_cell {};

struct vers_iter {};


static struct rb_root name_rb_tree =;
static struct rb_root uuid_rb_tree =;

static void dm_hash_remove_all(bool keep_open_devices, bool mark_deferred, bool only_deferred);

/*
 * Guards access to both hash tables.
 */
static DECLARE_RWSEM(_hash_lock);

/*
 * Protects use of mdptr to obtain hash cell name and uuid from mapped device.
 */
static DEFINE_MUTEX(dm_hash_cells_mutex);

static void dm_hash_exit(void)
{}

/*
 *---------------------------------------------------------------
 * Code for looking up a device by name
 *---------------------------------------------------------------
 */
static struct hash_cell *__get_name_cell(const char *str)
{}

static struct hash_cell *__get_uuid_cell(const char *str)
{}

static void __unlink_name(struct hash_cell *hc)
{}

static void __unlink_uuid(struct hash_cell *hc)
{}

static void __link_name(struct hash_cell *new_hc)
{}

static void __link_uuid(struct hash_cell *new_hc)
{}

static struct hash_cell *__get_dev_cell(uint64_t dev)
{}

/*
 *---------------------------------------------------------------
 * Inserting, removing and renaming a device.
 *---------------------------------------------------------------
 */
static struct hash_cell *alloc_cell(const char *name, const char *uuid,
				    struct mapped_device *md)
{}

static void free_cell(struct hash_cell *hc)
{}

/*
 * The kdev_t and uuid of a device can never change once it is
 * initially inserted.
 */
static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
{}

static struct dm_table *__hash_remove(struct hash_cell *hc)
{}

static void dm_hash_remove_all(bool keep_open_devices, bool mark_deferred, bool only_deferred)
{}

/*
 * Set the uuid of a hash_cell that isn't already set.
 */
static void __set_cell_uuid(struct hash_cell *hc, char *new_uuid)
{}

/*
 * Changes the name of a hash_cell and returns the old name for
 * the caller to free.
 */
static char *__change_cell_name(struct hash_cell *hc, char *new_name)
{}

static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
					    const char *new)
{}

void dm_deferred_remove(void)
{}

/*
 *---------------------------------------------------------------
 * Implementation of the ioctl commands
 *---------------------------------------------------------------
 */
/*
 * All the ioctl commands get dispatched to functions with this
 * prototype.
 */
ioctl_fn;

static int remove_all(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * Round up the ptr to an 8-byte boundary.
 */
#define ALIGN_MASK
static inline size_t align_val(size_t val)
{}
static inline void *align_ptr(void *ptr)
{}

/*
 * Retrieves the data payload buffer from an already allocated
 * struct dm_ioctl.
 */
static void *get_result_buffer(struct dm_ioctl *param, size_t param_size,
			       size_t *len)
{}

static bool filter_device(struct hash_cell *hc, const char *pfx_name, const char *pfx_uuid)
{}

static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

static void list_version_get_needed(struct target_type *tt, void *needed_param)
{}

static void list_version_get_info(struct target_type *tt, void *param)
{}

static int __list_versions(struct dm_ioctl *param, size_t param_size, const char *name)
{}

static int list_versions(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

static int get_target_version(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

static int check_name(const char *name)
{}

/*
 * On successful return, the caller must not attempt to acquire
 * _hash_lock without first calling dm_put_live_table, because dm_table_destroy
 * waits for this dm_put_live_table and could be called under this lock.
 */
static struct dm_table *dm_get_inactive_table(struct mapped_device *md, int *srcu_idx)
{}

static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md,
						      struct dm_ioctl *param,
						      int *srcu_idx)
{}

/*
 * Fills in a dm_ioctl structure, ready for sending back to
 * userland.
 */
static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
{}

static int dev_create(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * Always use UUID for lookups if it's present, otherwise use name or dev.
 */
static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
{}

static struct mapped_device *find_device(struct dm_ioctl *param)
{}

static int dev_remove(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * Check a string doesn't overrun the chunk of
 * memory we copied from userland.
 */
static int invalid_str(char *str, void *end)
{}

static int dev_rename(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

static int dev_set_geometry(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

static int do_suspend(struct dm_ioctl *param)
{}

static int do_resume(struct dm_ioctl *param)
{}

/*
 * Set or unset the suspension state of a device.
 * If the device already is in the requested state we just return its status.
 */
static int dev_suspend(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * Copies device info back to user space, used by
 * the create and info ioctls.
 */
static int dev_status(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * Build up the status struct for each target
 */
static void retrieve_status(struct dm_table *table,
			    struct dm_ioctl *param, size_t param_size)
{}

/*
 * Wait for a device to report an event
 */
static int dev_wait(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * Remember the global event number and make it possible to poll
 * for further events.
 */
static int dev_arm_poll(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

static inline blk_mode_t get_mode(struct dm_ioctl *param)
{}

static int next_target(struct dm_target_spec *last, uint32_t next, const char *end,
		       struct dm_target_spec **spec, char **target_params)
{}

static int populate_table(struct dm_table *table,
			  struct dm_ioctl *param, size_t param_size)
{}

static bool is_valid_type(enum dm_queue_mode cur, enum dm_queue_mode new)
{}

static int table_load(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

static int table_clear(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * Retrieves a list of devices used by a particular dm device.
 */
static void retrieve_deps(struct dm_table *table,
			  struct dm_ioctl *param, size_t param_size)
{}

static int table_deps(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * Return the status of a device as a text string for each
 * target.
 */
static int table_status(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * Process device-mapper dependent messages.  Messages prefixed with '@'
 * are processed by the DM core.  All others are delivered to the target.
 * Returns a number <= 1 if message was processed by device mapper.
 * Returns 2 if message should be delivered to the target.
 */
static int message_for_md(struct mapped_device *md, unsigned int argc, char **argv,
			  char *result, unsigned int maxlen)
{}

/*
 * Pass a message to the target that's at the supplied device offset.
 */
static int target_message(struct file *filp, struct dm_ioctl *param, size_t param_size)
{}

/*
 * The ioctl parameter block consists of two parts, a dm_ioctl struct
 * followed by a data buffer.  This flag is set if the second part,
 * which has a variable size, is not used by the function processing
 * the ioctl.
 */
#define IOCTL_FLAGS_NO_PARAMS
#define IOCTL_FLAGS_ISSUE_GLOBAL_EVENT

/*
 *---------------------------------------------------------------
 * Implementation of open/close/ioctl on the special char device.
 *---------------------------------------------------------------
 */
static ioctl_fn lookup_ioctl(unsigned int cmd, int *ioctl_flags)
{}

/*
 * As well as checking the version compatibility this always
 * copies the kernel interface version out.
 */
static int check_version(unsigned int cmd, struct dm_ioctl __user *user,
			 struct dm_ioctl *kernel_params)
{}

#define DM_PARAMS_MALLOC
#define DM_WIPE_BUFFER

static void free_params(struct dm_ioctl *param, size_t param_size, int param_flags)
{}

static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kernel,
		       int ioctl_flags, struct dm_ioctl **param, int *param_flags)
{}

static int validate_params(uint cmd, struct dm_ioctl *param)
{}

static int ctl_ioctl(struct file *file, uint command, struct dm_ioctl __user *user)
{}

static long dm_ctl_ioctl(struct file *file, uint command, ulong u)
{}

#ifdef CONFIG_COMPAT
static long dm_compat_ctl_ioctl(struct file *file, uint command, ulong u)
{}
#else
#define dm_compat_ctl_ioctl
#endif

static int dm_open(struct inode *inode, struct file *filp)
{}

static int dm_release(struct inode *inode, struct file *filp)
{}

static __poll_t dm_poll(struct file *filp, poll_table *wait)
{}

static const struct file_operations _ctl_fops =;

static struct miscdevice _dm_misc =;

MODULE_ALIAS_MISCDEV();
MODULE_ALIAS();

/*
 * Create misc character device and link to DM_DIR/control.
 */
int __init dm_interface_init(void)
{}

void dm_interface_exit(void)
{}

/**
 * dm_copy_name_and_uuid - Copy mapped device name & uuid into supplied buffers
 * @md: Pointer to mapped_device
 * @name: Buffer (size DM_NAME_LEN) for name
 * @uuid: Buffer (size DM_UUID_LEN) for uuid or empty string if uuid not defined
 */
int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid)
{}
EXPORT_SYMBOL_GPL();

/**
 * dm_early_create - create a mapped device in early boot.
 *
 * @dmi: Contains main information of the device mapping to be created.
 * @spec_array: array of pointers to struct dm_target_spec. Describes the
 * mapping table of the device.
 * @target_params_array: array of strings with the parameters to a specific
 * target.
 *
 * Instead of having the struct dm_target_spec and the parameters for every
 * target embedded at the end of struct dm_ioctl (as performed in a normal
 * ioctl), pass them as arguments, so the caller doesn't need to serialize them.
 * The size of the spec_array and target_params_array is given by
 * @dmi->target_count.
 * This function is supposed to be called in early boot, so locking mechanisms
 * to protect against concurrent loads are not required.
 */
int __init dm_early_create(struct dm_ioctl *dmi,
			   struct dm_target_spec **spec_array,
			   char **target_params_array)
{}