Skip to content

Commit

Permalink
mmc: core: add random fault injection
Browse files Browse the repository at this point in the history
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: Per Forlin <per.forlin@linaro.org>
Acked-by: Akinobu Mita <akinobu.mita@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
  • Loading branch information
Per Forlin authored and Chris Ball committed Oct 26, 2011
1 parent df87ecb commit 1b676f7
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 0 deletions.
41 changes: 41 additions & 0 deletions drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand All @@ -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",
Expand Down
25 changes: 25 additions & 0 deletions drivers/mmc/core/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions include/linux/mmc/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
};

Expand Down
11 changes: 11 additions & 0 deletions lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 1b676f7

Please sign in to comment.