diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 87 |
1 files changed, 66 insertions, 21 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 714adc4ac4c2..315138605088 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -690,6 +690,15 @@ static void cache_state(struct extent_state *state, | |||
690 | } | 690 | } |
691 | } | 691 | } |
692 | 692 | ||
693 | static void uncache_state(struct extent_state **cached_ptr) | ||
694 | { | ||
695 | if (cached_ptr && (*cached_ptr)) { | ||
696 | struct extent_state *state = *cached_ptr; | ||
697 | *cached_ptr = NULL; | ||
698 | free_extent_state(state); | ||
699 | } | ||
700 | } | ||
701 | |||
693 | /* | 702 | /* |
694 | * set some bits on a range in the tree. This may require allocations or | 703 | * set some bits on a range in the tree. This may require allocations or |
695 | * sleeping, so the gfp mask is used to indicate what is allowed. | 704 | * sleeping, so the gfp mask is used to indicate what is allowed. |
@@ -940,10 +949,10 @@ static int clear_extent_new(struct extent_io_tree *tree, u64 start, u64 end, | |||
940 | } | 949 | } |
941 | 950 | ||
942 | int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end, | 951 | int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end, |
943 | gfp_t mask) | 952 | struct extent_state **cached_state, gfp_t mask) |
944 | { | 953 | { |
945 | return set_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, NULL, | 954 | return set_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, |
946 | NULL, mask); | 955 | NULL, cached_state, mask); |
947 | } | 956 | } |
948 | 957 | ||
949 | static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, | 958 | static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, |
@@ -1012,8 +1021,7 @@ int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end, | |||
1012 | mask); | 1021 | mask); |
1013 | } | 1022 | } |
1014 | 1023 | ||
1015 | int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, | 1024 | int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, gfp_t mask) |
1016 | gfp_t mask) | ||
1017 | { | 1025 | { |
1018 | return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, NULL, | 1026 | return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, NULL, |
1019 | mask); | 1027 | mask); |
@@ -1735,6 +1743,9 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | |||
1735 | 1743 | ||
1736 | do { | 1744 | do { |
1737 | struct page *page = bvec->bv_page; | 1745 | struct page *page = bvec->bv_page; |
1746 | struct extent_state *cached = NULL; | ||
1747 | struct extent_state *state; | ||
1748 | |||
1738 | tree = &BTRFS_I(page->mapping->host)->io_tree; | 1749 | tree = &BTRFS_I(page->mapping->host)->io_tree; |
1739 | 1750 | ||
1740 | start = ((u64)page->index << PAGE_CACHE_SHIFT) + | 1751 | start = ((u64)page->index << PAGE_CACHE_SHIFT) + |
@@ -1749,9 +1760,20 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | |||
1749 | if (++bvec <= bvec_end) | 1760 | if (++bvec <= bvec_end) |
1750 | prefetchw(&bvec->bv_page->flags); | 1761 | prefetchw(&bvec->bv_page->flags); |
1751 | 1762 | ||
1763 | spin_lock(&tree->lock); | ||
1764 | state = find_first_extent_bit_state(tree, start, EXTENT_LOCKED); | ||
1765 | if (state && state->start == start) { | ||
1766 | /* | ||
1767 | * take a reference on the state, unlock will drop | ||
1768 | * the ref | ||
1769 | */ | ||
1770 | cache_state(state, &cached); | ||
1771 | } | ||
1772 | spin_unlock(&tree->lock); | ||
1773 | |||
1752 | if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) { | 1774 | if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) { |
1753 | ret = tree->ops->readpage_end_io_hook(page, start, end, | 1775 | ret = tree->ops->readpage_end_io_hook(page, start, end, |
1754 | NULL); | 1776 | state); |
1755 | if (ret) | 1777 | if (ret) |
1756 | uptodate = 0; | 1778 | uptodate = 0; |
1757 | } | 1779 | } |
@@ -1764,15 +1786,16 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | |||
1764 | test_bit(BIO_UPTODATE, &bio->bi_flags); | 1786 | test_bit(BIO_UPTODATE, &bio->bi_flags); |
1765 | if (err) | 1787 | if (err) |
1766 | uptodate = 0; | 1788 | uptodate = 0; |
1789 | uncache_state(&cached); | ||
1767 | continue; | 1790 | continue; |
1768 | } | 1791 | } |
1769 | } | 1792 | } |
1770 | 1793 | ||
1771 | if (uptodate) { | 1794 | if (uptodate) { |
1772 | set_extent_uptodate(tree, start, end, | 1795 | set_extent_uptodate(tree, start, end, &cached, |
1773 | GFP_ATOMIC); | 1796 | GFP_ATOMIC); |
1774 | } | 1797 | } |
1775 | unlock_extent(tree, start, end, GFP_ATOMIC); | 1798 | unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC); |
1776 | 1799 | ||
1777 | if (whole_page) { | 1800 | if (whole_page) { |
1778 | if (uptodate) { | 1801 | if (uptodate) { |
@@ -1811,6 +1834,7 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err) | |||
1811 | 1834 | ||
1812 | do { | 1835 | do { |
1813 | struct page *page = bvec->bv_page; | 1836 | struct page *page = bvec->bv_page; |
1837 | struct extent_state *cached = NULL; | ||
1814 | tree = &BTRFS_I(page->mapping->host)->io_tree; | 1838 | tree = &BTRFS_I(page->mapping->host)->io_tree; |
1815 | 1839 | ||
1816 | start = ((u64)page->index << PAGE_CACHE_SHIFT) + | 1840 | start = ((u64)page->index << PAGE_CACHE_SHIFT) + |
@@ -1821,13 +1845,14 @@ static void end_bio_extent_preparewrite(struct bio *bio, int err) | |||
1821 | prefetchw(&bvec->bv_page->flags); | 1845 | prefetchw(&bvec->bv_page->flags); |
1822 | 1846 | ||
1823 | if (uptodate) { | 1847 | if (uptodate) { |
1824 | set_extent_uptodate(tree, start, end, GFP_ATOMIC); | 1848 | set_extent_uptodate(tree, start, end, &cached, |
1849 | GFP_ATOMIC); | ||
1825 | } else { | 1850 | } else { |
1826 | ClearPageUptodate(page); | 1851 | ClearPageUptodate(page); |
1827 | SetPageError(page); | 1852 | SetPageError(page); |
1828 | } | 1853 | } |
1829 | 1854 | ||
1830 | unlock_extent(tree, start, end, GFP_ATOMIC); | 1855 | unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC); |
1831 | 1856 | ||
1832 | } while (bvec >= bio->bi_io_vec); | 1857 | } while (bvec >= bio->bi_io_vec); |
1833 | 1858 | ||
@@ -2016,14 +2041,17 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | |||
2016 | while (cur <= end) { | 2041 | while (cur <= end) { |
2017 | if (cur >= last_byte) { | 2042 | if (cur >= last_byte) { |
2018 | char *userpage; | 2043 | char *userpage; |
2044 | struct extent_state *cached = NULL; | ||
2045 | |||
2019 | iosize = PAGE_CACHE_SIZE - page_offset; | 2046 | iosize = PAGE_CACHE_SIZE - page_offset; |
2020 | userpage = kmap_atomic(page, KM_USER0); | 2047 | userpage = kmap_atomic(page, KM_USER0); |
2021 | memset(userpage + page_offset, 0, iosize); | 2048 | memset(userpage + page_offset, 0, iosize); |
2022 | flush_dcache_page(page); | 2049 | flush_dcache_page(page); |
2023 | kunmap_atomic(userpage, KM_USER0); | 2050 | kunmap_atomic(userpage, KM_USER0); |
2024 | set_extent_uptodate(tree, cur, cur + iosize - 1, | 2051 | set_extent_uptodate(tree, cur, cur + iosize - 1, |
2025 | GFP_NOFS); | 2052 | &cached, GFP_NOFS); |
2026 | unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS); | 2053 | unlock_extent_cached(tree, cur, cur + iosize - 1, |
2054 | &cached, GFP_NOFS); | ||
2027 | break; | 2055 | break; |
2028 | } | 2056 | } |
2029 | em = get_extent(inode, page, page_offset, cur, | 2057 | em = get_extent(inode, page, page_offset, cur, |
@@ -2063,14 +2091,17 @@ static int __extent_read_full_page(struct extent_io_tree *tree, | |||
2063 | /* we've found a hole, just zero and go on */ | 2091 | /* we've found a hole, just zero and go on */ |
2064 | if (block_start == EXTENT_MAP_HOLE) { | 2092 | if (block_start == EXTENT_MAP_HOLE) { |
2065 | char *userpage; | 2093 | char *userpage; |
2094 | struct extent_state *cached = NULL; | ||
2095 | |||
2066 | userpage = kmap_atomic(page, KM_USER0); | 2096 | userpage = kmap_atomic(page, KM_USER0); |
2067 | memset(userpage + page_offset, 0, iosize); | 2097 | memset(userpage + page_offset, 0, iosize); |
2068 | flush_dcache_page(page); | 2098 | flush_dcache_page(page); |
2069 | kunmap_atomic(userpage, KM_USER0); | 2099 | kunmap_atomic(userpage, KM_USER0); |
2070 | 2100 | ||
2071 | set_extent_uptodate(tree, cur, cur + iosize - 1, | 2101 | set_extent_uptodate(tree, cur, cur + iosize - 1, |
2072 | GFP_NOFS); | 2102 | &cached, GFP_NOFS); |
2073 | unlock_extent(tree, cur, cur + iosize - 1, GFP_NOFS); | 2103 | unlock_extent_cached(tree, cur, cur + iosize - 1, |
2104 | &cached, GFP_NOFS); | ||
2074 | cur = cur + iosize; | 2105 | cur = cur + iosize; |
2075 | page_offset += iosize; | 2106 | page_offset += iosize; |
2076 | continue; | 2107 | continue; |
@@ -2188,10 +2219,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, | |||
2188 | unsigned long nr_written = 0; | 2219 | unsigned long nr_written = 0; |
2189 | 2220 | ||
2190 | if (wbc->sync_mode == WB_SYNC_ALL) | 2221 | if (wbc->sync_mode == WB_SYNC_ALL) |
2191 | write_flags = WRITE_SYNC_PLUG; | 2222 | write_flags = WRITE_SYNC; |
2192 | else | 2223 | else |
2193 | write_flags = WRITE; | 2224 | write_flags = WRITE; |
2194 | 2225 | ||
2226 | trace___extent_writepage(page, inode, wbc); | ||
2227 | |||
2195 | WARN_ON(!PageLocked(page)); | 2228 | WARN_ON(!PageLocked(page)); |
2196 | pg_offset = i_size & (PAGE_CACHE_SIZE - 1); | 2229 | pg_offset = i_size & (PAGE_CACHE_SIZE - 1); |
2197 | if (page->index > end_index || | 2230 | if (page->index > end_index || |
@@ -2787,9 +2820,12 @@ int extent_prepare_write(struct extent_io_tree *tree, | |||
2787 | iocount++; | 2820 | iocount++; |
2788 | block_start = block_start + iosize; | 2821 | block_start = block_start + iosize; |
2789 | } else { | 2822 | } else { |
2790 | set_extent_uptodate(tree, block_start, cur_end, | 2823 | struct extent_state *cached = NULL; |
2824 | |||
2825 | set_extent_uptodate(tree, block_start, cur_end, &cached, | ||
2791 | GFP_NOFS); | 2826 | GFP_NOFS); |
2792 | unlock_extent(tree, block_start, cur_end, GFP_NOFS); | 2827 | unlock_extent_cached(tree, block_start, cur_end, |
2828 | &cached, GFP_NOFS); | ||
2793 | block_start = cur_end + 1; | 2829 | block_start = cur_end + 1; |
2794 | } | 2830 | } |
2795 | page_offset = block_start & (PAGE_CACHE_SIZE - 1); | 2831 | page_offset = block_start & (PAGE_CACHE_SIZE - 1); |
@@ -3455,7 +3491,7 @@ int set_extent_buffer_uptodate(struct extent_io_tree *tree, | |||
3455 | num_pages = num_extent_pages(eb->start, eb->len); | 3491 | num_pages = num_extent_pages(eb->start, eb->len); |
3456 | 3492 | ||
3457 | set_extent_uptodate(tree, eb->start, eb->start + eb->len - 1, | 3493 | set_extent_uptodate(tree, eb->start, eb->start + eb->len - 1, |
3458 | GFP_NOFS); | 3494 | NULL, GFP_NOFS); |
3459 | for (i = 0; i < num_pages; i++) { | 3495 | for (i = 0; i < num_pages; i++) { |
3460 | page = extent_buffer_page(eb, i); | 3496 | page = extent_buffer_page(eb, i); |
3461 | if ((i == 0 && (eb->start & (PAGE_CACHE_SIZE - 1))) || | 3497 | if ((i == 0 && (eb->start & (PAGE_CACHE_SIZE - 1))) || |
@@ -3690,6 +3726,7 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, | |||
3690 | "wanted %lu %lu\n", (unsigned long long)eb->start, | 3726 | "wanted %lu %lu\n", (unsigned long long)eb->start, |
3691 | eb->len, start, min_len); | 3727 | eb->len, start, min_len); |
3692 | WARN_ON(1); | 3728 | WARN_ON(1); |
3729 | return -EINVAL; | ||
3693 | } | 3730 | } |
3694 | 3731 | ||
3695 | p = extent_buffer_page(eb, i); | 3732 | p = extent_buffer_page(eb, i); |
@@ -3882,6 +3919,12 @@ static void move_pages(struct page *dst_page, struct page *src_page, | |||
3882 | kunmap_atomic(dst_kaddr, KM_USER0); | 3919 | kunmap_atomic(dst_kaddr, KM_USER0); |
3883 | } | 3920 | } |
3884 | 3921 | ||
3922 | static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len) | ||
3923 | { | ||
3924 | unsigned long distance = (src > dst) ? src - dst : dst - src; | ||
3925 | return distance < len; | ||
3926 | } | ||
3927 | |||
3885 | static void copy_pages(struct page *dst_page, struct page *src_page, | 3928 | static void copy_pages(struct page *dst_page, struct page *src_page, |
3886 | unsigned long dst_off, unsigned long src_off, | 3929 | unsigned long dst_off, unsigned long src_off, |
3887 | unsigned long len) | 3930 | unsigned long len) |
@@ -3889,10 +3932,12 @@ static void copy_pages(struct page *dst_page, struct page *src_page, | |||
3889 | char *dst_kaddr = kmap_atomic(dst_page, KM_USER0); | 3932 | char *dst_kaddr = kmap_atomic(dst_page, KM_USER0); |
3890 | char *src_kaddr; | 3933 | char *src_kaddr; |
3891 | 3934 | ||
3892 | if (dst_page != src_page) | 3935 | if (dst_page != src_page) { |
3893 | src_kaddr = kmap_atomic(src_page, KM_USER1); | 3936 | src_kaddr = kmap_atomic(src_page, KM_USER1); |
3894 | else | 3937 | } else { |
3895 | src_kaddr = dst_kaddr; | 3938 | src_kaddr = dst_kaddr; |
3939 | BUG_ON(areas_overlap(src_off, dst_off, len)); | ||
3940 | } | ||
3896 | 3941 | ||
3897 | memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len); | 3942 | memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len); |
3898 | kunmap_atomic(dst_kaddr, KM_USER0); | 3943 | kunmap_atomic(dst_kaddr, KM_USER0); |
@@ -3967,7 +4012,7 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, | |||
3967 | "len %lu len %lu\n", dst_offset, len, dst->len); | 4012 | "len %lu len %lu\n", dst_offset, len, dst->len); |
3968 | BUG_ON(1); | 4013 | BUG_ON(1); |
3969 | } | 4014 | } |
3970 | if (dst_offset < src_offset) { | 4015 | if (!areas_overlap(src_offset, dst_offset, len)) { |
3971 | memcpy_extent_buffer(dst, dst_offset, src_offset, len); | 4016 | memcpy_extent_buffer(dst, dst_offset, src_offset, len); |
3972 | return; | 4017 | return; |
3973 | } | 4018 | } |