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 | |
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')
-rw-r--r-- | fs/btrfs/ctree.c | 11 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 72 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 50 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 5 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 7 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 39 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 6 |
7 files changed, 138 insertions, 52 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index efce173a935c..ff4e9c6859d1 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -569,7 +569,16 @@ static int check_leaf(struct btrfs_root *root, struct btrfs_path *path, | |||
569 | static int noinline check_block(struct btrfs_root *root, | 569 | static int noinline check_block(struct btrfs_root *root, |
570 | struct btrfs_path *path, int level) | 570 | struct btrfs_path *path, int level) |
571 | { | 571 | { |
572 | return 0; | 572 | u64 found_start; |
573 | if (btrfs_header_level(path->nodes[level]) != level) | ||
574 | printk("warning: bad level %Lu wanted %d found %d\n", | ||
575 | path->nodes[level]->start, level, | ||
576 | btrfs_header_level(path->nodes[level])); | ||
577 | found_start = btrfs_header_bytenr(path->nodes[level]); | ||
578 | if (found_start != path->nodes[level]->start) { | ||
579 | printk("warning: bad bytentr %Lu found %Lu\n", | ||
580 | path->nodes[level]->start, found_start); | ||
581 | } | ||
573 | #if 0 | 582 | #if 0 |
574 | struct extent_buffer *buf = path->nodes[level]; | 583 | struct extent_buffer *buf = path->nodes[level]; |
575 | 584 | ||
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 94ff87d0eae4..59bdf0474be3 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -156,7 +156,6 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | |||
156 | memcpy(&found, result, BTRFS_CRC32_SIZE); | 156 | memcpy(&found, result, BTRFS_CRC32_SIZE); |
157 | 157 | ||
158 | read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE); | 158 | read_extent_buffer(buf, &val, 0, BTRFS_CRC32_SIZE); |
159 | WARN_ON(1); | ||
160 | printk("btrfs: %s checksum verify failed on %llu " | 159 | printk("btrfs: %s checksum verify failed on %llu " |
161 | "wanted %X found %X from_this_trans %d " | 160 | "wanted %X found %X from_this_trans %d " |
162 | "level %d\n", | 161 | "level %d\n", |
@@ -171,6 +170,40 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, | |||
171 | return 0; | 170 | return 0; |
172 | } | 171 | } |
173 | 172 | ||
173 | static int btree_read_extent_buffer_pages(struct btrfs_root *root, | ||
174 | struct extent_buffer *eb, | ||
175 | u64 start) | ||
176 | { | ||
177 | struct extent_io_tree *io_tree; | ||
178 | int ret; | ||
179 | int num_copies = 0; | ||
180 | int mirror_num = 0; | ||
181 | |||
182 | io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; | ||
183 | while (1) { | ||
184 | ret = read_extent_buffer_pages(io_tree, eb, start, 1, | ||
185 | btree_get_extent, mirror_num); | ||
186 | if (!ret) { | ||
187 | if (mirror_num) | ||
188 | printk("good read %Lu mirror %d total %d\n", eb->start, mirror_num, num_copies); | ||
189 | return ret; | ||
190 | } | ||
191 | num_copies = btrfs_num_copies(&root->fs_info->mapping_tree, | ||
192 | eb->start, eb->len); | ||
193 | printk("failed to read %Lu mirror %d total %d\n", eb->start, mirror_num, num_copies); | ||
194 | if (num_copies == 1) { | ||
195 | printk("reading %Lu failed only one copy\n", eb->start); | ||
196 | return ret; | ||
197 | } | ||
198 | mirror_num++; | ||
199 | if (mirror_num > num_copies) { | ||
200 | printk("bailing at mirror %d of %d\n", mirror_num, num_copies); | ||
201 | return ret; | ||
202 | } | ||
203 | } | ||
204 | printk("read extent buffer page last\n"); | ||
205 | return -EIO; | ||
206 | } | ||
174 | 207 | ||
175 | int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | 208 | int csum_dirty_buffer(struct btrfs_root *root, struct page *page) |
176 | { | 209 | { |
@@ -180,6 +213,8 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | |||
180 | int found_level; | 213 | int found_level; |
181 | unsigned long len; | 214 | unsigned long len; |
182 | struct extent_buffer *eb; | 215 | struct extent_buffer *eb; |
216 | int ret; | ||
217 | |||
183 | tree = &BTRFS_I(page->mapping->host)->io_tree; | 218 | tree = &BTRFS_I(page->mapping->host)->io_tree; |
184 | 219 | ||
185 | if (page->private == EXTENT_PAGE_PRIVATE) | 220 | if (page->private == EXTENT_PAGE_PRIVATE) |
@@ -191,8 +226,8 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page) | |||
191 | WARN_ON(1); | 226 | WARN_ON(1); |
192 | } | 227 | } |
193 | eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); | 228 | eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); |
194 | read_extent_buffer_pages(tree, eb, start + PAGE_CACHE_SIZE, 1, | 229 | ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE); |
195 | btree_get_extent); | 230 | BUG_ON(ret); |
196 | btrfs_clear_buffer_defrag(eb); | 231 | btrfs_clear_buffer_defrag(eb); |
197 | found_start = btrfs_header_bytenr(eb); | 232 | found_start = btrfs_header_bytenr(eb); |
198 | if (found_start != start) { | 233 | if (found_start != start) { |
@@ -240,7 +275,7 @@ int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | |||
240 | unsigned long len; | 275 | unsigned long len; |
241 | struct extent_buffer *eb; | 276 | struct extent_buffer *eb; |
242 | struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; | 277 | struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; |
243 | int ret; | 278 | int ret = 0; |
244 | 279 | ||
245 | tree = &BTRFS_I(page->mapping->host)->io_tree; | 280 | tree = &BTRFS_I(page->mapping->host)->io_tree; |
246 | if (page->private == EXTENT_PAGE_PRIVATE) | 281 | if (page->private == EXTENT_PAGE_PRIVATE) |
@@ -252,25 +287,26 @@ int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | |||
252 | WARN_ON(1); | 287 | WARN_ON(1); |
253 | } | 288 | } |
254 | eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); | 289 | eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); |
255 | read_extent_buffer_pages(tree, eb, start + PAGE_CACHE_SIZE, 1, | 290 | |
256 | btree_get_extent); | ||
257 | btrfs_clear_buffer_defrag(eb); | 291 | btrfs_clear_buffer_defrag(eb); |
258 | found_start = btrfs_header_bytenr(eb); | 292 | found_start = btrfs_header_bytenr(eb); |
259 | if (found_start != start) { | 293 | if (found_start != start) { |
260 | printk("warning: eb start incorrect %Lu buffer %Lu len %lu\n", | 294 | printk("bad start on %Lu found %Lu\n", eb->start, found_start); |
261 | start, found_start, len); | 295 | ret = -EIO; |
262 | WARN_ON(1); | ||
263 | goto err; | 296 | goto err; |
264 | } | 297 | } |
265 | if (eb->first_page != page) { | 298 | if (eb->first_page != page) { |
266 | printk("bad first page %lu %lu\n", eb->first_page->index, | 299 | printk("bad first page %lu %lu\n", eb->first_page->index, |
267 | page->index); | 300 | page->index); |
268 | WARN_ON(1); | 301 | WARN_ON(1); |
302 | ret = -EIO; | ||
269 | goto err; | 303 | goto err; |
270 | } | 304 | } |
271 | found_level = btrfs_header_level(eb); | 305 | found_level = btrfs_header_level(eb); |
272 | 306 | ||
273 | ret = csum_tree_block(root, eb, 1); | 307 | ret = csum_tree_block(root, eb, 1); |
308 | if (ret) | ||
309 | ret = -EIO; | ||
274 | 310 | ||
275 | end = min_t(u64, eb->len, PAGE_CACHE_SIZE); | 311 | end = min_t(u64, eb->len, PAGE_CACHE_SIZE); |
276 | end = eb->start + end - 1; | 312 | end = eb->start + end - 1; |
@@ -278,7 +314,7 @@ int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | |||
278 | err: | 314 | err: |
279 | free_extent_buffer(eb); | 315 | free_extent_buffer(eb); |
280 | out: | 316 | out: |
281 | return 0; | 317 | return ret; |
282 | } | 318 | } |
283 | 319 | ||
284 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) | 320 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) |
@@ -329,7 +365,8 @@ int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, | |||
329 | return 0; | 365 | return 0; |
330 | } | 366 | } |
331 | 367 | ||
332 | static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) | 368 | static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, |
369 | int mirror_num) | ||
333 | { | 370 | { |
334 | struct btrfs_root *root = BTRFS_I(inode)->root; | 371 | struct btrfs_root *root = BTRFS_I(inode)->root; |
335 | u64 offset; | 372 | u64 offset; |
@@ -338,7 +375,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) | |||
338 | offset = bio->bi_sector << 9; | 375 | offset = bio->bi_sector << 9; |
339 | 376 | ||
340 | if (rw & (1 << BIO_RW)) { | 377 | if (rw & (1 << BIO_RW)) { |
341 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio); | 378 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num); |
342 | } | 379 | } |
343 | 380 | ||
344 | ret = btrfs_bio_wq_end_io(root->fs_info, bio, 1); | 381 | ret = btrfs_bio_wq_end_io(root->fs_info, bio, 1); |
@@ -349,7 +386,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) | |||
349 | submit_bio(rw, bio); | 386 | submit_bio(rw, bio); |
350 | return 0; | 387 | return 0; |
351 | } | 388 | } |
352 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio); | 389 | return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num); |
353 | } | 390 | } |
354 | 391 | ||
355 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 392 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
@@ -459,7 +496,7 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize) | |||
459 | if (!buf) | 496 | if (!buf) |
460 | return 0; | 497 | return 0; |
461 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, | 498 | read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, |
462 | buf, 0, 0, btree_get_extent); | 499 | buf, 0, 0, btree_get_extent, 0); |
463 | free_extent_buffer(buf); | 500 | free_extent_buffer(buf); |
464 | return ret; | 501 | return ret; |
465 | } | 502 | } |
@@ -522,8 +559,7 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, | |||
522 | if (!buf) | 559 | if (!buf) |
523 | return NULL; | 560 | return NULL; |
524 | 561 | ||
525 | ret = read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, buf, 0, | 562 | ret = btree_read_extent_buffer_pages(root, buf, 0); |
526 | 1, btree_get_extent); | ||
527 | 563 | ||
528 | if (ret == 0) { | 564 | if (ret == 0) { |
529 | buf->flags |= EXTENT_UPTODATE; | 565 | buf->flags |= EXTENT_UPTODATE; |
@@ -1366,10 +1402,8 @@ int btrfs_clear_buffer_defrag(struct extent_buffer *buf) | |||
1366 | int btrfs_read_buffer(struct extent_buffer *buf) | 1402 | int btrfs_read_buffer(struct extent_buffer *buf) |
1367 | { | 1403 | { |
1368 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; | 1404 | struct btrfs_root *root = BTRFS_I(buf->first_page->mapping->host)->root; |
1369 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
1370 | int ret; | 1405 | int ret; |
1371 | ret = read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, | 1406 | ret = btree_read_extent_buffer_pages(root, buf, 0); |
1372 | buf, 0, 1, btree_get_extent); | ||
1373 | if (ret == 0) { | 1407 | if (ret == 0) { |
1374 | buf->flags |= EXTENT_UPTODATE; | 1408 | buf->flags |= EXTENT_UPTODATE; |
1375 | } | 1409 | } |
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; |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 9d2991d1d3ce..8d6b8a14cc30 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -27,7 +27,8 @@ struct extent_state; | |||
27 | struct extent_io_ops { | 27 | struct extent_io_ops { |
28 | int (*fill_delalloc)(struct inode *inode, u64 start, u64 end); | 28 | int (*fill_delalloc)(struct inode *inode, u64 start, u64 end); |
29 | int (*writepage_io_hook)(struct page *page, u64 start, u64 end); | 29 | int (*writepage_io_hook)(struct page *page, u64 start, u64 end); |
30 | int (*submit_bio_hook)(struct inode *inode, int rw, struct bio *bio); | 30 | int (*submit_bio_hook)(struct inode *inode, int rw, struct bio *bio, |
31 | int mirror_num); | ||
31 | int (*merge_bio_hook)(struct page *page, unsigned long offset, | 32 | int (*merge_bio_hook)(struct page *page, unsigned long offset, |
32 | size_t size, struct bio *bio); | 33 | size_t size, struct bio *bio); |
33 | int (*readpage_io_hook)(struct page *page, u64 start, u64 end); | 34 | int (*readpage_io_hook)(struct page *page, u64 start, u64 end); |
@@ -172,7 +173,7 @@ struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree, | |||
172 | void free_extent_buffer(struct extent_buffer *eb); | 173 | void free_extent_buffer(struct extent_buffer *eb); |
173 | int read_extent_buffer_pages(struct extent_io_tree *tree, | 174 | int read_extent_buffer_pages(struct extent_io_tree *tree, |
174 | struct extent_buffer *eb, u64 start, int wait, | 175 | struct extent_buffer *eb, u64 start, int wait, |
175 | get_extent_t *get_extent); | 176 | get_extent_t *get_extent, int mirror_num); |
176 | 177 | ||
177 | static inline void extent_buffer_get(struct extent_buffer *eb) | 178 | static inline void extent_buffer_get(struct extent_buffer *eb) |
178 | { | 179 | { |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e1ef1acdb350..8c2d5d036bd6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -314,7 +314,7 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, | |||
314 | map_tree = &root->fs_info->mapping_tree; | 314 | map_tree = &root->fs_info->mapping_tree; |
315 | map_length = length; | 315 | map_length = length; |
316 | ret = btrfs_map_block(map_tree, READ, logical, | 316 | ret = btrfs_map_block(map_tree, READ, logical, |
317 | &map_length, NULL); | 317 | &map_length, NULL, 0); |
318 | 318 | ||
319 | if (map_length < length + size) { | 319 | if (map_length < length + size) { |
320 | return 1; | 320 | return 1; |
@@ -322,7 +322,8 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset, | |||
322 | return 0; | 322 | return 0; |
323 | } | 323 | } |
324 | 324 | ||
325 | int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) | 325 | int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, |
326 | int mirror_num) | ||
326 | { | 327 | { |
327 | struct btrfs_root *root = BTRFS_I(inode)->root; | 328 | struct btrfs_root *root = BTRFS_I(inode)->root; |
328 | struct btrfs_trans_handle *trans; | 329 | struct btrfs_trans_handle *trans; |
@@ -347,7 +348,7 @@ int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) | |||
347 | BUG_ON(ret); | 348 | BUG_ON(ret); |
348 | mutex_unlock(&root->fs_info->fs_mutex); | 349 | mutex_unlock(&root->fs_info->fs_mutex); |
349 | mapit: | 350 | mapit: |
350 | return btrfs_map_bio(root, rw, bio); | 351 | return btrfs_map_bio(root, rw, bio, mirror_num); |
351 | } | 352 | } |
352 | 353 | ||
353 | int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end) | 354 | int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end) |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 008d3640e8c2..3b927f698320 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -788,9 +788,31 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree) | |||
788 | } | 788 | } |
789 | } | 789 | } |
790 | 790 | ||
791 | int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len) | ||
792 | { | ||
793 | struct extent_map *em; | ||
794 | struct map_lookup *map; | ||
795 | struct extent_map_tree *em_tree = &map_tree->map_tree; | ||
796 | int ret; | ||
797 | |||
798 | spin_lock(&em_tree->lock); | ||
799 | em = lookup_extent_mapping(em_tree, logical, len); | ||
800 | BUG_ON(!em); | ||
801 | |||
802 | BUG_ON(em->start > logical || em->start + em->len < logical); | ||
803 | map = (struct map_lookup *)em->bdev; | ||
804 | if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1)) | ||
805 | ret = map->num_stripes; | ||
806 | else | ||
807 | ret = 1; | ||
808 | free_extent_map(em); | ||
809 | spin_unlock(&em_tree->lock); | ||
810 | return ret; | ||
811 | } | ||
812 | |||
791 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | 813 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, |
792 | u64 logical, u64 *length, | 814 | u64 logical, u64 *length, |
793 | struct btrfs_multi_bio **multi_ret) | 815 | struct btrfs_multi_bio **multi_ret, int mirror_num) |
794 | { | 816 | { |
795 | struct extent_map *em; | 817 | struct extent_map *em; |
796 | struct map_lookup *map; | 818 | struct map_lookup *map; |
@@ -822,6 +844,9 @@ again: | |||
822 | map = (struct map_lookup *)em->bdev; | 844 | map = (struct map_lookup *)em->bdev; |
823 | offset = logical - em->start; | 845 | offset = logical - em->start; |
824 | 846 | ||
847 | if (mirror_num > map->num_stripes) | ||
848 | mirror_num = 0; | ||
849 | |||
825 | /* if our multi bio struct is too small, back off and try again */ | 850 | /* if our multi bio struct is too small, back off and try again */ |
826 | if (multi_ret && (rw & (1 << BIO_RW)) && | 851 | if (multi_ret && (rw & (1 << BIO_RW)) && |
827 | stripes_allocated < map->num_stripes && | 852 | stripes_allocated < map->num_stripes && |
@@ -862,7 +887,9 @@ again: | |||
862 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { | 887 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { |
863 | if (rw & (1 << BIO_RW)) | 888 | if (rw & (1 << BIO_RW)) |
864 | multi->num_stripes = map->num_stripes; | 889 | multi->num_stripes = map->num_stripes; |
865 | else { | 890 | else if (mirror_num) { |
891 | stripe_index = mirror_num - 1; | ||
892 | } else { | ||
866 | int i; | 893 | int i; |
867 | u64 least = (u64)-1; | 894 | u64 least = (u64)-1; |
868 | struct btrfs_device *cur; | 895 | struct btrfs_device *cur; |
@@ -880,6 +907,8 @@ again: | |||
880 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { | 907 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { |
881 | if (rw & (1 << BIO_RW)) | 908 | if (rw & (1 << BIO_RW)) |
882 | multi->num_stripes = map->num_stripes; | 909 | multi->num_stripes = map->num_stripes; |
910 | else if (mirror_num) | ||
911 | stripe_index = mirror_num - 1; | ||
883 | } else { | 912 | } else { |
884 | /* | 913 | /* |
885 | * after this do_div call, stripe_nr is the number of stripes | 914 | * after this do_div call, stripe_nr is the number of stripes |
@@ -938,7 +967,8 @@ static int end_bio_multi_stripe(struct bio *bio, | |||
938 | #endif | 967 | #endif |
939 | } | 968 | } |
940 | 969 | ||
941 | int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) | 970 | int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, |
971 | int mirror_num) | ||
942 | { | 972 | { |
943 | struct btrfs_mapping_tree *map_tree; | 973 | struct btrfs_mapping_tree *map_tree; |
944 | struct btrfs_device *dev; | 974 | struct btrfs_device *dev; |
@@ -960,7 +990,8 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio) | |||
960 | map_tree = &root->fs_info->mapping_tree; | 990 | map_tree = &root->fs_info->mapping_tree; |
961 | map_length = length; | 991 | map_length = length; |
962 | 992 | ||
963 | ret = btrfs_map_block(map_tree, rw, logical, &map_length, &multi); | 993 | ret = btrfs_map_block(map_tree, rw, logical, &map_length, &multi, |
994 | mirror_num); | ||
964 | BUG_ON(ret); | 995 | BUG_ON(ret); |
965 | 996 | ||
966 | total_devs = multi->num_stripes; | 997 | total_devs = multi->num_stripes; |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 10ca0104750c..3d5d0a9cb827 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -93,7 +93,7 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, | |||
93 | u64 owner, u64 num_bytes, u64 *start); | 93 | u64 owner, u64 num_bytes, u64 *start); |
94 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | 94 | int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, |
95 | u64 logical, u64 *length, | 95 | u64 logical, u64 *length, |
96 | struct btrfs_multi_bio **multi_ret); | 96 | struct btrfs_multi_bio **multi_ret, int mirror_num); |
97 | int btrfs_read_sys_array(struct btrfs_root *root); | 97 | int btrfs_read_sys_array(struct btrfs_root *root); |
98 | int btrfs_read_chunk_tree(struct btrfs_root *root); | 98 | int btrfs_read_chunk_tree(struct btrfs_root *root); |
99 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | 99 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, |
@@ -101,7 +101,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
101 | u64 *num_bytes, u64 type); | 101 | u64 *num_bytes, u64 type); |
102 | void btrfs_mapping_init(struct btrfs_mapping_tree *tree); | 102 | void btrfs_mapping_init(struct btrfs_mapping_tree *tree); |
103 | void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree); | 103 | void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree); |
104 | int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio); | 104 | int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, |
105 | int mirror_num); | ||
105 | int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf); | 106 | int btrfs_read_super_device(struct btrfs_root *root, struct extent_buffer *buf); |
106 | int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, | 107 | int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, |
107 | int flags, void *holder); | 108 | int flags, void *holder); |
@@ -112,4 +113,5 @@ int btrfs_add_device(struct btrfs_trans_handle *trans, | |||
112 | struct btrfs_root *root, | 113 | struct btrfs_root *root, |
113 | struct btrfs_device *device); | 114 | struct btrfs_device *device); |
114 | int btrfs_cleanup_fs_uuids(void); | 115 | int btrfs_cleanup_fs_uuids(void); |
116 | int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len); | ||
115 | #endif | 117 | #endif |