diff options
| author | Akinobu Mita <akinobu.mita@gmail.com> | 2006-12-08 05:39:46 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-08 11:29:02 -0500 |
| commit | c17bb4951752d3e0f49cd1ea9d2e868422f9e0d6 (patch) | |
| tree | dcd23ef706ba09edae462528dc11a507b1d17af6 | |
| parent | 933e312e73f8fc39652bd4d216a5393cc3a014b9 (diff) | |
[PATCH] fault-injection capability for disk IO
This patch provides fault-injection capability for disk IO.
Boot option:
fail_make_request=<probability>,<interval>,<space>,<times>
<interval> -- specifies the interval of failures.
<probability> -- specifies how often it should fail in percent.
<space> -- specifies the size of free space where disk IO can be issued
safely in bytes.
<times> -- specifies how many times failures may happen at most.
Debugfs:
/debug/fail_make_request/interval
/debug/fail_make_request/probability
/debug/fail_make_request/specifies
/debug/fail_make_request/times
Example:
fail_make_request=10,100,0,-1
echo 1 > /sys/blocks/hda/hda1/make-it-fail
generic_make_request() on /dev/hda1 fails once per 10 times.
Cc: Jens Axboe <axboe@suse.de>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | block/genhd.c | 31 | ||||
| -rw-r--r-- | block/ll_rw_blk.c | 40 | ||||
| -rw-r--r-- | fs/partitions/check.c | 27 | ||||
| -rw-r--r-- | include/linux/genhd.h | 4 | ||||
| -rw-r--r-- | lib/Kconfig.debug | 7 |
5 files changed, 109 insertions, 0 deletions
diff --git a/block/genhd.c b/block/genhd.c index 653919d50cd4..457fdac4c17d 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
| @@ -417,6 +417,34 @@ static struct disk_attribute disk_attr_stat = { | |||
| 417 | .show = disk_stats_read | 417 | .show = disk_stats_read |
| 418 | }; | 418 | }; |
| 419 | 419 | ||
| 420 | #ifdef CONFIG_FAIL_MAKE_REQUEST | ||
| 421 | |||
| 422 | static ssize_t disk_fail_store(struct gendisk * disk, | ||
| 423 | const char *buf, size_t count) | ||
| 424 | { | ||
| 425 | int i; | ||
| 426 | |||
| 427 | if (count > 0 && sscanf(buf, "%d", &i) > 0) { | ||
| 428 | if (i == 0) | ||
| 429 | disk->flags &= ~GENHD_FL_FAIL; | ||
| 430 | else | ||
| 431 | disk->flags |= GENHD_FL_FAIL; | ||
| 432 | } | ||
| 433 | |||
| 434 | return count; | ||
| 435 | } | ||
| 436 | static ssize_t disk_fail_read(struct gendisk * disk, char *page) | ||
| 437 | { | ||
| 438 | return sprintf(page, "%d\n", disk->flags & GENHD_FL_FAIL ? 1 : 0); | ||
| 439 | } | ||
| 440 | static struct disk_attribute disk_attr_fail = { | ||
| 441 | .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR }, | ||
| 442 | .store = disk_fail_store, | ||
| 443 | .show = disk_fail_read | ||
| 444 | }; | ||
| 445 | |||
| 446 | #endif | ||
| 447 | |||
| 420 | static struct attribute * default_attrs[] = { | 448 | static struct attribute * default_attrs[] = { |
| 421 | &disk_attr_uevent.attr, | 449 | &disk_attr_uevent.attr, |
| 422 | &disk_attr_dev.attr, | 450 | &disk_attr_dev.attr, |
| @@ -424,6 +452,9 @@ static struct attribute * default_attrs[] = { | |||
| 424 | &disk_attr_removable.attr, | 452 | &disk_attr_removable.attr, |
| 425 | &disk_attr_size.attr, | 453 | &disk_attr_size.attr, |
| 426 | &disk_attr_stat.attr, | 454 | &disk_attr_stat.attr, |
| 455 | #ifdef CONFIG_FAIL_MAKE_REQUEST | ||
| 456 | &disk_attr_fail.attr, | ||
| 457 | #endif | ||
| 427 | NULL, | 458 | NULL, |
| 428 | }; | 459 | }; |
| 429 | 460 | ||
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 31512cd9f3ad..4f83fd922377 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
| 29 | #include <linux/cpu.h> | 29 | #include <linux/cpu.h> |
| 30 | #include <linux/blktrace_api.h> | 30 | #include <linux/blktrace_api.h> |
| 31 | #include <linux/fault-inject.h> | ||
| 31 | 32 | ||
| 32 | /* | 33 | /* |
| 33 | * for max sense size | 34 | * for max sense size |
| @@ -3056,6 +3057,42 @@ static void handle_bad_sector(struct bio *bio) | |||
| 3056 | set_bit(BIO_EOF, &bio->bi_flags); | 3057 | set_bit(BIO_EOF, &bio->bi_flags); |
| 3057 | } | 3058 | } |
| 3058 | 3059 | ||
| 3060 | #ifdef CONFIG_FAIL_MAKE_REQUEST | ||
| 3061 | |||
| 3062 | static DECLARE_FAULT_ATTR(fail_make_request); | ||
| 3063 | |||
| 3064 | static int __init setup_fail_make_request(char *str) | ||
| 3065 | { | ||
| 3066 | return setup_fault_attr(&fail_make_request, str); | ||
| 3067 | } | ||
| 3068 | __setup("fail_make_request=", setup_fail_make_request); | ||
| 3069 | |||
| 3070 | static int should_fail_request(struct bio *bio) | ||
| 3071 | { | ||
| 3072 | if ((bio->bi_bdev->bd_disk->flags & GENHD_FL_FAIL) || | ||
| 3073 | (bio->bi_bdev->bd_part && bio->bi_bdev->bd_part->make_it_fail)) | ||
| 3074 | return should_fail(&fail_make_request, bio->bi_size); | ||
| 3075 | |||
| 3076 | return 0; | ||
| 3077 | } | ||
| 3078 | |||
| 3079 | static int __init fail_make_request_debugfs(void) | ||
| 3080 | { | ||
| 3081 | return init_fault_attr_dentries(&fail_make_request, | ||
| 3082 | "fail_make_request"); | ||
| 3083 | } | ||
| 3084 | |||
| 3085 | late_initcall(fail_make_request_debugfs); | ||
| 3086 | |||
| 3087 | #else /* CONFIG_FAIL_MAKE_REQUEST */ | ||
| 3088 | |||
| 3089 | static inline int should_fail_request(struct bio *bio) | ||
| 3090 | { | ||
| 3091 | return 0; | ||
| 3092 | } | ||
| 3093 | |||
| 3094 | #endif /* CONFIG_FAIL_MAKE_REQUEST */ | ||
| 3095 | |||
| 3059 | /** | 3096 | /** |
| 3060 | * generic_make_request: hand a buffer to its device driver for I/O | 3097 | * generic_make_request: hand a buffer to its device driver for I/O |
| 3061 | * @bio: The bio describing the location in memory and on the device. | 3098 | * @bio: The bio describing the location in memory and on the device. |
| @@ -3141,6 +3178,9 @@ end_io: | |||
| 3141 | if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) | 3178 | if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) |
| 3142 | goto end_io; | 3179 | goto end_io; |
| 3143 | 3180 | ||
| 3181 | if (should_fail_request(bio)) | ||
| 3182 | goto end_io; | ||
| 3183 | |||
| 3144 | /* | 3184 | /* |
| 3145 | * If this device has partitions, remap block n | 3185 | * If this device has partitions, remap block n |
| 3146 | * of partition p to block n+start(p) of the disk. | 3186 | * of partition p to block n+start(p) of the disk. |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 1901137f4eca..3d73d94d93a7 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
| @@ -276,12 +276,39 @@ static struct part_attribute part_attr_stat = { | |||
| 276 | .show = part_stat_read | 276 | .show = part_stat_read |
| 277 | }; | 277 | }; |
| 278 | 278 | ||
| 279 | #ifdef CONFIG_FAIL_MAKE_REQUEST | ||
| 280 | |||
| 281 | static ssize_t part_fail_store(struct hd_struct * p, | ||
| 282 | const char *buf, size_t count) | ||
| 283 | { | ||
| 284 | int i; | ||
| 285 | |||
| 286 | if (count > 0 && sscanf(buf, "%d", &i) > 0) | ||
| 287 | p->make_it_fail = (i == 0) ? 0 : 1; | ||
| 288 | |||
| 289 | return count; | ||
| 290 | } | ||
| 291 | static ssize_t part_fail_read(struct hd_struct * p, char *page) | ||
| 292 | { | ||
| 293 | return sprintf(page, "%d\n", p->make_it_fail); | ||
| 294 | } | ||
| 295 | static struct part_attribute part_attr_fail = { | ||
| 296 | .attr = {.name = "make-it-fail", .mode = S_IRUGO | S_IWUSR }, | ||
| 297 | .store = part_fail_store, | ||
| 298 | .show = part_fail_read | ||
| 299 | }; | ||
| 300 | |||
| 301 | #endif | ||
| 302 | |||
| 279 | static struct attribute * default_attrs[] = { | 303 | static struct attribute * default_attrs[] = { |
| 280 | &part_attr_uevent.attr, | 304 | &part_attr_uevent.attr, |
| 281 | &part_attr_dev.attr, | 305 | &part_attr_dev.attr, |
| 282 | &part_attr_start.attr, | 306 | &part_attr_start.attr, |
| 283 | &part_attr_size.attr, | 307 | &part_attr_size.attr, |
| 284 | &part_attr_stat.attr, | 308 | &part_attr_stat.attr, |
| 309 | #ifdef CONFIG_FAIL_MAKE_REQUEST | ||
| 310 | &part_attr_fail.attr, | ||
| 311 | #endif | ||
| 285 | NULL, | 312 | NULL, |
| 286 | }; | 313 | }; |
| 287 | 314 | ||
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 41f276fdd185..0a022b2f63fc 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
| @@ -83,6 +83,9 @@ struct hd_struct { | |||
| 83 | struct kobject *holder_dir; | 83 | struct kobject *holder_dir; |
| 84 | unsigned ios[2], sectors[2]; /* READs and WRITEs */ | 84 | unsigned ios[2], sectors[2]; /* READs and WRITEs */ |
| 85 | int policy, partno; | 85 | int policy, partno; |
| 86 | #ifdef CONFIG_FAIL_MAKE_REQUEST | ||
| 87 | int make_it_fail; | ||
| 88 | #endif | ||
| 86 | }; | 89 | }; |
| 87 | 90 | ||
| 88 | #define GENHD_FL_REMOVABLE 1 | 91 | #define GENHD_FL_REMOVABLE 1 |
| @@ -90,6 +93,7 @@ struct hd_struct { | |||
| 90 | #define GENHD_FL_CD 8 | 93 | #define GENHD_FL_CD 8 |
| 91 | #define GENHD_FL_UP 16 | 94 | #define GENHD_FL_UP 16 |
| 92 | #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 | 95 | #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 |
| 96 | #define GENHD_FL_FAIL 64 | ||
| 93 | 97 | ||
| 94 | struct disk_stats { | 98 | struct disk_stats { |
| 95 | unsigned long sectors[2]; /* READs and WRITEs */ | 99 | unsigned long sectors[2]; /* READs and WRITEs */ |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c66b7b400c9f..336241bf0ced 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
| @@ -431,6 +431,13 @@ config FAIL_PAGE_ALLOC | |||
| 431 | help | 431 | help |
| 432 | This option provides fault-injection capabilitiy for alloc_pages(). | 432 | This option provides fault-injection capabilitiy for alloc_pages(). |
| 433 | 433 | ||
| 434 | config FAIL_MAKE_REQUEST | ||
| 435 | bool "Fault-injection capabilitiy for disk IO" | ||
| 436 | depends on DEBUG_KERNEL | ||
| 437 | select FAULT_INJECTION | ||
| 438 | help | ||
| 439 | This option provides fault-injection capabilitiy to disk IO. | ||
| 440 | |||
| 434 | config FAULT_INJECTION_DEBUG_FS | 441 | config FAULT_INJECTION_DEBUG_FS |
| 435 | bool "Debugfs entries for fault-injection capabilities" | 442 | bool "Debugfs entries for fault-injection capabilities" |
| 436 | depends on FAULT_INJECTION && SYSFS | 443 | depends on FAULT_INJECTION && SYSFS |
