aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-07-22 11:18:09 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:05 -0400
commitf421950f86bf96a11fef932e167ab2e70d4c43a0 (patch)
treea2b62b942b023e37b6aae39891c2b314d8d8a3fb /fs/btrfs/inode.c
parenta61e6f29dc7c9d56a776a518eed92bbc61848263 (diff)
Btrfs: Fix some data=ordered related data corruptions
Stress testing was showing data checksum errors, most of which were caused by a lookup bug in the extent_map tree. The tree was caching the last pointer returned, and searches would check the last pointer first. But, search callers also expect the search to return the very first matching extent in the range, which wasn't always true with the last pointer usage. For now, the code to cache the last return value is just removed. It is easy to fix, but I think lookups are rare enough that it isn't required anymore. This commit also replaces do_sync_mapping_range with a local copy of the related functions. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c54
1 files changed, 30 insertions, 24 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 60852ada658e..3da12a4d913d 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -485,7 +485,7 @@ int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end)
485 fixup = kzalloc(sizeof(*fixup), GFP_NOFS); 485 fixup = kzalloc(sizeof(*fixup), GFP_NOFS);
486 if (!fixup) 486 if (!fixup)
487 return -EAGAIN; 487 return -EAGAIN;
488printk("queueing worker to fixup page %lu %Lu\n", inode->i_ino, page_offset(page)); 488
489 SetPageChecked(page); 489 SetPageChecked(page);
490 page_cache_get(page); 490 page_cache_get(page);
491 fixup->work.func = btrfs_writepage_fixup_worker; 491 fixup->work.func = btrfs_writepage_fixup_worker;
@@ -502,11 +502,13 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
502 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 502 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
503 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; 503 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
504 struct extent_map *em; 504 struct extent_map *em;
505 struct extent_map *em_orig;
505 u64 alloc_hint = 0; 506 u64 alloc_hint = 0;
506 u64 clear_start; 507 u64 clear_start;
507 u64 clear_end; 508 u64 clear_end;
508 struct list_head list; 509 struct list_head list;
509 struct btrfs_key ins; 510 struct btrfs_key ins;
511 struct rb_node *rb;
510 int ret; 512 int ret;
511 513
512 ret = btrfs_dec_test_ordered_pending(inode, start, end - start + 1); 514 ret = btrfs_dec_test_ordered_pending(inode, start, end - start + 1);
@@ -535,6 +537,22 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
535 537
536 mutex_lock(&BTRFS_I(inode)->extent_mutex); 538 mutex_lock(&BTRFS_I(inode)->extent_mutex);
537 539
540 spin_lock(&em_tree->lock);
541 clear_start = ordered_extent->file_offset;
542 clear_end = ordered_extent->file_offset + ordered_extent->len;
543 em = lookup_extent_mapping(em_tree, clear_start,
544 ordered_extent->len);
545 em_orig = em;
546 while(em && clear_start < extent_map_end(em) && clear_end > em->start) {
547 clear_bit(EXTENT_FLAG_PINNED, &em->flags);
548 rb = rb_next(&em->rb_node);
549 if (!rb)
550 break;
551 em = rb_entry(rb, struct extent_map, rb_node);
552 }
553 free_extent_map(em_orig);
554 spin_unlock(&em_tree->lock);
555
538 ret = btrfs_drop_extents(trans, root, inode, 556 ret = btrfs_drop_extents(trans, root, inode,
539 ordered_extent->file_offset, 557 ordered_extent->file_offset,
540 ordered_extent->file_offset + 558 ordered_extent->file_offset +
@@ -548,22 +566,6 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)
548 ordered_extent->len, 0); 566 ordered_extent->len, 0);
549 BUG_ON(ret); 567 BUG_ON(ret);
550 568
551 spin_lock(&em_tree->lock);
552 clear_start = ordered_extent->file_offset;
553 clear_end = ordered_extent->file_offset + ordered_extent->len;
554 while(clear_start < clear_end) {
555 em = lookup_extent_mapping(em_tree, clear_start,
556 clear_end - clear_start);
557 if (em) {
558 clear_bit(EXTENT_FLAG_PINNED, &em->flags);
559 clear_start = em->start + em->len;
560 free_extent_map(em);
561 } else {
562 break;
563 }
564 }
565 spin_unlock(&em_tree->lock);
566
567 btrfs_drop_extent_cache(inode, ordered_extent->file_offset, 569 btrfs_drop_extent_cache(inode, ordered_extent->file_offset,
568 ordered_extent->file_offset + 570 ordered_extent->file_offset +
569 ordered_extent->len - 1); 571 ordered_extent->len - 1);
@@ -2318,7 +2320,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
2318 u64 extent_end = 0; 2320 u64 extent_end = 0;
2319 u64 objectid = inode->i_ino; 2321 u64 objectid = inode->i_ino;
2320 u32 found_type; 2322 u32 found_type;
2321 struct btrfs_path *path; 2323 struct btrfs_path *path = NULL;
2322 struct btrfs_root *root = BTRFS_I(inode)->root; 2324 struct btrfs_root *root = BTRFS_I(inode)->root;
2323 struct btrfs_file_extent_item *item; 2325 struct btrfs_file_extent_item *item;
2324 struct extent_buffer *leaf; 2326 struct extent_buffer *leaf;
@@ -2328,9 +2330,6 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
2328 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 2330 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
2329 struct btrfs_trans_handle *trans = NULL; 2331 struct btrfs_trans_handle *trans = NULL;
2330 2332
2331 path = btrfs_alloc_path();
2332 BUG_ON(!path);
2333
2334again: 2333again:
2335 spin_lock(&em_tree->lock); 2334 spin_lock(&em_tree->lock);
2336 em = lookup_extent_mapping(em_tree, start, len); 2335 em = lookup_extent_mapping(em_tree, start, len);
@@ -2354,6 +2353,12 @@ again:
2354 em->bdev = root->fs_info->fs_devices->latest_bdev; 2353 em->bdev = root->fs_info->fs_devices->latest_bdev;
2355 em->start = EXTENT_MAP_HOLE; 2354 em->start = EXTENT_MAP_HOLE;
2356 em->len = (u64)-1; 2355 em->len = (u64)-1;
2356
2357 if (!path) {
2358 path = btrfs_alloc_path();
2359 BUG_ON(!path);
2360 }
2361
2357 ret = btrfs_lookup_file_extent(trans, root, path, 2362 ret = btrfs_lookup_file_extent(trans, root, path,
2358 objectid, start, trans != NULL); 2363 objectid, start, trans != NULL);
2359 if (ret < 0) { 2364 if (ret < 0) {
@@ -2530,7 +2535,8 @@ insert:
2530 } 2535 }
2531 spin_unlock(&em_tree->lock); 2536 spin_unlock(&em_tree->lock);
2532out: 2537out:
2533 btrfs_free_path(path); 2538 if (path)
2539 btrfs_free_path(path);
2534 if (trans) { 2540 if (trans) {
2535 ret = btrfs_end_transaction(trans, root); 2541 ret = btrfs_end_transaction(trans, root);
2536 if (!err) { 2542 if (!err) {
@@ -2643,8 +2649,8 @@ static int btrfs_writepage(struct page *page, struct writeback_control *wbc)
2643 return extent_write_full_page(tree, page, btrfs_get_extent, wbc); 2649 return extent_write_full_page(tree, page, btrfs_get_extent, wbc);
2644} 2650}
2645 2651
2646static int btrfs_writepages(struct address_space *mapping, 2652int btrfs_writepages(struct address_space *mapping,
2647 struct writeback_control *wbc) 2653 struct writeback_control *wbc)
2648{ 2654{
2649 struct extent_io_tree *tree; 2655 struct extent_io_tree *tree;
2650 tree = &BTRFS_I(mapping->host)->io_tree; 2656 tree = &BTRFS_I(mapping->host)->io_tree;