mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 23:34:05 +08:00
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>
This commit is contained in:
parent
32b7c687c5
commit
4b384318a7
@ -639,7 +639,11 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||
faili = nr_pages - 1;
|
||||
cb->nr_pages = nr_pages;
|
||||
|
||||
add_ra_bio_pages(inode, em_start + em_len, cb);
|
||||
/* 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 */
|
||||
uncompressed_len = bio->bi_vcnt * PAGE_CACHE_SIZE;
|
||||
|
@ -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,15 +2808,18 @@ 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,
|
||||
&cached, GFP_NOFS);
|
||||
if (!parent_locked)
|
||||
unlock_extent_cached(tree, cur,
|
||||
cur + iosize - 1,
|
||||
&cached, GFP_NOFS);
|
||||
break;
|
||||
}
|
||||
em = __get_extent_map(inode, page, pg_offset, cur,
|
||||
end - cur + 1, get_extent, em_cached);
|
||||
if (IS_ERR_OR_NULL(em)) {
|
||||
SetPageError(page);
|
||||
unlock_extent(tree, cur, end);
|
||||
if (!parent_locked)
|
||||
unlock_extent(tree, cur, end);
|
||||
break;
|
||||
}
|
||||
extent_offset = cur - em->start;
|
||||
@ -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,7 +2871,8 @@ 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);
|
||||
unlock_extent(tree, cur, cur + iosize - 1);
|
||||
if (!parent_locked)
|
||||
unlock_extent(tree, cur, cur + iosize - 1);
|
||||
cur = cur + iosize;
|
||||
pg_offset += iosize;
|
||||
continue;
|
||||
@ -2877,7 +2882,8 @@ static int __do_readpage(struct extent_io_tree *tree,
|
||||
*/
|
||||
if (block_start == EXTENT_MAP_INLINE) {
|
||||
SetPageError(page);
|
||||
unlock_extent(tree, cur, cur + iosize - 1);
|
||||
if (!parent_locked)
|
||||
unlock_extent(tree, cur, cur + iosize - 1);
|
||||
cur = cur + iosize;
|
||||
pg_offset += iosize;
|
||||
continue;
|
||||
@ -2895,7 +2901,8 @@ static int __do_readpage(struct extent_io_tree *tree,
|
||||
*bio_flags = this_bio_flag;
|
||||
} else {
|
||||
SetPageError(page);
|
||||
unlock_extent(tree, cur, cur + iosize - 1);
|
||||
if (!parent_locked)
|
||||
unlock_extent(tree, cur, cur + iosize - 1);
|
||||
}
|
||||
cur = cur + iosize;
|
||||
pg_offset += 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)
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user