diff options
author | Josef Bacik <josef@redhat.com> | 2012-03-26 21:57:36 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-03-26 21:57:36 -0400 |
commit | ea466794084f55d8fcc100711cf17923bf57e962 (patch) | |
tree | 9905d556655ff0f036936ea51f9aa214bd2cbce8 /fs/btrfs/disk-io.c | |
parent | f3f266ab1bfe4770375d24fa8e72a03278e9450a (diff) |
Btrfs: deal with read errors on extent buffers differently
Since we need to read and write extent buffers in their entirety we can't use
the normal bio_readpage_error stuff since it only works on a per page basis. So
instead make it so that if we see an io error in endio we just mark the eb as
having an IO error and then in btree_read_extent_buffer_pages we will manually
try other mirrors and then overwrite the bad mirror if we find a good copy.
This works with larger than page size blocks. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 43 |
1 files changed, 29 insertions, 14 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 53c5ea702799..6107b6958413 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -360,9 +360,11 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, | |||
360 | u64 start, u64 parent_transid) | 360 | u64 start, u64 parent_transid) |
361 | { | 361 | { |
362 | struct extent_io_tree *io_tree; | 362 | struct extent_io_tree *io_tree; |
363 | int failed = 0; | ||
363 | int ret; | 364 | int ret; |
364 | int num_copies = 0; | 365 | int num_copies = 0; |
365 | int mirror_num = 0; | 366 | int mirror_num = 0; |
367 | int failed_mirror = 0; | ||
366 | 368 | ||
367 | clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); | 369 | clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); |
368 | io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; | 370 | io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; |
@@ -371,7 +373,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, | |||
371 | WAIT_COMPLETE, | 373 | WAIT_COMPLETE, |
372 | btree_get_extent, mirror_num); | 374 | btree_get_extent, mirror_num); |
373 | if (!ret && !verify_parent_transid(io_tree, eb, parent_transid)) | 375 | if (!ret && !verify_parent_transid(io_tree, eb, parent_transid)) |
374 | return ret; | 376 | break; |
375 | 377 | ||
376 | /* | 378 | /* |
377 | * This buffer's crc is fine, but its contents are corrupted, so | 379 | * This buffer's crc is fine, but its contents are corrupted, so |
@@ -379,18 +381,31 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, | |||
379 | * any less wrong. | 381 | * any less wrong. |
380 | */ | 382 | */ |
381 | if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) | 383 | if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) |
382 | return ret; | 384 | break; |
385 | |||
386 | if (!failed_mirror) { | ||
387 | failed = 1; | ||
388 | printk(KERN_ERR "failed mirror was %d\n", eb->failed_mirror); | ||
389 | failed_mirror = eb->failed_mirror; | ||
390 | } | ||
383 | 391 | ||
384 | num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, | 392 | num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, |
385 | eb->start, eb->len); | 393 | eb->start, eb->len); |
386 | if (num_copies == 1) | 394 | if (num_copies == 1) |
387 | return ret; | 395 | break; |
388 | 396 | ||
389 | mirror_num++; | 397 | mirror_num++; |
398 | if (mirror_num == failed_mirror) | ||
399 | mirror_num++; | ||
400 | |||
390 | if (mirror_num > num_copies) | 401 | if (mirror_num > num_copies) |
391 | return ret; | 402 | break; |
392 | } | 403 | } |
393 | return -EIO; | 404 | |
405 | if (failed && !ret) | ||
406 | repair_eb_io_failure(root, eb, failed_mirror); | ||
407 | |||
408 | return ret; | ||
394 | } | 409 | } |
395 | 410 | ||
396 | /* | 411 | /* |
@@ -575,6 +590,11 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | |||
575 | if (!reads_done) | 590 | if (!reads_done) |
576 | goto err; | 591 | goto err; |
577 | 592 | ||
593 | if (test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) { | ||
594 | ret = -EIO; | ||
595 | goto err; | ||
596 | } | ||
597 | |||
578 | found_start = btrfs_header_bytenr(eb); | 598 | found_start = btrfs_header_bytenr(eb); |
579 | if (found_start != eb->start) { | 599 | if (found_start != eb->start) { |
580 | printk_ratelimited(KERN_INFO "btrfs bad tree block start " | 600 | printk_ratelimited(KERN_INFO "btrfs bad tree block start " |
@@ -626,21 +646,16 @@ out: | |||
626 | return ret; | 646 | return ret; |
627 | } | 647 | } |
628 | 648 | ||
629 | static int btree_io_failed_hook(struct bio *failed_bio, | 649 | static int btree_io_failed_hook(struct page *page, int failed_mirror) |
630 | struct page *page, u64 start, u64 end, | ||
631 | int mirror_num, struct extent_state *state) | ||
632 | { | 650 | { |
633 | struct extent_buffer *eb; | 651 | struct extent_buffer *eb; |
634 | struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; | 652 | struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; |
635 | 653 | ||
636 | eb = (struct extent_buffer *)page->private; | 654 | eb = (struct extent_buffer *)page->private; |
637 | if (page != eb->pages[0]) | 655 | set_bit(EXTENT_BUFFER_IOERR, &eb->bflags); |
638 | return -EIO; | 656 | eb->failed_mirror = failed_mirror; |
639 | 657 | if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) | |
640 | if (test_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) { | ||
641 | clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags); | ||
642 | btree_readahead_hook(root, eb, eb->start, -EIO); | 658 | btree_readahead_hook(root, eb, eb->start, -EIO); |
643 | } | ||
644 | return -EIO; /* we fixed nothing */ | 659 | return -EIO; /* we fixed nothing */ |
645 | } | 660 | } |
646 | 661 | ||