diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 95 |
1 files changed, 51 insertions, 44 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 7073cbb1b2d4..d2d03684fab2 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -2,7 +2,6 @@ | |||
2 | #include <linux/slab.h> | 2 | #include <linux/slab.h> |
3 | #include <linux/bio.h> | 3 | #include <linux/bio.h> |
4 | #include <linux/mm.h> | 4 | #include <linux/mm.h> |
5 | #include <linux/gfp.h> | ||
6 | #include <linux/pagemap.h> | 5 | #include <linux/pagemap.h> |
7 | #include <linux/page-flags.h> | 6 | #include <linux/page-flags.h> |
8 | #include <linux/module.h> | 7 | #include <linux/module.h> |
@@ -513,7 +512,10 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, | |||
513 | u64 last_end; | 512 | u64 last_end; |
514 | int err; | 513 | int err; |
515 | int set = 0; | 514 | int set = 0; |
515 | int clear = 0; | ||
516 | 516 | ||
517 | if (bits & (EXTENT_IOBITS | EXTENT_BOUNDARY)) | ||
518 | clear = 1; | ||
517 | again: | 519 | again: |
518 | if (!prealloc && (mask & __GFP_WAIT)) { | 520 | if (!prealloc && (mask & __GFP_WAIT)) { |
519 | prealloc = alloc_extent_state(mask); | 521 | prealloc = alloc_extent_state(mask); |
@@ -524,14 +526,20 @@ again: | |||
524 | spin_lock(&tree->lock); | 526 | spin_lock(&tree->lock); |
525 | if (cached_state) { | 527 | if (cached_state) { |
526 | cached = *cached_state; | 528 | cached = *cached_state; |
527 | *cached_state = NULL; | 529 | |
528 | cached_state = NULL; | 530 | if (clear) { |
531 | *cached_state = NULL; | ||
532 | cached_state = NULL; | ||
533 | } | ||
534 | |||
529 | if (cached && cached->tree && cached->start == start) { | 535 | if (cached && cached->tree && cached->start == start) { |
530 | atomic_dec(&cached->refs); | 536 | if (clear) |
537 | atomic_dec(&cached->refs); | ||
531 | state = cached; | 538 | state = cached; |
532 | goto hit_next; | 539 | goto hit_next; |
533 | } | 540 | } |
534 | free_extent_state(cached); | 541 | if (clear) |
542 | free_extent_state(cached); | ||
535 | } | 543 | } |
536 | /* | 544 | /* |
537 | * this search will find the extents that end after | 545 | * this search will find the extents that end after |
@@ -946,11 +954,11 @@ int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, | |||
946 | } | 954 | } |
947 | 955 | ||
948 | int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end, | 956 | int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end, |
949 | gfp_t mask) | 957 | struct extent_state **cached_state, gfp_t mask) |
950 | { | 958 | { |
951 | return set_extent_bit(tree, start, end, | 959 | return set_extent_bit(tree, start, end, |
952 | EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_UPTODATE, | 960 | EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_UPTODATE, |
953 | 0, NULL, NULL, mask); | 961 | 0, NULL, cached_state, mask); |
954 | } | 962 | } |
955 | 963 | ||
956 | int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, | 964 | int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, |
@@ -984,10 +992,11 @@ int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end, | |||
984 | } | 992 | } |
985 | 993 | ||
986 | static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, | 994 | static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, |
987 | u64 end, gfp_t mask) | 995 | u64 end, struct extent_state **cached_state, |
996 | gfp_t mask) | ||
988 | { | 997 | { |
989 | return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0, | 998 | return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0, |
990 | NULL, mask); | 999 | cached_state, mask); |
991 | } | 1000 | } |
992 | 1001 | ||
993 | int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end) | 1002 | int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end) |
@@ -1171,7 +1180,8 @@ out: | |||
1171 | * 1 is returned if we find something, 0 if nothing was in the tree | 1180 | * 1 is returned if we find something, 0 if nothing was in the tree |
1172 | */ | 1181 | */ |
1173 | static noinline u64 find_delalloc_range(struct extent_io_tree *tree, | 1182 | static noinline u64 find_delalloc_range(struct extent_io_tree *tree, |
1174 | u64 *start, u64 *end, u64 max_bytes) | 1183 | u64 *start, u64 *end, u64 max_bytes, |
1184 | struct extent_state **cached_state) | ||
1175 | { | 1185 | { |
1176 | struct rb_node *node; | 1186 | struct rb_node *node; |
1177 | struct extent_state *state; | 1187 | struct extent_state *state; |
@@ -1203,8 +1213,11 @@ static noinline u64 find_delalloc_range(struct extent_io_tree *tree, | |||
1203 | *end = state->end; | 1213 | *end = state->end; |
1204 | goto out; | 1214 | goto out; |
1205 | } | 1215 | } |
1206 | if (!found) | 1216 | if (!found) { |
1207 | *start = state->start; | 1217 | *start = state->start; |
1218 | *cached_state = state; | ||
1219 | atomic_inc(&state->refs); | ||
1220 | } | ||
1208 | found++; | 1221 | found++; |
1209 | *end = state->end; | 1222 | *end = state->end; |
1210 | cur_start = state->end + 1; | 1223 | cur_start = state->end + 1; |
@@ -1336,10 +1349,11 @@ again: | |||
1336 | delalloc_start = *start; | 1349 | delalloc_start = *start; |
1337 | delalloc_end = 0; | 1350 | delalloc_end = 0; |
1338 | found = find_delalloc_range(tree, &delalloc_start, &delalloc_end, | 1351 | found = find_delalloc_range(tree, &delalloc_start, &delalloc_end, |
1339 | max_bytes); | 1352 | max_bytes, &cached_state); |
1340 | if (!found || delalloc_end <= *start) { | 1353 | if (!found || delalloc_end <= *start) { |
1341 | *start = delalloc_start; | 1354 | *start = delalloc_start; |
1342 | *end = delalloc_end; | 1355 | *end = delalloc_end; |
1356 | free_extent_state(cached_state); | ||
1343 | return found; | 1357 | return found; |
1344 | } | 1358 | } |
1345 | 1359 | ||
@@ -1722,7 +1736,7 @@ static void end_bio_extent_writepage(struct bio *bio, int err) | |||
1722 | } | 1736 | } |
1723 | 1737 | ||
1724 | if (!uptodate) { | 1738 | if (!uptodate) { |
1725 | clear_extent_uptodate(tree, start, end, GFP_NOFS); | 1739 | clear_extent_uptodate(tree, start, end, NULL, GFP_NOFS); |
1726 | ClearPageUptodate(page); | 1740 | ClearPageUptodate(page); |
1727 | SetPageError(page); | 1741 | SetPageError(page); |
1728 | } | 1742 | } |
@@ -1750,7 +1764,8 @@ static void end_bio_extent_writepage(struct bio *bio, int err) | |||
1750 | static void end_bio_extent_readpage(struct bio *bio, int err) | 1764 | static void end_bio_extent_readpage(struct bio *bio, int err) |
1751 | { | 1765 | { |
1752 | int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | 1766 | int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); |
1753 | struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; | 1767 | struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1; |
1768 | struct bio_vec *bvec = bio->bi_io_vec; | ||
1754 | struct extent_io_tree *tree; | 1769 | struct extent_io_tree *tree; |
1755 | u64 start; | 1770 | u64 start; |
1756 | u64 end; | 1771 | u64 end; |
@@ -1773,7 +1788,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | |||
1773 | else | 1788 | else |
1774 | whole_page = 0; | 1789 | whole_page = 0; |
1775 | 1790 | ||
1776 | if (--bvec >= bio->bi_io_vec) | 1791 | if (++bvec <= bvec_end) |
1777 | prefetchw(&bvec->bv_page->flags); | 1792 | prefetchw(&bvec->bv_page->flags); |
1778 | 1793 | ||
1779 | if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) { | 1794 | if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) { |
@@ -1818,7 +1833,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | |||
1818 | } | 1833 | } |
1819 | check_page_locked(tree, page); | 1834 | check_page_locked(tree, page); |
1820 | } | 1835 | } |
1821 | } while (bvec >= bio->bi_io_vec); | 1836 | } while (bvec <= bvec_end); |
1822 | 1837 | ||
1823 | bio_put(bio); | 1838 | bio_put(bio); |
1824 | } | 1839 | } |
@@ -2663,33 +2678,20 @@ int extent_readpages(struct extent_io_tree *tree, | |||
2663 | { | 2678 | { |
2664 | struct bio *bio = NULL; | 2679 | struct bio *bio = NULL; |
2665 | unsigned page_idx; | 2680 | unsigned page_idx; |
2666 | struct pagevec pvec; | ||
2667 | unsigned long bio_flags = 0; | 2681 | unsigned long bio_flags = 0; |
2668 | 2682 | ||
2669 | pagevec_init(&pvec, 0); | ||
2670 | for (page_idx = 0; page_idx < nr_pages; page_idx++) { | 2683 | for (page_idx = 0; page_idx < nr_pages; page_idx++) { |
2671 | struct page *page = list_entry(pages->prev, struct page, lru); | 2684 | struct page *page = list_entry(pages->prev, struct page, lru); |
2672 | 2685 | ||
2673 | prefetchw(&page->flags); | 2686 | prefetchw(&page->flags); |
2674 | list_del(&page->lru); | 2687 | list_del(&page->lru); |
2675 | /* | 2688 | if (!add_to_page_cache_lru(page, mapping, |
2676 | * what we want to do here is call add_to_page_cache_lru, | ||
2677 | * but that isn't exported, so we reproduce it here | ||
2678 | */ | ||
2679 | if (!add_to_page_cache(page, mapping, | ||
2680 | page->index, GFP_KERNEL)) { | 2689 | page->index, GFP_KERNEL)) { |
2681 | |||
2682 | /* open coding of lru_cache_add, also not exported */ | ||
2683 | page_cache_get(page); | ||
2684 | if (!pagevec_add(&pvec, page)) | ||
2685 | __pagevec_lru_add_file(&pvec); | ||
2686 | __extent_read_full_page(tree, page, get_extent, | 2690 | __extent_read_full_page(tree, page, get_extent, |
2687 | &bio, 0, &bio_flags); | 2691 | &bio, 0, &bio_flags); |
2688 | } | 2692 | } |
2689 | page_cache_release(page); | 2693 | page_cache_release(page); |
2690 | } | 2694 | } |
2691 | if (pagevec_count(&pvec)) | ||
2692 | __pagevec_lru_add_file(&pvec); | ||
2693 | BUG_ON(!list_empty(pages)); | 2695 | BUG_ON(!list_empty(pages)); |
2694 | if (bio) | 2696 | if (bio) |
2695 | submit_one_bio(READ, bio, 0, bio_flags); | 2697 | submit_one_bio(READ, bio, 0, bio_flags); |
@@ -2704,6 +2706,7 @@ int extent_readpages(struct extent_io_tree *tree, | |||
2704 | int extent_invalidatepage(struct extent_io_tree *tree, | 2706 | int extent_invalidatepage(struct extent_io_tree *tree, |
2705 | struct page *page, unsigned long offset) | 2707 | struct page *page, unsigned long offset) |
2706 | { | 2708 | { |
2709 | struct extent_state *cached_state = NULL; | ||
2707 | u64 start = ((u64)page->index << PAGE_CACHE_SHIFT); | 2710 | u64 start = ((u64)page->index << PAGE_CACHE_SHIFT); |
2708 | u64 end = start + PAGE_CACHE_SIZE - 1; | 2711 | u64 end = start + PAGE_CACHE_SIZE - 1; |
2709 | size_t blocksize = page->mapping->host->i_sb->s_blocksize; | 2712 | size_t blocksize = page->mapping->host->i_sb->s_blocksize; |
@@ -2712,12 +2715,12 @@ int extent_invalidatepage(struct extent_io_tree *tree, | |||
2712 | if (start > end) | 2715 | if (start > end) |
2713 | return 0; | 2716 | return 0; |
2714 | 2717 | ||
2715 | lock_extent(tree, start, end, GFP_NOFS); | 2718 | lock_extent_bits(tree, start, end, 0, &cached_state, GFP_NOFS); |
2716 | wait_on_page_writeback(page); | 2719 | wait_on_page_writeback(page); |
2717 | clear_extent_bit(tree, start, end, | 2720 | clear_extent_bit(tree, start, end, |
2718 | EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC | | 2721 | EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC | |
2719 | EXTENT_DO_ACCOUNTING, | 2722 | EXTENT_DO_ACCOUNTING, |
2720 | 1, 1, NULL, GFP_NOFS); | 2723 | 1, 1, &cached_state, GFP_NOFS); |
2721 | return 0; | 2724 | return 0; |
2722 | } | 2725 | } |
2723 | 2726 | ||
@@ -2920,16 +2923,17 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock, | |||
2920 | get_extent_t *get_extent) | 2923 | get_extent_t *get_extent) |
2921 | { | 2924 | { |
2922 | struct inode *inode = mapping->host; | 2925 | struct inode *inode = mapping->host; |
2926 | struct extent_state *cached_state = NULL; | ||
2923 | u64 start = iblock << inode->i_blkbits; | 2927 | u64 start = iblock << inode->i_blkbits; |
2924 | sector_t sector = 0; | 2928 | sector_t sector = 0; |
2925 | size_t blksize = (1 << inode->i_blkbits); | 2929 | size_t blksize = (1 << inode->i_blkbits); |
2926 | struct extent_map *em; | 2930 | struct extent_map *em; |
2927 | 2931 | ||
2928 | lock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1, | 2932 | lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + blksize - 1, |
2929 | GFP_NOFS); | 2933 | 0, &cached_state, GFP_NOFS); |
2930 | em = get_extent(inode, NULL, 0, start, blksize, 0); | 2934 | em = get_extent(inode, NULL, 0, start, blksize, 0); |
2931 | unlock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1, | 2935 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, |
2932 | GFP_NOFS); | 2936 | start + blksize - 1, &cached_state, GFP_NOFS); |
2933 | if (!em || IS_ERR(em)) | 2937 | if (!em || IS_ERR(em)) |
2934 | return 0; | 2938 | return 0; |
2935 | 2939 | ||
@@ -2951,6 +2955,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
2951 | u32 flags = 0; | 2955 | u32 flags = 0; |
2952 | u64 disko = 0; | 2956 | u64 disko = 0; |
2953 | struct extent_map *em = NULL; | 2957 | struct extent_map *em = NULL; |
2958 | struct extent_state *cached_state = NULL; | ||
2954 | int end = 0; | 2959 | int end = 0; |
2955 | u64 em_start = 0, em_len = 0; | 2960 | u64 em_start = 0, em_len = 0; |
2956 | unsigned long emflags; | 2961 | unsigned long emflags; |
@@ -2959,8 +2964,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
2959 | if (len == 0) | 2964 | if (len == 0) |
2960 | return -EINVAL; | 2965 | return -EINVAL; |
2961 | 2966 | ||
2962 | lock_extent(&BTRFS_I(inode)->io_tree, start, start + len, | 2967 | lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0, |
2963 | GFP_NOFS); | 2968 | &cached_state, GFP_NOFS); |
2964 | em = get_extent(inode, NULL, 0, off, max - off, 0); | 2969 | em = get_extent(inode, NULL, 0, off, max - off, 0); |
2965 | if (!em) | 2970 | if (!em) |
2966 | goto out; | 2971 | goto out; |
@@ -3023,8 +3028,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
3023 | out_free: | 3028 | out_free: |
3024 | free_extent_map(em); | 3029 | free_extent_map(em); |
3025 | out: | 3030 | out: |
3026 | unlock_extent(&BTRFS_I(inode)->io_tree, start, start + len, | 3031 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len, |
3027 | GFP_NOFS); | 3032 | &cached_state, GFP_NOFS); |
3028 | return ret; | 3033 | return ret; |
3029 | } | 3034 | } |
3030 | 3035 | ||
@@ -3264,7 +3269,8 @@ int set_extent_buffer_dirty(struct extent_io_tree *tree, | |||
3264 | } | 3269 | } |
3265 | 3270 | ||
3266 | int clear_extent_buffer_uptodate(struct extent_io_tree *tree, | 3271 | int clear_extent_buffer_uptodate(struct extent_io_tree *tree, |
3267 | struct extent_buffer *eb) | 3272 | struct extent_buffer *eb, |
3273 | struct extent_state **cached_state) | ||
3268 | { | 3274 | { |
3269 | unsigned long i; | 3275 | unsigned long i; |
3270 | struct page *page; | 3276 | struct page *page; |
@@ -3274,7 +3280,7 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree, | |||
3274 | clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); | 3280 | clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); |
3275 | 3281 | ||
3276 | clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1, | 3282 | clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1, |
3277 | GFP_NOFS); | 3283 | cached_state, GFP_NOFS); |
3278 | for (i = 0; i < num_pages; i++) { | 3284 | for (i = 0; i < num_pages; i++) { |
3279 | page = extent_buffer_page(eb, i); | 3285 | page = extent_buffer_page(eb, i); |
3280 | if (page) | 3286 | if (page) |
@@ -3334,7 +3340,8 @@ int extent_range_uptodate(struct extent_io_tree *tree, | |||
3334 | } | 3340 | } |
3335 | 3341 | ||
3336 | int extent_buffer_uptodate(struct extent_io_tree *tree, | 3342 | int extent_buffer_uptodate(struct extent_io_tree *tree, |
3337 | struct extent_buffer *eb) | 3343 | struct extent_buffer *eb, |
3344 | struct extent_state *cached_state) | ||
3338 | { | 3345 | { |
3339 | int ret = 0; | 3346 | int ret = 0; |
3340 | unsigned long num_pages; | 3347 | unsigned long num_pages; |
@@ -3346,7 +3353,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree, | |||
3346 | return 1; | 3353 | return 1; |
3347 | 3354 | ||
3348 | ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1, | 3355 | ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1, |
3349 | EXTENT_UPTODATE, 1, NULL); | 3356 | EXTENT_UPTODATE, 1, cached_state); |
3350 | if (ret) | 3357 | if (ret) |
3351 | return ret; | 3358 | return ret; |
3352 | 3359 | ||