diff options
author | Mark Fasheh <mfasheh@suse.de> | 2013-08-06 14:42:50 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-09-01 08:04:59 -0400 |
commit | 4b384318a74e38eb248f74f9a92a700d2ce841f1 (patch) | |
tree | 5ef01855a2824b7c832e9303a19cfb2527c9d08d /fs | |
parent | 32b7c687c52a0b78a7d41ce6423c2fd8f5ca92da (diff) |
btrfs: Introduce extent_read_full_page_nolock()
We want this for btrfs_extent_same. Basically readpage and friends do their
own extent locking but for the purposes of dedupe, we want to have both
files locked down across a set of readpage operations (so that we can
compare data). Introduce this variant and a flag which can be set for
extent_read_full_page() to indicate that we are already locked.
Partial credit for this patch goes to Gabriel de Perthuis <g2p.code@gmail.com>
as I have included a fix from him to the original patch which avoids a
deadlock on compressed extents.
Signed-off-by: Mark Fasheh <mfasheh@suse.de>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/compression.c | 6 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 37 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 3 |
3 files changed, 37 insertions, 9 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index b189bd1e7a3e..37dff5b2d56d 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c | |||
@@ -639,7 +639,11 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, | |||
639 | faili = nr_pages - 1; | 639 | faili = nr_pages - 1; |
640 | cb->nr_pages = nr_pages; | 640 | cb->nr_pages = nr_pages; |
641 | 641 | ||
642 | add_ra_bio_pages(inode, em_start + em_len, cb); | 642 | /* In the parent-locked case, we only locked the range we are |
643 | * interested in. In all other cases, we can opportunistically | ||
644 | * cache decompressed data that goes beyond the requested range. */ | ||
645 | if (!(bio_flags & EXTENT_BIO_PARENT_LOCKED)) | ||
646 | add_ra_bio_pages(inode, em_start + em_len, cb); | ||
643 | 647 | ||
644 | /* include any pages we added in add_ra-bio_pages */ | 648 | /* include any pages we added in add_ra-bio_pages */ |
645 | uncompressed_len = bio->bi_vcnt * PAGE_CACHE_SIZE; | 649 | uncompressed_len = bio->bi_vcnt * PAGE_CACHE_SIZE; |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index a8d662b31830..df6e6c27782e 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -2764,11 +2764,12 @@ static int __do_readpage(struct extent_io_tree *tree, | |||
2764 | struct block_device *bdev; | 2764 | struct block_device *bdev; |
2765 | int ret; | 2765 | int ret; |
2766 | int nr = 0; | 2766 | int nr = 0; |
2767 | int parent_locked = *bio_flags & EXTENT_BIO_PARENT_LOCKED; | ||
2767 | size_t pg_offset = 0; | 2768 | size_t pg_offset = 0; |
2768 | size_t iosize; | 2769 | size_t iosize; |
2769 | size_t disk_io_size; | 2770 | size_t disk_io_size; |
2770 | size_t blocksize = inode->i_sb->s_blocksize; | 2771 | size_t blocksize = inode->i_sb->s_blocksize; |
2771 | unsigned long this_bio_flag = 0; | 2772 | unsigned long this_bio_flag = *bio_flags & EXTENT_BIO_PARENT_LOCKED; |
2772 | 2773 | ||
2773 | set_page_extent_mapped(page); | 2774 | set_page_extent_mapped(page); |
2774 | 2775 | ||
@@ -2807,15 +2808,18 @@ static int __do_readpage(struct extent_io_tree *tree, | |||
2807 | kunmap_atomic(userpage); | 2808 | kunmap_atomic(userpage); |
2808 | set_extent_uptodate(tree, cur, cur + iosize - 1, | 2809 | set_extent_uptodate(tree, cur, cur + iosize - 1, |
2809 | &cached, GFP_NOFS); | 2810 | &cached, GFP_NOFS); |
2810 | unlock_extent_cached(tree, cur, cur + iosize - 1, | 2811 | if (!parent_locked) |
2811 | &cached, GFP_NOFS); | 2812 | unlock_extent_cached(tree, cur, |
2813 | cur + iosize - 1, | ||
2814 | &cached, GFP_NOFS); | ||
2812 | break; | 2815 | break; |
2813 | } | 2816 | } |
2814 | em = __get_extent_map(inode, page, pg_offset, cur, | 2817 | em = __get_extent_map(inode, page, pg_offset, cur, |
2815 | end - cur + 1, get_extent, em_cached); | 2818 | end - cur + 1, get_extent, em_cached); |
2816 | if (IS_ERR_OR_NULL(em)) { | 2819 | if (IS_ERR_OR_NULL(em)) { |
2817 | SetPageError(page); | 2820 | SetPageError(page); |
2818 | unlock_extent(tree, cur, end); | 2821 | if (!parent_locked) |
2822 | unlock_extent(tree, cur, end); | ||
2819 | break; | 2823 | break; |
2820 | } | 2824 | } |
2821 | extent_offset = cur - em->start; | 2825 | extent_offset = cur - em->start; |
@@ -2823,7 +2827,7 @@ static int __do_readpage(struct extent_io_tree *tree, | |||
2823 | BUG_ON(end < cur); | 2827 | BUG_ON(end < cur); |
2824 | 2828 | ||
2825 | if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { | 2829 | if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { |
2826 | this_bio_flag = EXTENT_BIO_COMPRESSED; | 2830 | this_bio_flag |= EXTENT_BIO_COMPRESSED; |
2827 | extent_set_compress_type(&this_bio_flag, | 2831 | extent_set_compress_type(&this_bio_flag, |
2828 | em->compress_type); | 2832 | em->compress_type); |
2829 | } | 2833 | } |
@@ -2867,7 +2871,8 @@ static int __do_readpage(struct extent_io_tree *tree, | |||
2867 | if (test_range_bit(tree, cur, cur_end, | 2871 | if (test_range_bit(tree, cur, cur_end, |
2868 | EXTENT_UPTODATE, 1, NULL)) { | 2872 | EXTENT_UPTODATE, 1, NULL)) { |
2869 | check_page_uptodate(tree, page); | 2873 | check_page_uptodate(tree, page); |
2870 | unlock_extent(tree, cur, cur + iosize - 1); | 2874 | if (!parent_locked) |
2875 | unlock_extent(tree, cur, cur + iosize - 1); | ||
2871 | cur = cur + iosize; | 2876 | cur = cur + iosize; |
2872 | pg_offset += iosize; | 2877 | pg_offset += iosize; |
2873 | continue; | 2878 | continue; |
@@ -2877,7 +2882,8 @@ static int __do_readpage(struct extent_io_tree *tree, | |||
2877 | */ | 2882 | */ |
2878 | if (block_start == EXTENT_MAP_INLINE) { | 2883 | if (block_start == EXTENT_MAP_INLINE) { |
2879 | SetPageError(page); | 2884 | SetPageError(page); |
2880 | unlock_extent(tree, cur, cur + iosize - 1); | 2885 | if (!parent_locked) |
2886 | unlock_extent(tree, cur, cur + iosize - 1); | ||
2881 | cur = cur + iosize; | 2887 | cur = cur + iosize; |
2882 | pg_offset += iosize; | 2888 | pg_offset += iosize; |
2883 | continue; | 2889 | continue; |
@@ -2895,7 +2901,8 @@ static int __do_readpage(struct extent_io_tree *tree, | |||
2895 | *bio_flags = this_bio_flag; | 2901 | *bio_flags = this_bio_flag; |
2896 | } else { | 2902 | } else { |
2897 | SetPageError(page); | 2903 | SetPageError(page); |
2898 | unlock_extent(tree, cur, cur + iosize - 1); | 2904 | if (!parent_locked) |
2905 | unlock_extent(tree, cur, cur + iosize - 1); | ||
2899 | } | 2906 | } |
2900 | cur = cur + iosize; | 2907 | cur = cur + iosize; |
2901 | pg_offset += iosize; | 2908 | pg_offset += iosize; |
@@ -3021,6 +3028,20 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page, | |||
3021 | return ret; | 3028 | return ret; |
3022 | } | 3029 | } |
3023 | 3030 | ||
3031 | int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page, | ||
3032 | get_extent_t *get_extent, int mirror_num) | ||
3033 | { | ||
3034 | struct bio *bio = NULL; | ||
3035 | unsigned long bio_flags = EXTENT_BIO_PARENT_LOCKED; | ||
3036 | int ret; | ||
3037 | |||
3038 | ret = __do_readpage(tree, page, get_extent, NULL, &bio, mirror_num, | ||
3039 | &bio_flags, READ); | ||
3040 | if (bio) | ||
3041 | ret = submit_one_bio(READ, bio, mirror_num, bio_flags); | ||
3042 | return ret; | ||
3043 | } | ||
3044 | |||
3024 | static noinline void update_nr_written(struct page *page, | 3045 | static noinline void update_nr_written(struct page *page, |
3025 | struct writeback_control *wbc, | 3046 | struct writeback_control *wbc, |
3026 | unsigned long nr_written) | 3047 | unsigned long nr_written) |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index c450620a333f..3940a0386865 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -29,6 +29,7 @@ | |||
29 | */ | 29 | */ |
30 | #define EXTENT_BIO_COMPRESSED 1 | 30 | #define EXTENT_BIO_COMPRESSED 1 |
31 | #define EXTENT_BIO_TREE_LOG 2 | 31 | #define EXTENT_BIO_TREE_LOG 2 |
32 | #define EXTENT_BIO_PARENT_LOCKED 4 | ||
32 | #define EXTENT_BIO_FLAG_SHIFT 16 | 33 | #define EXTENT_BIO_FLAG_SHIFT 16 |
33 | 34 | ||
34 | /* these are bit numbers for test/set bit */ | 35 | /* these are bit numbers for test/set bit */ |
@@ -199,6 +200,8 @@ int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end, | |||
199 | int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end); | 200 | int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end); |
200 | int extent_read_full_page(struct extent_io_tree *tree, struct page *page, | 201 | int extent_read_full_page(struct extent_io_tree *tree, struct page *page, |
201 | get_extent_t *get_extent, int mirror_num); | 202 | get_extent_t *get_extent, int mirror_num); |
203 | int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page, | ||
204 | get_extent_t *get_extent, int mirror_num); | ||
202 | int __init extent_io_init(void); | 205 | int __init extent_io_init(void); |
203 | void extent_io_exit(void); | 206 | void extent_io_exit(void); |
204 | 207 | ||