aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-04-09 16:28:12 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:01 -0400
commitf188591e987e21b6f7f8864c66a02858b95b530e (patch)
tree996f04b7c8d1e8a626b123e7a2a217992d705c60 /fs/btrfs/disk-io.c
parent22c599485b1fdd95e4476a4752596a6cf6c6629a (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/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c72
1 files changed, 53 insertions, 19 deletions
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
173static 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)
188printk("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);
193printk("failed to read %Lu mirror %d total %d\n", eb->start, mirror_num, num_copies);
194 if (num_copies == 1) {
195printk("reading %Lu failed only one copy\n", eb->start);
196 return ret;
197 }
198 mirror_num++;
199 if (mirror_num > num_copies) {
200printk("bailing at mirror %d of %d\n", mirror_num, num_copies);
201 return ret;
202 }
203 }
204printk("read extent buffer page last\n");
205 return -EIO;
206}
174 207
175int csum_dirty_buffer(struct btrfs_root *root, struct page *page) 208int 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", 294printk("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,
278err: 314err:
279 free_extent_buffer(eb); 315 free_extent_buffer(eb);
280out: 316out:
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
332static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio) 368static 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
355static int btree_writepage(struct page *page, struct writeback_control *wbc) 392static 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)
1366int btrfs_read_buffer(struct extent_buffer *buf) 1402int 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 }