aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2008-09-14 08:56:33 -0400
committerJens Axboe <jens.axboe@oracle.com>2008-10-09 02:56:17 -0400
commit581d4e28d9195aa8b2231383dbabc288988d615e (patch)
tree093bcac9a538ef67edcf91826f7532bdb88e6248
parent0a0d96b03a1f3bfd6bc3ea08008699e8e59fccd9 (diff)
block: add fault injection mechanism for faking request timeouts
Only works for the generic request timer handling. Allows one to sporadically ignore request completions, thus exercising the timeout handling. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--block/blk-softirq.c2
-rw-r--r--block/blk-timeout.c59
-rw-r--r--block/blk.h12
-rw-r--r--block/genhd.c8
-rw-r--r--include/linux/blkdev.h1
-rw-r--r--lib/Kconfig.debug13
6 files changed, 94 insertions, 1 deletions
diff --git a/block/blk-softirq.c b/block/blk-softirq.c
index 7ab344afb16f..e660d26ca656 100644
--- a/block/blk-softirq.c
+++ b/block/blk-softirq.c
@@ -154,6 +154,8 @@ do_local:
154 **/ 154 **/
155void blk_complete_request(struct request *req) 155void blk_complete_request(struct request *req)
156{ 156{
157 if (unlikely(blk_should_fake_timeout(req->q)))
158 return;
157 if (!blk_mark_rq_complete(req)) 159 if (!blk_mark_rq_complete(req))
158 __blk_complete_request(req); 160 __blk_complete_request(req);
159} 161}
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
index 6e5c781c5af1..9b4ad138bb33 100644
--- a/block/blk-timeout.c
+++ b/block/blk-timeout.c
@@ -4,9 +4,68 @@
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5#include <linux/module.h> 5#include <linux/module.h>
6#include <linux/blkdev.h> 6#include <linux/blkdev.h>
7#include <linux/fault-inject.h>
7 8
8#include "blk.h" 9#include "blk.h"
9 10
11#ifdef CONFIG_FAIL_IO_TIMEOUT
12
13static DECLARE_FAULT_ATTR(fail_io_timeout);
14
15static int __init setup_fail_io_timeout(char *str)
16{
17 return setup_fault_attr(&fail_io_timeout, str);
18}
19__setup("fail_io_timeout=", setup_fail_io_timeout);
20
21int blk_should_fake_timeout(struct request_queue *q)
22{
23 if (!test_bit(QUEUE_FLAG_FAIL_IO, &q->queue_flags))
24 return 0;
25
26 return should_fail(&fail_io_timeout, 1);
27}
28
29static int __init fail_io_timeout_debugfs(void)
30{
31 return init_fault_attr_dentries(&fail_io_timeout, "fail_io_timeout");
32}
33
34late_initcall(fail_io_timeout_debugfs);
35
36ssize_t part_timeout_show(struct device *dev, struct device_attribute *attr,
37 char *buf)
38{
39 struct gendisk *disk = dev_to_disk(dev);
40 int set = test_bit(QUEUE_FLAG_FAIL_IO, &disk->queue->queue_flags);
41
42 return sprintf(buf, "%d\n", set != 0);
43}
44
45ssize_t part_timeout_store(struct device *dev, struct device_attribute *attr,
46 const char *buf, size_t count)
47{
48 struct gendisk *disk = dev_to_disk(dev);
49 int val;
50
51 if (count) {
52 struct request_queue *q = disk->queue;
53 char *p = (char *) buf;
54
55 val = simple_strtoul(p, &p, 10);
56 spin_lock_irq(q->queue_lock);
57 if (val)
58 queue_flag_set(QUEUE_FLAG_FAIL_IO, q);
59 else
60 queue_flag_clear(QUEUE_FLAG_FAIL_IO, q);
61 spin_unlock_irq(q->queue_lock);
62 }
63
64 return count;
65}
66
67#endif /* CONFIG_FAIL_IO_TIMEOUT */
68
10/* 69/*
11 * blk_delete_timer - Delete/cancel timer for a given function. 70 * blk_delete_timer - Delete/cancel timer for a given function.
12 * @req: request that we are canceling timer for 71 * @req: request that we are canceling timer for
diff --git a/block/blk.h b/block/blk.h
index a4f4a50aefaa..e5c579769963 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -42,6 +42,18 @@ static inline void blk_clear_rq_complete(struct request *rq)
42 clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags); 42 clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags);
43} 43}
44 44
45#ifdef CONFIG_FAIL_IO_TIMEOUT
46int blk_should_fake_timeout(struct request_queue *);
47ssize_t part_timeout_show(struct device *, struct device_attribute *, char *);
48ssize_t part_timeout_store(struct device *, struct device_attribute *,
49 const char *, size_t);
50#else
51static inline int blk_should_fake_timeout(struct request_queue *q)
52{
53 return 0;
54}
55#endif
56
45struct io_context *current_io_context(gfp_t gfp_flags, int node); 57struct io_context *current_io_context(gfp_t gfp_flags, int node);
46 58
47int ll_back_merge_fn(struct request_queue *q, struct request *req, 59int ll_back_merge_fn(struct request_queue *q, struct request *req,
diff --git a/block/genhd.c b/block/genhd.c
index 8acaff0154e3..4cd3433c99ac 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -817,6 +817,11 @@ static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
817static struct device_attribute dev_attr_fail = 817static struct device_attribute dev_attr_fail =
818 __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); 818 __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
819#endif 819#endif
820#ifdef CONFIG_FAIL_IO_TIMEOUT
821static struct device_attribute dev_attr_fail_timeout =
822 __ATTR(io-timeout-fail, S_IRUGO|S_IWUSR, part_timeout_show,
823 part_timeout_store);
824#endif
820 825
821static struct attribute *disk_attrs[] = { 826static struct attribute *disk_attrs[] = {
822 &dev_attr_range.attr, 827 &dev_attr_range.attr,
@@ -829,6 +834,9 @@ static struct attribute *disk_attrs[] = {
829#ifdef CONFIG_FAIL_MAKE_REQUEST 834#ifdef CONFIG_FAIL_MAKE_REQUEST
830 &dev_attr_fail.attr, 835 &dev_attr_fail.attr,
831#endif 836#endif
837#ifdef CONFIG_FAIL_IO_TIMEOUT
838 &dev_attr_fail_timeout.attr,
839#endif
832 NULL 840 NULL
833}; 841};
834 842
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index b47767c72ce3..e34999d14c16 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -440,6 +440,7 @@ struct request_queue
440#define QUEUE_FLAG_BIDI 9 /* queue supports bidi requests */ 440#define QUEUE_FLAG_BIDI 9 /* queue supports bidi requests */
441#define QUEUE_FLAG_NOMERGES 10 /* disable merge attempts */ 441#define QUEUE_FLAG_NOMERGES 10 /* disable merge attempts */
442#define QUEUE_FLAG_SAME_COMP 11 /* force complete on same CPU */ 442#define QUEUE_FLAG_SAME_COMP 11 /* force complete on same CPU */
443#define QUEUE_FLAG_FAIL_IO 12 /* fake timeout */
443 444
444static inline int queue_is_locked(struct request_queue *q) 445static inline int queue_is_locked(struct request_queue *q)
445{ 446{
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index c556896abe57..7d7a31d0ddeb 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -683,10 +683,21 @@ config FAIL_PAGE_ALLOC
683 683
684config FAIL_MAKE_REQUEST 684config FAIL_MAKE_REQUEST
685 bool "Fault-injection capability for disk IO" 685 bool "Fault-injection capability for disk IO"
686 depends on FAULT_INJECTION 686 depends on FAULT_INJECTION && BLOCK
687 help 687 help
688 Provide fault-injection capability for disk IO. 688 Provide fault-injection capability for disk IO.
689 689
690config FAIL_IO_TIMEOUT
691 bool "Faul-injection capability for faking disk interrupts"
692 depends on FAULT_INJECTION && BLOCK
693 help
694 Provide fault-injection capability on end IO handling. This
695 will make the block layer "forget" an interrupt as configured,
696 thus exercising the error handling.
697
698 Only works with drivers that use the generic timeout handling,
699 for others it wont do anything.
700
690config FAULT_INJECTION_DEBUG_FS 701config FAULT_INJECTION_DEBUG_FS
691 bool "Debugfs entries for fault-injection capabilities" 702 bool "Debugfs entries for fault-injection capabilities"
692 depends on FAULT_INJECTION && SYSFS && DEBUG_FS 703 depends on FAULT_INJECTION && SYSFS && DEBUG_FS