aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMark Fasheh <mfasheh@suse.de>2013-08-06 14:42:50 -0400
committerChris Mason <chris.mason@fusionio.com>2013-09-01 08:04:59 -0400
commit4b384318a74e38eb248f74f9a92a700d2ce841f1 (patch)
tree5ef01855a2824b7c832e9303a19cfb2527c9d08d /fs
parent32b7c687c52a0b78a7d41ce6423c2fd8f5ca92da (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.c6
-rw-r--r--fs/btrfs/extent_io.c37
-rw-r--r--fs/btrfs/extent_io.h3
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
3031int 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
3024static noinline void update_nr_written(struct page *page, 3045static 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,
199int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end); 200int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
200int extent_read_full_page(struct extent_io_tree *tree, struct page *page, 201int 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);
203int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page,
204 get_extent_t *get_extent, int mirror_num);
202int __init extent_io_init(void); 205int __init extent_io_init(void);
203void extent_io_exit(void); 206void extent_io_exit(void);
204 207