Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b676f70 authored by Per Forlin's avatar Per Forlin Committed by Chris Ball
Browse files

mmc: core: add random fault injection



This adds support to inject data errors after a completed host transfer.
The mmc core will return error even though the host transfer is successful.
This simple fault injection proved to be very useful to test the
non-blocking error handling in the mmc_blk_issue_rw_rq().
Random faults can also test how the host driver handles pre_req()
and post_req() in case of errors.

Signed-off-by: default avatarPer Forlin <per.forlin@linaro.org>
Acked-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
Reviewed-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent df87ecbf
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/suspend.h>
#include <linux/fault-inject.h>
#include <linux/random.h>

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -83,6 +85,43 @@ static void mmc_flush_scheduled_work(void)
	flush_workqueue(workqueue);
}

#ifdef CONFIG_FAIL_MMC_REQUEST

/*
 * Internal function. Inject random data errors.
 * If mmc_data is NULL no errors are injected.
 */
static void mmc_should_fail_request(struct mmc_host *host,
				    struct mmc_request *mrq)
{
	struct mmc_command *cmd = mrq->cmd;
	struct mmc_data *data = mrq->data;
	static const int data_errors[] = {
		-ETIMEDOUT,
		-EILSEQ,
		-EIO,
	};

	if (!data)
		return;

	if (cmd->error || data->error ||
	    !should_fail(&host->fail_mmc_request, data->blksz * data->blocks))
		return;

	data->error = data_errors[random32() % ARRAY_SIZE(data_errors)];
	data->bytes_xfered = (random32() % (data->bytes_xfered >> 9)) << 9;
}

#else /* CONFIG_FAIL_MMC_REQUEST */

static inline void mmc_should_fail_request(struct mmc_host *host,
					   struct mmc_request *mrq)
{
}

#endif /* CONFIG_FAIL_MMC_REQUEST */

/**
 *	mmc_request_done - finish processing an MMC request
 *	@host: MMC host which completed request
@@ -109,6 +148,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
		cmd->error = 0;
		host->ops->request(host, mrq);
	} else {
		mmc_should_fail_request(host, mrq);

		led_trigger_event(host->led, LED_OFF);

		pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
+25 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/fault-inject.h>

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -158,6 +159,23 @@ static int mmc_clock_opt_set(void *data, u64 val)
	return 0;
}

#ifdef CONFIG_FAIL_MMC_REQUEST

static DECLARE_FAULT_ATTR(fail_mmc_request);

#ifdef KERNEL
/*
 * Internal function. Pass the boot param fail_mmc_request to
 * the setup fault injection attributes routine.
 */
static int __init setup_fail_mmc_request(char *str)
{
	return setup_fault_attr(&fail_mmc_request, str);
}
__setup("fail_mmc_request=", setup_fail_mmc_request);
#endif /* KERNEL */
#endif /* CONFIG_FAIL_MMC_REQUEST */

DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
	"%llu\n");

@@ -187,6 +205,13 @@ void mmc_add_host_debugfs(struct mmc_host *host)
	if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
				root, &host->clk_delay))
		goto err_node;
#endif
#ifdef CONFIG_FAIL_MMC_REQUEST
	host->fail_mmc_request = fail_mmc_request;
	if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
					     root,
					     &host->fail_mmc_request)))
		goto err_node;
#endif
	return;

+5 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@

#include <linux/leds.h>
#include <linux/sched.h>
#include <linux/fault-inject.h>

#include <linux/mmc/core.h>
#include <linux/mmc/pm.h>
@@ -302,6 +303,10 @@ struct mmc_host {

	struct mmc_async_req	*areq;		/* active async req */

#ifdef CONFIG_FAIL_MMC_REQUEST
	struct fault_attr	fail_mmc_request;
#endif

	unsigned long		private[0] ____cacheline_aligned;
};

+11 −0
Original line number Diff line number Diff line
@@ -1070,6 +1070,17 @@ config FAIL_IO_TIMEOUT
	  Only works with drivers that use the generic timeout handling,
	  for others it wont do anything.

config FAIL_MMC_REQUEST
	bool "Fault-injection capability for MMC IO"
	select DEBUG_FS
	depends on FAULT_INJECTION && MMC
	help
	  Provide fault-injection capability for MMC IO.
	  This will make the mmc core return data errors. This is
	  useful to test the error handling in the mmc block device
	  and to test how the mmc host driver handles retries from
	  the block device.

config FAULT_INJECTION_DEBUG_FS
	bool "Debugfs entries for fault-injection capabilities"
	depends on FAULT_INJECTION && SYSFS && DEBUG_FS