diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-09 16:28:12 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | f188591e987e21b6f7f8864c66a02858b95b530e (patch) | |
tree | 996f04b7c8d1e8a626b123e7a2a217992d705c60 /fs/btrfs/extent_io.c | |
parent | 22c599485b1fdd95e4476a4752596a6cf6c6629a (diff) |
Btrfs: Retry metadata reads in the face of checksum failures
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 50 |
1 files changed, 29 insertions, 21 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index cfc383c17a3a..2f159375c878 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -1546,7 +1546,7 @@ static int end_bio_extent_readpage(struct bio *bio, | |||
1546 | !(state->state & EXTENT_LOCKED)) | 1546 | !(state->state & EXTENT_LOCKED)) |
1547 | state = NULL; | 1547 | state = NULL; |
1548 | } | 1548 | } |
1549 | if (!state) { | 1549 | if (!state && uptodate) { |
1550 | spin_unlock_irqrestore(&tree->lock, flags); | 1550 | spin_unlock_irqrestore(&tree->lock, flags); |
1551 | set_extent_uptodate(tree, start, end, | 1551 | set_extent_uptodate(tree, start, end, |
1552 | GFP_ATOMIC); | 1552 | GFP_ATOMIC); |
@@ -1567,8 +1567,10 @@ static int end_bio_extent_readpage(struct bio *bio, | |||
1567 | } else { | 1567 | } else { |
1568 | state = NULL; | 1568 | state = NULL; |
1569 | } | 1569 | } |
1570 | set_state_cb(tree, clear, EXTENT_UPTODATE); | 1570 | if (uptodate) { |
1571 | clear->state |= EXTENT_UPTODATE; | 1571 | set_state_cb(tree, clear, EXTENT_UPTODATE); |
1572 | clear->state |= EXTENT_UPTODATE; | ||
1573 | } | ||
1572 | clear_state_bit(tree, clear, EXTENT_LOCKED, | 1574 | clear_state_bit(tree, clear, EXTENT_LOCKED, |
1573 | 1, 0); | 1575 | 1, 0); |
1574 | if (cur == start) | 1576 | if (cur == start) |
@@ -1685,7 +1687,7 @@ extent_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, | |||
1685 | return bio; | 1687 | return bio; |
1686 | } | 1688 | } |
1687 | 1689 | ||
1688 | static int submit_one_bio(int rw, struct bio *bio) | 1690 | static int submit_one_bio(int rw, struct bio *bio, int mirror_num) |
1689 | { | 1691 | { |
1690 | u64 maxsector; | 1692 | u64 maxsector; |
1691 | int ret = 0; | 1693 | int ret = 0; |
@@ -1722,7 +1724,8 @@ static int submit_one_bio(int rw, struct bio *bio) | |||
1722 | WARN_ON(1); | 1724 | WARN_ON(1); |
1723 | } | 1725 | } |
1724 | if (tree->ops && tree->ops->submit_bio_hook) | 1726 | if (tree->ops && tree->ops->submit_bio_hook) |
1725 | tree->ops->submit_bio_hook(page->mapping->host, rw, bio); | 1727 | tree->ops->submit_bio_hook(page->mapping->host, rw, bio, |
1728 | mirror_num); | ||
1726 | else | 1729 | else |
1727 | submit_bio(rw, bio); | 1730 | submit_bio(rw, bio); |
1728 | if (bio_flagged(bio, BIO_EOPNOTSUPP)) | 1731 | if (bio_flagged(bio, BIO_EOPNOTSUPP)) |
@@ -1737,7 +1740,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, | |||
1737 | struct block_device *bdev, | 1740 | struct block_device *bdev, |
1738 | struct bio **bio_ret, | 1741 | struct bio **bio_ret, |
1739 | unsigned long max_pages, | 1742 | unsigned long max_pages, |
1740 | bio_end_io_t end_io_func) | 1743 | bio_end_io_t end_io_func, |
1744 | int mirror_num) | ||
1741 | { | 1745 | { |
1742 | int ret = 0; | 1746 | int ret = 0; |
1743 | struct bio *bio; | 1747 | struct bio *bio; |
@@ -1749,7 +1753,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, | |||
1749 | (tree->ops && tree->ops->merge_bio_hook && | 1753 | (tree->ops && tree->ops->merge_bio_hook && |
1750 | tree->ops->merge_bio_hook(page, offset, size, bio)) || | 1754 | tree->ops->merge_bio_hook(page, offset, size, bio)) || |
1751 | bio_add_page(bio, page, size, offset) < size) { | 1755 | bio_add_page(bio, page, size, offset) < size) { |
1752 | ret = submit_one_bio(rw, bio); | 1756 | ret = submit_one_bio(rw, bio, mirror_num); |
1753 | bio = NULL; | 1757 | bio = NULL; |
1754 | } else { | 1758 | } else { |
1755 | return 0; | 1759 | return 0; |
@@ -1769,7 +1773,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, | |||
1769 | if (bio_ret) { | 1773 | if (bio_ret) { |
1770 | *bio_ret = bio; | 1774 | *bio_ret = bio; |
1771 | } else { | 1775 | } else { |
1772 | ret = submit_one_bio(rw, bio); | 1776 | ret = submit_one_bio(rw, bio, mirror_num); |
1773 | } | 1777 | } |
1774 | 1778 | ||
1775 | return ret; | 1779 | return ret; |
@@ -1798,7 +1802,7 @@ void set_page_extent_head(struct page *page, unsigned long len) | |||
1798 | static int __extent_read_full_page(struct extent_io_tree *tree, | 1802 | static int __extent_read_full_page(struct extent_io_tree *tree, |
1799 | struct page *page, | 1803 | struct page *page, |
1800 | get_extent_t *get_extent, | 1804 | get_extent_t *get_extent, |
1801 | struct bio **bio) | 1805 | struct bio **bio, int mirror_num) |
1802 | { | 1806 | { |
1803 | struct inode *inode = page->mapping->host; | 1807 | struct inode *inode = page->mapping->host; |
1804 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; | 1808 | u64 start = (u64)page->index << PAGE_CACHE_SHIFT; |
@@ -1901,7 +1905,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | |||
1901 | ret = submit_extent_page(READ, tree, page, | 1905 | ret = submit_extent_page(READ, tree, page, |
1902 | sector, iosize, page_offset, | 1906 | sector, iosize, page_offset, |
1903 | bdev, bio, nr, | 1907 | bdev, bio, nr, |
1904 | end_bio_extent_readpage); | 1908 | end_bio_extent_readpage, mirror_num); |
1905 | } | 1909 | } |
1906 | if (ret) | 1910 | if (ret) |
1907 | SetPageError(page); | 1911 | SetPageError(page); |
@@ -1923,9 +1927,9 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page, | |||
1923 | struct bio *bio = NULL; | 1927 | struct bio *bio = NULL; |
1924 | int ret; | 1928 | int ret; |
1925 | 1929 | ||
1926 | ret = __extent_read_full_page(tree, page, get_extent, &bio); | 1930 | ret = __extent_read_full_page(tree, page, get_extent, &bio, 0); |
1927 | if (bio) | 1931 | if (bio) |
1928 | submit_one_bio(READ, bio); | 1932 | submit_one_bio(READ, bio, 0); |
1929 | return ret; | 1933 | return ret; |
1930 | } | 1934 | } |
1931 | EXPORT_SYMBOL(extent_read_full_page); | 1935 | EXPORT_SYMBOL(extent_read_full_page); |
@@ -2077,7 +2081,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
2077 | ret = submit_extent_page(WRITE, tree, page, sector, | 2081 | ret = submit_extent_page(WRITE, tree, page, sector, |
2078 | iosize, page_offset, bdev, | 2082 | iosize, page_offset, bdev, |
2079 | &epd->bio, max_nr, | 2083 | &epd->bio, max_nr, |
2080 | end_bio_extent_writepage); | 2084 | end_bio_extent_writepage, 0); |
2081 | if (ret) | 2085 | if (ret) |
2082 | SetPageError(page); | 2086 | SetPageError(page); |
2083 | } | 2087 | } |
@@ -2244,7 +2248,7 @@ int extent_write_full_page(struct extent_io_tree *tree, struct page *page, | |||
2244 | 2248 | ||
2245 | write_cache_pages(mapping, &wbc_writepages, __extent_writepage, &epd); | 2249 | write_cache_pages(mapping, &wbc_writepages, __extent_writepage, &epd); |
2246 | if (epd.bio) { | 2250 | if (epd.bio) { |
2247 | submit_one_bio(WRITE, epd.bio); | 2251 | submit_one_bio(WRITE, epd.bio, 0); |
2248 | } | 2252 | } |
2249 | return ret; | 2253 | return ret; |
2250 | } | 2254 | } |
@@ -2265,7 +2269,7 @@ int extent_writepages(struct extent_io_tree *tree, | |||
2265 | 2269 | ||
2266 | ret = write_cache_pages(mapping, wbc, __extent_writepage, &epd); | 2270 | ret = write_cache_pages(mapping, wbc, __extent_writepage, &epd); |
2267 | if (epd.bio) { | 2271 | if (epd.bio) { |
2268 | submit_one_bio(WRITE, epd.bio); | 2272 | submit_one_bio(WRITE, epd.bio, 0); |
2269 | } | 2273 | } |
2270 | return ret; | 2274 | return ret; |
2271 | } | 2275 | } |
@@ -2297,7 +2301,8 @@ int extent_readpages(struct extent_io_tree *tree, | |||
2297 | page_cache_get(page); | 2301 | page_cache_get(page); |
2298 | if (!pagevec_add(&pvec, page)) | 2302 | if (!pagevec_add(&pvec, page)) |
2299 | __pagevec_lru_add(&pvec); | 2303 | __pagevec_lru_add(&pvec); |
2300 | __extent_read_full_page(tree, page, get_extent, &bio); | 2304 | __extent_read_full_page(tree, page, get_extent, |
2305 | &bio, 0); | ||
2301 | } | 2306 | } |
2302 | page_cache_release(page); | 2307 | page_cache_release(page); |
2303 | } | 2308 | } |
@@ -2305,7 +2310,7 @@ int extent_readpages(struct extent_io_tree *tree, | |||
2305 | __pagevec_lru_add(&pvec); | 2310 | __pagevec_lru_add(&pvec); |
2306 | BUG_ON(!list_empty(pages)); | 2311 | BUG_ON(!list_empty(pages)); |
2307 | if (bio) | 2312 | if (bio) |
2308 | submit_one_bio(READ, bio); | 2313 | submit_one_bio(READ, bio, 0); |
2309 | return 0; | 2314 | return 0; |
2310 | } | 2315 | } |
2311 | EXPORT_SYMBOL(extent_readpages); | 2316 | EXPORT_SYMBOL(extent_readpages); |
@@ -2430,7 +2435,7 @@ int extent_prepare_write(struct extent_io_tree *tree, | |||
2430 | ret = submit_extent_page(READ, tree, page, | 2435 | ret = submit_extent_page(READ, tree, page, |
2431 | sector, iosize, page_offset, em->bdev, | 2436 | sector, iosize, page_offset, em->bdev, |
2432 | NULL, 1, | 2437 | NULL, 1, |
2433 | end_bio_extent_preparewrite); | 2438 | end_bio_extent_preparewrite, 0); |
2434 | iocount++; | 2439 | iocount++; |
2435 | block_start = block_start + iosize; | 2440 | block_start = block_start + iosize; |
2436 | } else { | 2441 | } else { |
@@ -2696,6 +2701,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree, | |||
2696 | mark_page_accessed(page0); | 2701 | mark_page_accessed(page0); |
2697 | set_page_extent_mapped(page0); | 2702 | set_page_extent_mapped(page0); |
2698 | set_page_extent_head(page0, len); | 2703 | set_page_extent_head(page0, len); |
2704 | uptodate = PageUptodate(page0); | ||
2699 | } else { | 2705 | } else { |
2700 | i = 0; | 2706 | i = 0; |
2701 | } | 2707 | } |
@@ -3006,7 +3012,7 @@ EXPORT_SYMBOL(extent_buffer_uptodate); | |||
3006 | int read_extent_buffer_pages(struct extent_io_tree *tree, | 3012 | int read_extent_buffer_pages(struct extent_io_tree *tree, |
3007 | struct extent_buffer *eb, | 3013 | struct extent_buffer *eb, |
3008 | u64 start, int wait, | 3014 | u64 start, int wait, |
3009 | get_extent_t *get_extent) | 3015 | get_extent_t *get_extent, int mirror_num) |
3010 | { | 3016 | { |
3011 | unsigned long i; | 3017 | unsigned long i; |
3012 | unsigned long start_i; | 3018 | unsigned long start_i; |
@@ -3062,8 +3068,10 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, | |||
3062 | if (!PageUptodate(page)) { | 3068 | if (!PageUptodate(page)) { |
3063 | if (start_i == 0) | 3069 | if (start_i == 0) |
3064 | inc_all_pages = 1; | 3070 | inc_all_pages = 1; |
3071 | ClearPageError(page); | ||
3065 | err = __extent_read_full_page(tree, page, | 3072 | err = __extent_read_full_page(tree, page, |
3066 | get_extent, &bio); | 3073 | get_extent, &bio, |
3074 | mirror_num); | ||
3067 | if (err) { | 3075 | if (err) { |
3068 | ret = err; | 3076 | ret = err; |
3069 | } | 3077 | } |
@@ -3073,7 +3081,7 @@ int read_extent_buffer_pages(struct extent_io_tree *tree, | |||
3073 | } | 3081 | } |
3074 | 3082 | ||
3075 | if (bio) | 3083 | if (bio) |
3076 | submit_one_bio(READ, bio); | 3084 | submit_one_bio(READ, bio, mirror_num); |
3077 | 3085 | ||
3078 | if (ret || !wait) { | 3086 | if (ret || !wait) { |
3079 | return ret; | 3087 | return ret; |