diff options
Diffstat (limited to 'fs/btrfs/inode.c')
| -rw-r--r-- | fs/btrfs/inode.c | 42 | 
1 files changed, 27 insertions, 15 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index c40060cc481f..5e71f1ea3391 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6709,6 +6709,20 @@ static noinline int uncompress_inline(struct btrfs_path *path,  	max_size = min_t(unsigned long, PAGE_SIZE, max_size);  	ret = btrfs_decompress(compress_type, tmp, page,  			       extent_offset, inline_size, max_size); + +	/* +	 * decompression code contains a memset to fill in any space between the end +	 * of the uncompressed data and the end of max_size in case the decompressed +	 * data ends up shorter than ram_bytes.  That doesn't cover the hole between +	 * the end of an inline extent and the beginning of the next block, so we +	 * cover that region here. +	 */ + +	if (max_size + pg_offset < PAGE_SIZE) { +		char *map = kmap(page); +		memset(map + pg_offset + max_size, 0, PAGE_SIZE - max_size - pg_offset); +		kunmap(page); +	}  	kfree(tmp);  	return ret;  } @@ -7896,7 +7910,6 @@ struct btrfs_retry_complete {  static void btrfs_retry_endio_nocsum(struct bio *bio)  {  	struct btrfs_retry_complete *done = bio->bi_private; -	struct inode *inode;  	struct bio_vec *bvec;  	int i; @@ -7904,12 +7917,12 @@ static void btrfs_retry_endio_nocsum(struct bio *bio)  		goto end;  	ASSERT(bio->bi_vcnt == 1); -	inode = bio->bi_io_vec->bv_page->mapping->host; -	ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(inode)); +	ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(done->inode));  	done->uptodate = 1;  	bio_for_each_segment_all(bvec, bio, i) -	clean_io_failure(BTRFS_I(done->inode), done->start, bvec->bv_page, 0); +		clean_io_failure(BTRFS_I(done->inode), done->start, +				 bvec->bv_page, 0);  end:  	complete(&done->done);  	bio_put(bio); @@ -7959,8 +7972,10 @@ next_block_or_try_again:  		start += sectorsize; -		if (nr_sectors--) { +		nr_sectors--; +		if (nr_sectors) {  			pgoff += sectorsize; +			ASSERT(pgoff < PAGE_SIZE);  			goto next_block_or_try_again;  		}  	} @@ -7972,9 +7987,7 @@ static void btrfs_retry_endio(struct bio *bio)  {  	struct btrfs_retry_complete *done = bio->bi_private;  	struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); -	struct inode *inode;  	struct bio_vec *bvec; -	u64 start;  	int uptodate;  	int ret;  	int i; @@ -7984,11 +7997,8 @@ static void btrfs_retry_endio(struct bio *bio)  	uptodate = 1; -	start = done->start; -  	ASSERT(bio->bi_vcnt == 1); -	inode = bio->bi_io_vec->bv_page->mapping->host; -	ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(inode)); +	ASSERT(bio->bi_io_vec->bv_len == btrfs_inode_sectorsize(done->inode));  	bio_for_each_segment_all(bvec, bio, i) {  		ret = __readpage_endio_check(done->inode, io_bio, i, @@ -8066,8 +8076,10 @@ next:  		ASSERT(nr_sectors); -		if (--nr_sectors) { +		nr_sectors--; +		if (nr_sectors) {  			pgoff += sectorsize; +			ASSERT(pgoff < PAGE_SIZE);  			goto next_block;  		}  	} @@ -10509,9 +10521,9 @@ out_inode:  }  __attribute__((const)) -static int dummy_readpage_io_failed_hook(struct page *page, int failed_mirror) +static int btrfs_readpage_io_failed_hook(struct page *page, int failed_mirror)  { -	return 0; +	return -EAGAIN;  }  static const struct inode_operations btrfs_dir_inode_operations = { @@ -10556,7 +10568,7 @@ static const struct extent_io_ops btrfs_extent_io_ops = {  	.submit_bio_hook = btrfs_submit_bio_hook,  	.readpage_end_io_hook = btrfs_readpage_end_io_hook,  	.merge_bio_hook = btrfs_merge_bio_hook, -	.readpage_io_failed_hook = dummy_readpage_io_failed_hook, +	.readpage_io_failed_hook = btrfs_readpage_io_failed_hook,  	/* optional callbacks */  	.fill_delalloc = run_delalloc_range,  | 
