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

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
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/fault-inject.h>
#include <linux/random.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
...@@ -83,6 +85,43 @@ static void mmc_flush_scheduled_work(void) ...@@ -83,6 +85,43 @@ static void mmc_flush_scheduled_work(void)
flush_workqueue(workqueue); 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 * mmc_request_done - finish processing an MMC request
* @host: MMC host which completed request * @host: MMC host which completed request
...@@ -109,6 +148,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) ...@@ -109,6 +148,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
cmd->error = 0; cmd->error = 0;
host->ops->request(host, mrq); host->ops->request(host, mrq);
} else { } else {
mmc_should_fail_request(host, mrq);
led_trigger_event(host->led, LED_OFF); led_trigger_event(host->led, LED_OFF);
pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/fault-inject.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
...@@ -158,6 +159,23 @@ static int mmc_clock_opt_set(void *data, u64 val) ...@@ -158,6 +159,23 @@ static int mmc_clock_opt_set(void *data, u64 val)
return 0; 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, DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
"%llu\n"); "%llu\n");
...@@ -187,6 +205,13 @@ void mmc_add_host_debugfs(struct mmc_host *host) ...@@ -187,6 +205,13 @@ void mmc_add_host_debugfs(struct mmc_host *host)
if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
root, &host->clk_delay)) root, &host->clk_delay))
goto err_node; 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 #endif
return; return;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/fault-inject.h>
#include <linux/mmc/core.h> #include <linux/mmc/core.h>
#include <linux/mmc/pm.h> #include <linux/mmc/pm.h>
...@@ -302,6 +303,10 @@ struct mmc_host { ...@@ -302,6 +303,10 @@ struct mmc_host {
struct mmc_async_req *areq; /* active async req */ 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; unsigned long private[0] ____cacheline_aligned;
}; };
......
...@@ -1070,6 +1070,17 @@ config FAIL_IO_TIMEOUT ...@@ -1070,6 +1070,17 @@ config FAIL_IO_TIMEOUT
Only works with drivers that use the generic timeout handling, Only works with drivers that use the generic timeout handling,
for others it wont do anything. 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 config FAULT_INJECTION_DEBUG_FS
bool "Debugfs entries for fault-injection capabilities" bool "Debugfs entries for fault-injection capabilities"
depends on FAULT_INJECTION && SYSFS && DEBUG_FS depends on FAULT_INJECTION && SYSFS && DEBUG_FS
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment