Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b384318 authored by Mark Fasheh's avatar Mark Fasheh Committed by Chris Mason
Browse files

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: default avatarMark Fasheh <mfasheh@suse.de>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
Signed-off-by: default avatarChris Mason <chris.mason@fusionio.com>
parent 32b7c687
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -639,6 +639,10 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
	faili = nr_pages - 1;
	cb->nr_pages = nr_pages;

	/* In the parent-locked case, we only locked the range we are
	 * interested in.  In all other cases, we can opportunistically
	 * cache decompressed data that goes beyond the requested range. */
	if (!(bio_flags & EXTENT_BIO_PARENT_LOCKED))
		add_ra_bio_pages(inode, em_start + em_len, cb);

	/* include any pages we added in add_ra-bio_pages */
+29 −8
Original line number Diff line number Diff line
@@ -2764,11 +2764,12 @@ static int __do_readpage(struct extent_io_tree *tree,
	struct block_device *bdev;
	int ret;
	int nr = 0;
	int parent_locked = *bio_flags & EXTENT_BIO_PARENT_LOCKED;
	size_t pg_offset = 0;
	size_t iosize;
	size_t disk_io_size;
	size_t blocksize = inode->i_sb->s_blocksize;
	unsigned long this_bio_flag = 0;
	unsigned long this_bio_flag = *bio_flags & EXTENT_BIO_PARENT_LOCKED;

	set_page_extent_mapped(page);

@@ -2807,7 +2808,9 @@ static int __do_readpage(struct extent_io_tree *tree,
			kunmap_atomic(userpage);
			set_extent_uptodate(tree, cur, cur + iosize - 1,
					    &cached, GFP_NOFS);
			unlock_extent_cached(tree, cur, cur + iosize - 1,
			if (!parent_locked)
				unlock_extent_cached(tree, cur,
						     cur + iosize - 1,
						     &cached, GFP_NOFS);
			break;
		}
@@ -2815,6 +2818,7 @@ static int __do_readpage(struct extent_io_tree *tree,
				      end - cur + 1, get_extent, em_cached);
		if (IS_ERR_OR_NULL(em)) {
			SetPageError(page);
			if (!parent_locked)
				unlock_extent(tree, cur, end);
			break;
		}
@@ -2823,7 +2827,7 @@ static int __do_readpage(struct extent_io_tree *tree,
		BUG_ON(end < cur);

		if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
			this_bio_flag = EXTENT_BIO_COMPRESSED;
			this_bio_flag |= EXTENT_BIO_COMPRESSED;
			extent_set_compress_type(&this_bio_flag,
						 em->compress_type);
		}
@@ -2867,6 +2871,7 @@ static int __do_readpage(struct extent_io_tree *tree,
		if (test_range_bit(tree, cur, cur_end,
				   EXTENT_UPTODATE, 1, NULL)) {
			check_page_uptodate(tree, page);
			if (!parent_locked)
				unlock_extent(tree, cur, cur + iosize - 1);
			cur = cur + iosize;
			pg_offset += iosize;
@@ -2877,6 +2882,7 @@ static int __do_readpage(struct extent_io_tree *tree,
		 */
		if (block_start == EXTENT_MAP_INLINE) {
			SetPageError(page);
			if (!parent_locked)
				unlock_extent(tree, cur, cur + iosize - 1);
			cur = cur + iosize;
			pg_offset += iosize;
@@ -2895,6 +2901,7 @@ static int __do_readpage(struct extent_io_tree *tree,
			*bio_flags = this_bio_flag;
		} else {
			SetPageError(page);
			if (!parent_locked)
				unlock_extent(tree, cur, cur + iosize - 1);
		}
		cur = cur + iosize;
@@ -3021,6 +3028,20 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
	return ret;
}

int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page,
				 get_extent_t *get_extent, int mirror_num)
{
	struct bio *bio = NULL;
	unsigned long bio_flags = EXTENT_BIO_PARENT_LOCKED;
	int ret;

	ret = __do_readpage(tree, page, get_extent, NULL, &bio, mirror_num,
				      &bio_flags, READ);
	if (bio)
		ret = submit_one_bio(READ, bio, mirror_num, bio_flags);
	return ret;
}

static noinline void update_nr_written(struct page *page,
				      struct writeback_control *wbc,
				      unsigned long nr_written)
+3 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
 */
#define EXTENT_BIO_COMPRESSED 1
#define EXTENT_BIO_TREE_LOG 2
#define EXTENT_BIO_PARENT_LOCKED 4
#define EXTENT_BIO_FLAG_SHIFT 16

/* 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,
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
			  get_extent_t *get_extent, int mirror_num);
int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page,
				 get_extent_t *get_extent, int mirror_num);
int __init extent_io_init(void);
void extent_io_exit(void);