diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
| -rw-r--r-- | fs/btrfs/disk-io.c | 40 |
1 files changed, 24 insertions, 16 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 09ef25f0c6c7..e1fe74a2ce16 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -323,7 +323,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | |||
| 323 | * in the wrong place. | 323 | * in the wrong place. |
| 324 | */ | 324 | */ |
| 325 | static int verify_parent_transid(struct extent_io_tree *io_tree, | 325 | static int verify_parent_transid(struct extent_io_tree *io_tree, |
| 326 | struct extent_buffer *eb, u64 parent_transid) | 326 | struct extent_buffer *eb, u64 parent_transid, |
| 327 | int atomic) | ||
| 327 | { | 328 | { |
| 328 | struct extent_state *cached_state = NULL; | 329 | struct extent_state *cached_state = NULL; |
| 329 | int ret; | 330 | int ret; |
| @@ -331,6 +332,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree, | |||
| 331 | if (!parent_transid || btrfs_header_generation(eb) == parent_transid) | 332 | if (!parent_transid || btrfs_header_generation(eb) == parent_transid) |
| 332 | return 0; | 333 | return 0; |
| 333 | 334 | ||
| 335 | if (atomic) | ||
| 336 | return -EAGAIN; | ||
| 337 | |||
| 334 | lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1, | 338 | lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1, |
| 335 | 0, &cached_state); | 339 | 0, &cached_state); |
| 336 | if (extent_buffer_uptodate(eb) && | 340 | if (extent_buffer_uptodate(eb) && |
| @@ -372,7 +376,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, | |||
| 372 | ret = read_extent_buffer_pages(io_tree, eb, start, | 376 | ret = read_extent_buffer_pages(io_tree, eb, start, |
| 373 | WAIT_COMPLETE, | 377 | WAIT_COMPLETE, |
| 374 | btree_get_extent, mirror_num); | 378 | btree_get_extent, mirror_num); |
| 375 | if (!ret && !verify_parent_transid(io_tree, eb, parent_transid)) | 379 | if (!ret && !verify_parent_transid(io_tree, eb, |
| 380 | parent_transid, 0)) | ||
| 376 | break; | 381 | break; |
| 377 | 382 | ||
| 378 | /* | 383 | /* |
| @@ -383,17 +388,16 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root, | |||
| 383 | if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) | 388 | if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) |
| 384 | break; | 389 | break; |
| 385 | 390 | ||
| 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 | } | ||
| 391 | |||
| 392 | num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, | 391 | num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, |
| 393 | eb->start, eb->len); | 392 | eb->start, eb->len); |
| 394 | if (num_copies == 1) | 393 | if (num_copies == 1) |
| 395 | break; | 394 | break; |
| 396 | 395 | ||
| 396 | if (!failed_mirror) { | ||
| 397 | failed = 1; | ||
| 398 | failed_mirror = eb->read_mirror; | ||
| 399 | } | ||
| 400 | |||
| 397 | mirror_num++; | 401 | mirror_num++; |
| 398 | if (mirror_num == failed_mirror) | 402 | if (mirror_num == failed_mirror) |
| 399 | mirror_num++; | 403 | mirror_num++; |
| @@ -564,7 +568,7 @@ struct extent_buffer *find_eb_for_page(struct extent_io_tree *tree, | |||
| 564 | } | 568 | } |
| 565 | 569 | ||
| 566 | static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | 570 | static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, |
| 567 | struct extent_state *state) | 571 | struct extent_state *state, int mirror) |
| 568 | { | 572 | { |
| 569 | struct extent_io_tree *tree; | 573 | struct extent_io_tree *tree; |
| 570 | u64 found_start; | 574 | u64 found_start; |
| @@ -589,6 +593,7 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | |||
| 589 | if (!reads_done) | 593 | if (!reads_done) |
| 590 | goto err; | 594 | goto err; |
| 591 | 595 | ||
| 596 | eb->read_mirror = mirror; | ||
| 592 | if (test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) { | 597 | if (test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) { |
| 593 | ret = -EIO; | 598 | ret = -EIO; |
| 594 | goto err; | 599 | goto err; |
| @@ -652,7 +657,7 @@ static int btree_io_failed_hook(struct page *page, int failed_mirror) | |||
| 652 | 657 | ||
| 653 | eb = (struct extent_buffer *)page->private; | 658 | eb = (struct extent_buffer *)page->private; |
| 654 | set_bit(EXTENT_BUFFER_IOERR, &eb->bflags); | 659 | set_bit(EXTENT_BUFFER_IOERR, &eb->bflags); |
| 655 | eb->failed_mirror = failed_mirror; | 660 | eb->read_mirror = failed_mirror; |
| 656 | if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) | 661 | if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) |
| 657 | btree_readahead_hook(root, eb, eb->start, -EIO); | 662 | btree_readahead_hook(root, eb, eb->start, -EIO); |
| 658 | return -EIO; /* we fixed nothing */ | 663 | return -EIO; /* we fixed nothing */ |
| @@ -1202,7 +1207,7 @@ static int __must_check find_and_setup_root(struct btrfs_root *tree_root, | |||
| 1202 | root->commit_root = NULL; | 1207 | root->commit_root = NULL; |
| 1203 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), | 1208 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), |
| 1204 | blocksize, generation); | 1209 | blocksize, generation); |
| 1205 | if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { | 1210 | if (!root->node || !btrfs_buffer_uptodate(root->node, generation, 0)) { |
| 1206 | free_extent_buffer(root->node); | 1211 | free_extent_buffer(root->node); |
| 1207 | root->node = NULL; | 1212 | root->node = NULL; |
| 1208 | return -EIO; | 1213 | return -EIO; |
| @@ -2254,9 +2259,9 @@ int open_ctree(struct super_block *sb, | |||
| 2254 | goto fail_sb_buffer; | 2259 | goto fail_sb_buffer; |
| 2255 | } | 2260 | } |
| 2256 | 2261 | ||
| 2257 | if (sectorsize < PAGE_SIZE) { | 2262 | if (sectorsize != PAGE_SIZE) { |
| 2258 | printk(KERN_WARNING "btrfs: Incompatible sector size " | 2263 | printk(KERN_WARNING "btrfs: Incompatible sector size(%lu) " |
| 2259 | "found on %s\n", sb->s_id); | 2264 | "found on %s\n", (unsigned long)sectorsize, sb->s_id); |
| 2260 | goto fail_sb_buffer; | 2265 | goto fail_sb_buffer; |
| 2261 | } | 2266 | } |
| 2262 | 2267 | ||
| @@ -3143,7 +3148,8 @@ int close_ctree(struct btrfs_root *root) | |||
| 3143 | return 0; | 3148 | return 0; |
| 3144 | } | 3149 | } |
| 3145 | 3150 | ||
| 3146 | int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) | 3151 | int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, |
| 3152 | int atomic) | ||
| 3147 | { | 3153 | { |
| 3148 | int ret; | 3154 | int ret; |
| 3149 | struct inode *btree_inode = buf->pages[0]->mapping->host; | 3155 | struct inode *btree_inode = buf->pages[0]->mapping->host; |
| @@ -3153,7 +3159,9 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) | |||
| 3153 | return ret; | 3159 | return ret; |
| 3154 | 3160 | ||
| 3155 | ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf, | 3161 | ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf, |
| 3156 | parent_transid); | 3162 | parent_transid, atomic); |
| 3163 | if (ret == -EAGAIN) | ||
| 3164 | return ret; | ||
| 3157 | return !ret; | 3165 | return !ret; |
| 3158 | } | 3166 | } |
| 3159 | 3167 | ||
