diff options
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 79 |
1 files changed, 50 insertions, 29 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 7073cbb1b2d..c99121ac5d6 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -513,7 +513,10 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, | |||
513 | u64 last_end; | 513 | u64 last_end; |
514 | int err; | 514 | int err; |
515 | int set = 0; | 515 | int set = 0; |
516 | int clear = 0; | ||
516 | 517 | ||
518 | if (bits & (EXTENT_IOBITS | EXTENT_BOUNDARY)) | ||
519 | clear = 1; | ||
517 | again: | 520 | again: |
518 | if (!prealloc && (mask & __GFP_WAIT)) { | 521 | if (!prealloc && (mask & __GFP_WAIT)) { |
519 | prealloc = alloc_extent_state(mask); | 522 | prealloc = alloc_extent_state(mask); |
@@ -524,14 +527,20 @@ again: | |||
524 | spin_lock(&tree->lock); | 527 | spin_lock(&tree->lock); |
525 | if (cached_state) { | 528 | if (cached_state) { |
526 | cached = *cached_state; | 529 | cached = *cached_state; |
527 | *cached_state = NULL; | 530 | |
528 | cached_state = NULL; | 531 | if (clear) { |
532 | *cached_state = NULL; | ||
533 | cached_state = NULL; | ||
534 | } | ||
535 | |||
529 | if (cached && cached->tree && cached->start == start) { | 536 | if (cached && cached->tree && cached->start == start) { |
530 | atomic_dec(&cached->refs); | 537 | if (clear) |
538 | atomic_dec(&cached->refs); | ||
531 | state = cached; | 539 | state = cached; |
532 | goto hit_next; | 540 | goto hit_next; |
533 | } | 541 | } |
534 | free_extent_state(cached); | 542 | if (clear) |
543 | free_extent_state(cached); | ||
535 | } | 544 | } |
536 | /* | 545 | /* |
537 | * this search will find the extents that end after | 546 | * this search will find the extents that end after |
@@ -946,11 +955,11 @@ int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, | |||
946 | } | 955 | } |
947 | 956 | ||
948 | int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end, | 957 | int set_extent_delalloc(struct extent_io_tree *tree, u64 start, u64 end, |
949 | gfp_t mask) | 958 | struct extent_state **cached_state, gfp_t mask) |
950 | { | 959 | { |
951 | return set_extent_bit(tree, start, end, | 960 | return set_extent_bit(tree, start, end, |
952 | EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_UPTODATE, | 961 | EXTENT_DELALLOC | EXTENT_DIRTY | EXTENT_UPTODATE, |
953 | 0, NULL, NULL, mask); | 962 | 0, NULL, cached_state, mask); |
954 | } | 963 | } |
955 | 964 | ||
956 | int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, | 965 | int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end, |
@@ -984,10 +993,11 @@ int set_extent_uptodate(struct extent_io_tree *tree, u64 start, u64 end, | |||
984 | } | 993 | } |
985 | 994 | ||
986 | static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, | 995 | static int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, |
987 | u64 end, gfp_t mask) | 996 | u64 end, struct extent_state **cached_state, |
997 | gfp_t mask) | ||
988 | { | 998 | { |
989 | return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0, | 999 | return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0, |
990 | NULL, mask); | 1000 | cached_state, mask); |
991 | } | 1001 | } |
992 | 1002 | ||
993 | int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end) | 1003 | int wait_on_extent_writeback(struct extent_io_tree *tree, u64 start, u64 end) |
@@ -1171,7 +1181,8 @@ out: | |||
1171 | * 1 is returned if we find something, 0 if nothing was in the tree | 1181 | * 1 is returned if we find something, 0 if nothing was in the tree |
1172 | */ | 1182 | */ |
1173 | static noinline u64 find_delalloc_range(struct extent_io_tree *tree, | 1183 | static noinline u64 find_delalloc_range(struct extent_io_tree *tree, |
1174 | u64 *start, u64 *end, u64 max_bytes) | 1184 | u64 *start, u64 *end, u64 max_bytes, |
1185 | struct extent_state **cached_state) | ||
1175 | { | 1186 | { |
1176 | struct rb_node *node; | 1187 | struct rb_node *node; |
1177 | struct extent_state *state; | 1188 | struct extent_state *state; |
@@ -1203,8 +1214,11 @@ static noinline u64 find_delalloc_range(struct extent_io_tree *tree, | |||
1203 | *end = state->end; | 1214 | *end = state->end; |
1204 | goto out; | 1215 | goto out; |
1205 | } | 1216 | } |
1206 | if (!found) | 1217 | if (!found) { |
1207 | *start = state->start; | 1218 | *start = state->start; |
1219 | *cached_state = state; | ||
1220 | atomic_inc(&state->refs); | ||
1221 | } | ||
1208 | found++; | 1222 | found++; |
1209 | *end = state->end; | 1223 | *end = state->end; |
1210 | cur_start = state->end + 1; | 1224 | cur_start = state->end + 1; |
@@ -1336,10 +1350,11 @@ again: | |||
1336 | delalloc_start = *start; | 1350 | delalloc_start = *start; |
1337 | delalloc_end = 0; | 1351 | delalloc_end = 0; |
1338 | found = find_delalloc_range(tree, &delalloc_start, &delalloc_end, | 1352 | found = find_delalloc_range(tree, &delalloc_start, &delalloc_end, |
1339 | max_bytes); | 1353 | max_bytes, &cached_state); |
1340 | if (!found || delalloc_end <= *start) { | 1354 | if (!found || delalloc_end <= *start) { |
1341 | *start = delalloc_start; | 1355 | *start = delalloc_start; |
1342 | *end = delalloc_end; | 1356 | *end = delalloc_end; |
1357 | free_extent_state(cached_state); | ||
1343 | return found; | 1358 | return found; |
1344 | } | 1359 | } |
1345 | 1360 | ||
@@ -1722,7 +1737,7 @@ static void end_bio_extent_writepage(struct bio *bio, int err) | |||
1722 | } | 1737 | } |
1723 | 1738 | ||
1724 | if (!uptodate) { | 1739 | if (!uptodate) { |
1725 | clear_extent_uptodate(tree, start, end, GFP_NOFS); | 1740 | clear_extent_uptodate(tree, start, end, NULL, GFP_NOFS); |
1726 | ClearPageUptodate(page); | 1741 | ClearPageUptodate(page); |
1727 | SetPageError(page); | 1742 | SetPageError(page); |
1728 | } | 1743 | } |
@@ -1750,7 +1765,8 @@ static void end_bio_extent_writepage(struct bio *bio, int err) | |||
1750 | static void end_bio_extent_readpage(struct bio *bio, int err) | 1765 | static void end_bio_extent_readpage(struct bio *bio, int err) |
1751 | { | 1766 | { |
1752 | int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | 1767 | int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); |
1753 | struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; | 1768 | struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1; |
1769 | struct bio_vec *bvec = bio->bi_io_vec; | ||
1754 | struct extent_io_tree *tree; | 1770 | struct extent_io_tree *tree; |
1755 | u64 start; | 1771 | u64 start; |
1756 | u64 end; | 1772 | u64 end; |
@@ -1773,7 +1789,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | |||
1773 | else | 1789 | else |
1774 | whole_page = 0; | 1790 | whole_page = 0; |
1775 | 1791 | ||
1776 | if (--bvec >= bio->bi_io_vec) | 1792 | if (++bvec <= bvec_end) |
1777 | prefetchw(&bvec->bv_page->flags); | 1793 | prefetchw(&bvec->bv_page->flags); |
1778 | 1794 | ||
1779 | if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) { | 1795 | if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) { |
@@ -1818,7 +1834,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) | |||
1818 | } | 1834 | } |
1819 | check_page_locked(tree, page); | 1835 | check_page_locked(tree, page); |
1820 | } | 1836 | } |
1821 | } while (bvec >= bio->bi_io_vec); | 1837 | } while (bvec <= bvec_end); |
1822 | 1838 | ||
1823 | bio_put(bio); | 1839 | bio_put(bio); |
1824 | } | 1840 | } |
@@ -2704,6 +2720,7 @@ int extent_readpages(struct extent_io_tree *tree, | |||
2704 | int extent_invalidatepage(struct extent_io_tree *tree, | 2720 | int extent_invalidatepage(struct extent_io_tree *tree, |
2705 | struct page *page, unsigned long offset) | 2721 | struct page *page, unsigned long offset) |
2706 | { | 2722 | { |
2723 | struct extent_state *cached_state = NULL; | ||
2707 | u64 start = ((u64)page->index << PAGE_CACHE_SHIFT); | 2724 | u64 start = ((u64)page->index << PAGE_CACHE_SHIFT); |
2708 | u64 end = start + PAGE_CACHE_SIZE - 1; | 2725 | u64 end = start + PAGE_CACHE_SIZE - 1; |
2709 | size_t blocksize = page->mapping->host->i_sb->s_blocksize; | 2726 | size_t blocksize = page->mapping->host->i_sb->s_blocksize; |
@@ -2712,12 +2729,12 @@ int extent_invalidatepage(struct extent_io_tree *tree, | |||
2712 | if (start > end) | 2729 | if (start > end) |
2713 | return 0; | 2730 | return 0; |
2714 | 2731 | ||
2715 | lock_extent(tree, start, end, GFP_NOFS); | 2732 | lock_extent_bits(tree, start, end, 0, &cached_state, GFP_NOFS); |
2716 | wait_on_page_writeback(page); | 2733 | wait_on_page_writeback(page); |
2717 | clear_extent_bit(tree, start, end, | 2734 | clear_extent_bit(tree, start, end, |
2718 | EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC | | 2735 | EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC | |
2719 | EXTENT_DO_ACCOUNTING, | 2736 | EXTENT_DO_ACCOUNTING, |
2720 | 1, 1, NULL, GFP_NOFS); | 2737 | 1, 1, &cached_state, GFP_NOFS); |
2721 | return 0; | 2738 | return 0; |
2722 | } | 2739 | } |
2723 | 2740 | ||
@@ -2920,16 +2937,17 @@ sector_t extent_bmap(struct address_space *mapping, sector_t iblock, | |||
2920 | get_extent_t *get_extent) | 2937 | get_extent_t *get_extent) |
2921 | { | 2938 | { |
2922 | struct inode *inode = mapping->host; | 2939 | struct inode *inode = mapping->host; |
2940 | struct extent_state *cached_state = NULL; | ||
2923 | u64 start = iblock << inode->i_blkbits; | 2941 | u64 start = iblock << inode->i_blkbits; |
2924 | sector_t sector = 0; | 2942 | sector_t sector = 0; |
2925 | size_t blksize = (1 << inode->i_blkbits); | 2943 | size_t blksize = (1 << inode->i_blkbits); |
2926 | struct extent_map *em; | 2944 | struct extent_map *em; |
2927 | 2945 | ||
2928 | lock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1, | 2946 | lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + blksize - 1, |
2929 | GFP_NOFS); | 2947 | 0, &cached_state, GFP_NOFS); |
2930 | em = get_extent(inode, NULL, 0, start, blksize, 0); | 2948 | em = get_extent(inode, NULL, 0, start, blksize, 0); |
2931 | unlock_extent(&BTRFS_I(inode)->io_tree, start, start + blksize - 1, | 2949 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, |
2932 | GFP_NOFS); | 2950 | start + blksize - 1, &cached_state, GFP_NOFS); |
2933 | if (!em || IS_ERR(em)) | 2951 | if (!em || IS_ERR(em)) |
2934 | return 0; | 2952 | return 0; |
2935 | 2953 | ||
@@ -2951,6 +2969,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
2951 | u32 flags = 0; | 2969 | u32 flags = 0; |
2952 | u64 disko = 0; | 2970 | u64 disko = 0; |
2953 | struct extent_map *em = NULL; | 2971 | struct extent_map *em = NULL; |
2972 | struct extent_state *cached_state = NULL; | ||
2954 | int end = 0; | 2973 | int end = 0; |
2955 | u64 em_start = 0, em_len = 0; | 2974 | u64 em_start = 0, em_len = 0; |
2956 | unsigned long emflags; | 2975 | unsigned long emflags; |
@@ -2959,8 +2978,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
2959 | if (len == 0) | 2978 | if (len == 0) |
2960 | return -EINVAL; | 2979 | return -EINVAL; |
2961 | 2980 | ||
2962 | lock_extent(&BTRFS_I(inode)->io_tree, start, start + len, | 2981 | lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0, |
2963 | GFP_NOFS); | 2982 | &cached_state, GFP_NOFS); |
2964 | em = get_extent(inode, NULL, 0, off, max - off, 0); | 2983 | em = get_extent(inode, NULL, 0, off, max - off, 0); |
2965 | if (!em) | 2984 | if (!em) |
2966 | goto out; | 2985 | goto out; |
@@ -3023,8 +3042,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
3023 | out_free: | 3042 | out_free: |
3024 | free_extent_map(em); | 3043 | free_extent_map(em); |
3025 | out: | 3044 | out: |
3026 | unlock_extent(&BTRFS_I(inode)->io_tree, start, start + len, | 3045 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len, |
3027 | GFP_NOFS); | 3046 | &cached_state, GFP_NOFS); |
3028 | return ret; | 3047 | return ret; |
3029 | } | 3048 | } |
3030 | 3049 | ||
@@ -3264,7 +3283,8 @@ int set_extent_buffer_dirty(struct extent_io_tree *tree, | |||
3264 | } | 3283 | } |
3265 | 3284 | ||
3266 | int clear_extent_buffer_uptodate(struct extent_io_tree *tree, | 3285 | int clear_extent_buffer_uptodate(struct extent_io_tree *tree, |
3267 | struct extent_buffer *eb) | 3286 | struct extent_buffer *eb, |
3287 | struct extent_state **cached_state) | ||
3268 | { | 3288 | { |
3269 | unsigned long i; | 3289 | unsigned long i; |
3270 | struct page *page; | 3290 | struct page *page; |
@@ -3274,7 +3294,7 @@ int clear_extent_buffer_uptodate(struct extent_io_tree *tree, | |||
3274 | clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); | 3294 | clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); |
3275 | 3295 | ||
3276 | clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1, | 3296 | clear_extent_uptodate(tree, eb->start, eb->start + eb->len - 1, |
3277 | GFP_NOFS); | 3297 | cached_state, GFP_NOFS); |
3278 | for (i = 0; i < num_pages; i++) { | 3298 | for (i = 0; i < num_pages; i++) { |
3279 | page = extent_buffer_page(eb, i); | 3299 | page = extent_buffer_page(eb, i); |
3280 | if (page) | 3300 | if (page) |
@@ -3334,7 +3354,8 @@ int extent_range_uptodate(struct extent_io_tree *tree, | |||
3334 | } | 3354 | } |
3335 | 3355 | ||
3336 | int extent_buffer_uptodate(struct extent_io_tree *tree, | 3356 | int extent_buffer_uptodate(struct extent_io_tree *tree, |
3337 | struct extent_buffer *eb) | 3357 | struct extent_buffer *eb, |
3358 | struct extent_state *cached_state) | ||
3338 | { | 3359 | { |
3339 | int ret = 0; | 3360 | int ret = 0; |
3340 | unsigned long num_pages; | 3361 | unsigned long num_pages; |
@@ -3346,7 +3367,7 @@ int extent_buffer_uptodate(struct extent_io_tree *tree, | |||
3346 | return 1; | 3367 | return 1; |
3347 | 3368 | ||
3348 | ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1, | 3369 | ret = test_range_bit(tree, eb->start, eb->start + eb->len - 1, |
3349 | EXTENT_UPTODATE, 1, NULL); | 3370 | EXTENT_UPTODATE, 1, cached_state); |
3350 | if (ret) | 3371 | if (ret) |
3351 | return ret; | 3372 | return ret; |
3352 | 3373 | ||