diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/inode.c | 60 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.c | 13 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.h | 7 |
3 files changed, 62 insertions, 18 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4d4e2de3e879..f0e41b840739 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2562,8 +2562,10 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) | |||
2562 | struct extent_state *cached_state = NULL; | 2562 | struct extent_state *cached_state = NULL; |
2563 | struct new_sa_defrag_extent *new = NULL; | 2563 | struct new_sa_defrag_extent *new = NULL; |
2564 | int compress_type = 0; | 2564 | int compress_type = 0; |
2565 | int ret; | 2565 | int ret = 0; |
2566 | u64 logical_len = ordered_extent->len; | ||
2566 | bool nolock; | 2567 | bool nolock; |
2568 | bool truncated = false; | ||
2567 | 2569 | ||
2568 | nolock = btrfs_is_free_space_inode(inode); | 2570 | nolock = btrfs_is_free_space_inode(inode); |
2569 | 2571 | ||
@@ -2572,6 +2574,14 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) | |||
2572 | goto out; | 2574 | goto out; |
2573 | } | 2575 | } |
2574 | 2576 | ||
2577 | if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered_extent->flags)) { | ||
2578 | truncated = true; | ||
2579 | logical_len = ordered_extent->truncated_len; | ||
2580 | /* Truncated the entire extent, don't bother adding */ | ||
2581 | if (!logical_len) | ||
2582 | goto out; | ||
2583 | } | ||
2584 | |||
2575 | if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) { | 2585 | if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) { |
2576 | BUG_ON(!list_empty(&ordered_extent->list)); /* Logic error */ | 2586 | BUG_ON(!list_empty(&ordered_extent->list)); /* Logic error */ |
2577 | btrfs_ordered_update_i_size(inode, 0, ordered_extent); | 2587 | btrfs_ordered_update_i_size(inode, 0, ordered_extent); |
@@ -2627,15 +2637,14 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) | |||
2627 | ret = btrfs_mark_extent_written(trans, inode, | 2637 | ret = btrfs_mark_extent_written(trans, inode, |
2628 | ordered_extent->file_offset, | 2638 | ordered_extent->file_offset, |
2629 | ordered_extent->file_offset + | 2639 | ordered_extent->file_offset + |
2630 | ordered_extent->len); | 2640 | logical_len); |
2631 | } else { | 2641 | } else { |
2632 | BUG_ON(root == root->fs_info->tree_root); | 2642 | BUG_ON(root == root->fs_info->tree_root); |
2633 | ret = insert_reserved_file_extent(trans, inode, | 2643 | ret = insert_reserved_file_extent(trans, inode, |
2634 | ordered_extent->file_offset, | 2644 | ordered_extent->file_offset, |
2635 | ordered_extent->start, | 2645 | ordered_extent->start, |
2636 | ordered_extent->disk_len, | 2646 | ordered_extent->disk_len, |
2637 | ordered_extent->len, | 2647 | logical_len, logical_len, |
2638 | ordered_extent->len, | ||
2639 | compress_type, 0, 0, | 2648 | compress_type, 0, 0, |
2640 | BTRFS_FILE_EXTENT_REG); | 2649 | BTRFS_FILE_EXTENT_REG); |
2641 | } | 2650 | } |
@@ -2667,17 +2676,27 @@ out: | |||
2667 | if (trans) | 2676 | if (trans) |
2668 | btrfs_end_transaction(trans, root); | 2677 | btrfs_end_transaction(trans, root); |
2669 | 2678 | ||
2670 | if (ret) { | 2679 | if (ret || truncated) { |
2671 | clear_extent_uptodate(io_tree, ordered_extent->file_offset, | 2680 | u64 start, end; |
2672 | ordered_extent->file_offset + | 2681 | |
2673 | ordered_extent->len - 1, NULL, GFP_NOFS); | 2682 | if (truncated) |
2683 | start = ordered_extent->file_offset + logical_len; | ||
2684 | else | ||
2685 | start = ordered_extent->file_offset; | ||
2686 | end = ordered_extent->file_offset + ordered_extent->len - 1; | ||
2687 | clear_extent_uptodate(io_tree, start, end, NULL, GFP_NOFS); | ||
2688 | |||
2689 | /* Drop the cache for the part of the extent we didn't write. */ | ||
2690 | btrfs_drop_extent_cache(inode, start, end, 0); | ||
2674 | 2691 | ||
2675 | /* | 2692 | /* |
2676 | * If the ordered extent had an IOERR or something else went | 2693 | * If the ordered extent had an IOERR or something else went |
2677 | * wrong we need to return the space for this ordered extent | 2694 | * wrong we need to return the space for this ordered extent |
2678 | * back to the allocator. | 2695 | * back to the allocator. We only free the extent in the |
2696 | * truncated case if we didn't write out the extent at all. | ||
2679 | */ | 2697 | */ |
2680 | if (!test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags) && | 2698 | if ((ret || !logical_len) && |
2699 | !test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags) && | ||
2681 | !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) | 2700 | !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) |
2682 | btrfs_free_reserved_extent(root, ordered_extent->start, | 2701 | btrfs_free_reserved_extent(root, ordered_extent->start, |
2683 | ordered_extent->disk_len); | 2702 | ordered_extent->disk_len); |
@@ -7336,10 +7355,23 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset, | |||
7336 | * whoever cleared the private bit is responsible | 7355 | * whoever cleared the private bit is responsible |
7337 | * for the finish_ordered_io | 7356 | * for the finish_ordered_io |
7338 | */ | 7357 | */ |
7339 | if (TestClearPagePrivate2(page) && | 7358 | if (TestClearPagePrivate2(page)) { |
7340 | btrfs_dec_test_ordered_pending(inode, &ordered, page_start, | 7359 | struct btrfs_ordered_inode_tree *tree; |
7341 | PAGE_CACHE_SIZE, 1)) { | 7360 | u64 new_len; |
7342 | btrfs_finish_ordered_io(ordered); | 7361 | |
7362 | tree = &BTRFS_I(inode)->ordered_tree; | ||
7363 | |||
7364 | spin_lock_irq(&tree->lock); | ||
7365 | set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags); | ||
7366 | new_len = page_start - ordered->file_offset; | ||
7367 | if (new_len < ordered->truncated_len) | ||
7368 | ordered->truncated_len = new_len; | ||
7369 | spin_unlock_irq(&tree->lock); | ||
7370 | |||
7371 | if (btrfs_dec_test_ordered_pending(inode, &ordered, | ||
7372 | page_start, | ||
7373 | PAGE_CACHE_SIZE, 1)) | ||
7374 | btrfs_finish_ordered_io(ordered); | ||
7343 | } | 7375 | } |
7344 | btrfs_put_ordered_extent(ordered); | 7376 | btrfs_put_ordered_extent(ordered); |
7345 | cached_state = NULL; | 7377 | cached_state = NULL; |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index f2023ccb7cf6..966b413a33b8 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
@@ -205,6 +205,7 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | |||
205 | entry->bytes_left = len; | 205 | entry->bytes_left = len; |
206 | entry->inode = igrab(inode); | 206 | entry->inode = igrab(inode); |
207 | entry->compress_type = compress_type; | 207 | entry->compress_type = compress_type; |
208 | entry->truncated_len = (u64)-1; | ||
208 | if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE) | 209 | if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE) |
209 | set_bit(type, &entry->flags); | 210 | set_bit(type, &entry->flags); |
210 | 211 | ||
@@ -920,12 +921,16 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, | |||
920 | struct btrfs_ordered_extent *test; | 921 | struct btrfs_ordered_extent *test; |
921 | int ret = 1; | 922 | int ret = 1; |
922 | 923 | ||
923 | if (ordered) | 924 | spin_lock_irq(&tree->lock); |
925 | if (ordered) { | ||
924 | offset = entry_end(ordered); | 926 | offset = entry_end(ordered); |
925 | else | 927 | if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags)) |
928 | offset = min(offset, | ||
929 | ordered->file_offset + | ||
930 | ordered->truncated_len); | ||
931 | } else { | ||
926 | offset = ALIGN(offset, BTRFS_I(inode)->root->sectorsize); | 932 | offset = ALIGN(offset, BTRFS_I(inode)->root->sectorsize); |
927 | 933 | } | |
928 | spin_lock_irq(&tree->lock); | ||
929 | disk_i_size = BTRFS_I(inode)->disk_i_size; | 934 | disk_i_size = BTRFS_I(inode)->disk_i_size; |
930 | 935 | ||
931 | /* truncate file */ | 936 | /* truncate file */ |
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 68844d59ee6f..d9a5aa097b4f 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h | |||
@@ -69,6 +69,7 @@ struct btrfs_ordered_sum { | |||
69 | * the isize. */ | 69 | * the isize. */ |
70 | #define BTRFS_ORDERED_LOGGED_CSUM 8 /* We've logged the csums on this ordered | 70 | #define BTRFS_ORDERED_LOGGED_CSUM 8 /* We've logged the csums on this ordered |
71 | ordered extent */ | 71 | ordered extent */ |
72 | #define BTRFS_ORDERED_TRUNCATED 9 /* Set when we have to truncate an extent */ | ||
72 | 73 | ||
73 | struct btrfs_ordered_extent { | 74 | struct btrfs_ordered_extent { |
74 | /* logical offset in the file */ | 75 | /* logical offset in the file */ |
@@ -96,6 +97,12 @@ struct btrfs_ordered_extent { | |||
96 | */ | 97 | */ |
97 | u64 outstanding_isize; | 98 | u64 outstanding_isize; |
98 | 99 | ||
100 | /* | ||
101 | * If we get truncated we need to adjust the file extent we enter for | ||
102 | * this ordered extent so that we do not expose stale data. | ||
103 | */ | ||
104 | u64 truncated_len; | ||
105 | |||
99 | /* flags (described above) */ | 106 | /* flags (described above) */ |
100 | unsigned long flags; | 107 | unsigned long flags; |
101 | 108 | ||