linux/lib/test_kmod.c

// SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.1
/*
 * kmod stress test driver
 *
 * Copyright (C) 2017 Luis R. Rodriguez <[email protected]>
 */
#define pr_fmt(fmt)

/*
 * This driver provides an interface to trigger and test the kernel's
 * module loader through a series of configurations and a few triggers.
 * To test this driver use the following script as root:
 *
 * tools/testing/selftests/kmod/kmod.sh --help
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/printk.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/device.h>

#define TEST_START_NUM_THREADS
#define TEST_START_DRIVER
#define TEST_START_TEST_FS
#define TEST_START_TEST_CASE


static bool force_init_test =;
module_param(force_init_test, bool_enable_only, 0644);
MODULE_PARM_DESC();

/*
 * For device allocation / registration
 */
static DEFINE_MUTEX(reg_dev_mutex);
static LIST_HEAD(reg_test_devs);

/*
 * num_test_devs actually represents the *next* ID of the next
 * device we will allow to create.
 */
static int num_test_devs;

/**
 * enum kmod_test_case - linker table test case
 * @TEST_KMOD_DRIVER: stress tests request_module()
 * @TEST_KMOD_FS_TYPE: stress tests get_fs_type()
 *
 * If you add a  test case, please be sure to review if you need to set
 * @need_mod_put for your tests case.
 */
enum kmod_test_case {};

struct test_config {};

struct kmod_test_device;

/**
 * struct kmod_test_device_info - thread info
 *
 * @ret_sync: return value if request_module() is used, sync request for
 * 	@TEST_KMOD_DRIVER
 * @fs_sync: return value of get_fs_type() for @TEST_KMOD_FS_TYPE
 * @task_sync: kthread's task_struct or %NULL if not running
 * @thread_idx: thread ID
 * @test_dev: test device test is being performed under
 * @need_mod_put: Some tests (get_fs_type() is one) requires putting the module
 *	(module_put(fs_sync->owner)) when done, otherwise you will not be able
 *	to unload the respective modules and re-test. We use this to keep
 *	accounting of when we need this and to help out in case we need to
 *	error out and deal with module_put() on error.
 */
struct kmod_test_device_info {};

/**
 * struct kmod_test_device - test device to help test kmod
 *
 * @dev_idx: unique ID for test device
 * @config: configuration for the test
 * @misc_dev: we use a misc device under the hood
 * @dev: pointer to misc_dev's own struct device
 * @config_mutex: protects configuration of test
 * @trigger_mutex: the test trigger can only be fired once at a time
 * @thread_mutex: protects @done count, and the @info per each thread
 * @done: number of threads which have completed or failed
 * @test_is_oom: when we run out of memory, use this to halt moving forward
 * @kthreads_done: completion used to signal when all work is done
 * @list: needed to be part of the reg_test_devs
 * @info: array of info for each thread
 */
struct kmod_test_device {};

static const char *test_case_str(enum kmod_test_case test_case)
{}

static struct miscdevice *dev_to_misc_dev(struct device *dev)
{}

static struct kmod_test_device *misc_dev_to_test_dev(struct miscdevice *misc_dev)
{}

static struct kmod_test_device *dev_to_test_dev(struct device *dev)
{}

/* Must run with thread_mutex held */
static void kmod_test_done_check(struct kmod_test_device *test_dev,
				 unsigned int idx)
{}

static void test_kmod_put_module(struct kmod_test_device_info *info)
{}

static int run_request(void *data)
{}

static int tally_work_test(struct kmod_test_device_info *info)
{}

/*
 * XXX: add result option to display if all errors did not match.
 * For now we just keep any error code if one was found.
 *
 * If this ran it means *all* tasks were created fine and we
 * are now just collecting results.
 *
 * Only propagate errors, do not override with a subsequent success case.
 */
static void tally_up_work(struct kmod_test_device *test_dev)
{}

static int try_one_request(struct kmod_test_device *test_dev, unsigned int idx)
{}

static void test_dev_kmod_stop_tests(struct kmod_test_device *test_dev)
{}

/*
 * Only wait *iff* we did not run into any errors during all of our thread
 * set up. If run into any issues we stop threads and just bail out with
 * an error to the trigger. This also means we don't need any tally work
 * for any threads which fail.
 */
static int try_requests(struct kmod_test_device *test_dev)
{}

static int run_test_driver(struct kmod_test_device *test_dev)
{}

static int run_test_fs_type(struct kmod_test_device *test_dev)
{}

static ssize_t config_show(struct device *dev,
			   struct device_attribute *attr,
			   char *buf)
{}
static DEVICE_ATTR_RO(config);

