diff options
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 | ||