History

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.

Jens Axboe committed 18 years ago

Commit 581d4e21 parent 0a0d96b6 files · +94 −1Browse files

Unified · Split

6 files
  1. block/blk-softirq.c +2 −0
  2. block/blk-timeout.c +59 −0
  3. block/blk.h +12 −0
  4. block/genhd.c +8 −0
  5. include/linux/blkdev.h +1 −0
  6. lib/Kconfig.debug +12 −1
block/blk-softirq.c+2−0
@@ -154,6 +154,8 @@ do_local: · 153 unmodified lines
154154 **/
155155 void blk_complete_request(struct request *req)
156156 {
157+ if (unlikely(blk_should_fake_timeout(req->q)))
158+ return;
157159 if (!blk_mark_rq_complete(req))
158160 __blk_complete_request(req);
159161 }
block/blk-timeout.c+59−0
@@ -4,9 +4,68 @@ · 3 unmodified lines
44 #include <linux/kernel.h>
55 #include <linux/module.h>
66 #include <linux/blkdev.h>
7+#include <linux/fault-inject.h>
78
89 #include "blk.h"
910
11+#ifdef CONFIG_FAIL_IO_TIMEOUT
12+
13+static DECLARE_FAULT_ATTR(fail_io_timeout);
14+
15+static 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+
21+int 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+
29+static int __init fail_io_timeout_debugfs(void)
30+{
31+ return init_fault_attr_dentries(&fail_io_timeout, "fail_io_timeout");
32+}
33+
34+late_initcall(fail_io_timeout_debugfs);
35+
36+ssize_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+
45+ssize_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+
1069 /*
1170 * blk_delete_timer - Delete/cancel timer for a given function.
1271 * @req: request that we are canceling timer for
block/blk.h+12−0
@@ -42,6 +42,18 @@ static inline void blk_clear_rq_complete(struct request *rq) · 41 unmodified lines
4242 clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags);
4343 }
4444
45+#ifdef CONFIG_FAIL_IO_TIMEOUT
46+int blk_should_fake_timeout(struct request_queue *);
47+ssize_t part_timeout_show(struct device *, struct device_attribute *, char *);
48+ssize_t part_timeout_store(struct device *, struct device_attribute *,
49+ const char *, size_t);
50+#else
51+static inline int blk_should_fake_timeout(struct request_queue *q)
52+{
53+ return 0;
54+}
55+#endif
56+
4557 struct io_context *current_io_context(gfp_t gfp_flags, int node);
4658
4759 int ll_back_merge_fn(struct request_queue *q, struct request *req,
block/genhd.c+8−0
@@ -817,6 +817,11 @@ static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); · 816 unmodified lines
817817 static struct device_attribute dev_attr_fail =
818818 __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
819819 #endif
820+#ifdef CONFIG_FAIL_IO_TIMEOUT
821+static 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
820825
821826 static struct attribute *disk_attrs[] = {
822827 &dev_attr_range.attr,
@@ -828,6 +833,9 @@ static struct attribute *disk_attrs[] = { · 5 unmodified lines
828833 &dev_attr_stat.attr,
829834 #ifdef CONFIG_FAIL_MAKE_REQUEST
830835 &dev_attr_fail.attr,
836+#endif
837+#ifdef CONFIG_FAIL_IO_TIMEOUT
838+ &dev_attr_fail_timeout.attr,
831839 #endif
832840 NULL
833841 };
include/linux/blkdev.h+1−0
@@ -440,6 +440,7 @@ struct request_queue · 439 unmodified lines
440440 #define QUEUE_FLAG_BIDI 9 /* queue supports bidi requests */
441441 #define QUEUE_FLAG_NOMERGES 10 /* disable merge attempts */
442442 #define QUEUE_FLAG_SAME_COMP 11 /* force complete on same CPU */
443+#define QUEUE_FLAG_FAIL_IO 12 /* fake timeout */
443444
444445 static inline int queue_is_locked(struct request_queue *q)
445446 {
lib/Kconfig.debug+12−1
@@ -683,10 +683,21 @@ config FAIL_PAGE_ALLOC · 682 unmodified lines
683683
684684 config FAIL_MAKE_REQUEST
685685 bool "Fault-injection capability for disk IO"
686− depends on FAULT_INJECTION
686+ depends on FAULT_INJECTION && BLOCK
687687 help
688688 Provide fault-injection capability for disk IO.
689689
690+config 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+
690701 config FAULT_INJECTION_DEBUG_FS
691702 bool "Debugfs entries for fault-injection capabilities"
692703 depends on FAULT_INJECTION && SYSFS && DEBUG_FS