/*
 * This ensures we don't allow kicking threads through if our configuration
 * is faulty.
 */
static int __trigger_config_run(struct kmod_test_device *test_dev)
{}

static int trigger_config_run(struct kmod_test_device *test_dev)
{}

static ssize_t
trigger_config_store(struct device *dev,
		     struct device_attribute *attr,
		     const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(trigger_config);

/*
 * XXX: move to kstrncpy() once merged.
 *
 * Users should use kfree_const() when freeing these.
 */
static int __kstrncpy(char **dst, const char *name, size_t count, gfp_t gfp)
{}

static int config_copy_test_driver_name(struct test_config *config,
				    const char *name,
				    size_t count)
{}


static int config_copy_test_fs(struct test_config *config, const char *name,
			       size_t count)
{}

static void __kmod_config_free(struct test_config *config)
{}

static void kmod_config_free(struct kmod_test_device *test_dev)
{}

static ssize_t config_test_driver_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{}

/*
 * As per sysfs_kf_seq_show() the buf is max PAGE_SIZE.
 */
static ssize_t config_test_show_str(struct mutex *config_mutex,
				    char *dst,
				    char *src)
{}

static ssize_t config_test_driver_show(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{}
static DEVICE_ATTR_RW(config_test_driver);

static ssize_t config_test_fs_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{}

static ssize_t config_test_fs_show(struct device *dev,
				   struct device_attribute *attr,
				   char *buf)
{}
static DEVICE_ATTR_RW(config_test_fs);

static int trigger_config_run_type(struct kmod_test_device *test_dev,
				   enum kmod_test_case test_case,
				   const char *test_str)
{}

static void free_test_dev_info(struct kmod_test_device *test_dev)
{}

static int kmod_config_sync_info(struct kmod_test_device *test_dev)
{}

/*
 * Old kernels may not have this, if you want to port this code to
 * test it on older kernels.
 */
#ifdef get_kmod_umh_limit
static unsigned int kmod_init_test_thread_limit(void)
{
	return get_kmod_umh_limit();
}
#else
static unsigned int kmod_init_test_thread_limit(void)
{}
#endif

static int __kmod_config_init(struct kmod_test_device *test_dev)
{}

static ssize_t reset_store(struct device *dev,
			   struct device_attribute *attr,
			   const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(reset);

static int test_dev_config_update_uint_sync(struct kmod_test_device *test_dev,
					    const char *buf, size_t size,
					    unsigned int *config,
					    int (*test_sync)(struct kmod_test_device *test_dev))
{}

static int test_dev_config_update_uint_range(struct kmod_test_device *test_dev,
					     const char *buf, size_t size,
					     unsigned int *config,
					     unsigned int min,
					     unsigned int max)
{}

static int test_dev_config_update_int(struct kmod_test_device *test_dev,
				      const char *buf, size_t size,
				      int *config)
{}

static ssize_t test_dev_config_show_int(struct kmod_test_device *test_dev,
					char *buf,
					int config)
{}

static ssize_t test_dev_config_show_uint(struct kmod_test_device *test_dev,
					 char *buf,
					 unsigned int config)
{}

static ssize_t test_result_store(struct device *dev,
				 struct device_attribute *attr,
				 const char *buf, size_t count)
{}

static ssize_t config_num_threads_store(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{}

static ssize_t config_num_threads_show(struct device *dev,
				       struct device_attribute *attr,
				       char *buf)
{}
static DEVICE_ATTR_RW(config_num_threads);

static ssize_t config_test_case_store(struct device *dev,
				      struct device_attribute *attr,
				      const char *buf, size_t count)
{}

static ssize_t config_test_case_show(struct device *dev,
				     struct device_attribute *attr,
				     char *buf)
{}
static DEVICE_ATTR_RW(config_test_case);

static ssize_t test_result_show(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{}
static DEVICE_ATTR_RW(test_result);

#define TEST_KMOD_DEV_ATTR(name)

static struct attribute *test_dev_attrs[] =;

ATTRIBUTE_GROUPS();

static int kmod_config_init(struct kmod_test_device *test_dev)
{}

static struct kmod_test_device *alloc_test_dev_kmod(int idx)
{}

static void free_test_dev_kmod(struct kmod_test_device *test_dev)
{}

static struct kmod_test_device *register_test_dev_kmod(void)
{}

static int __init test_kmod_init(void)
{}
late_initcall(test_kmod_init);

static
void unregister_test_dev_kmod(struct kmod_test_device *test_dev)
{}

static void __exit test_kmod_exit(void)
{}
module_exit(test_kmod_exit);

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