diff options
Diffstat (limited to 'fs/btrfs/compression.c')
| -rw-r--r-- | fs/btrfs/compression.c | 138 | 
1 files changed, 43 insertions, 95 deletions
| diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index 10e6b282d09d..2c0b7b57fcd5 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -32,6 +32,7 @@  #include <linux/writeback.h>  #include <linux/bit_spinlock.h>  #include <linux/slab.h> +#include <linux/sched/mm.h>  #include "ctree.h"  #include "disk-io.h"  #include "transaction.h" @@ -42,48 +43,7 @@  #include "extent_io.h"  #include "extent_map.h" -struct compressed_bio { -	/* number of bios pending for this compressed extent */ -	refcount_t pending_bios; - -	/* the pages with the compressed data on them */ -	struct page **compressed_pages; - -	/* inode that owns this data */ -	struct inode *inode; - -	/* starting offset in the inode for our pages */ -	u64 start; - -	/* number of bytes in the inode we're working on */ -	unsigned long len; - -	/* number of bytes on disk */ -	unsigned long compressed_len; - -	/* the compression algorithm for this bio */ -	int compress_type; - -	/* number of compressed pages in the array */ -	unsigned long nr_pages; - -	/* IO errors */ -	int errors; -	int mirror_num; - -	/* for reads, this is the bio we are copying the data into */ -	struct bio *orig_bio; - -	/* -	 * the start of a variable length array of checksums only -	 * used by reads -	 */ -	u32 sums; -}; - -static int btrfs_decompress_bio(int type, struct page **pages_in, -				   u64 disk_start, struct bio *orig_bio, -				   size_t srclen); +static int btrfs_decompress_bio(struct compressed_bio *cb);  static inline int compressed_bio_size(struct btrfs_fs_info *fs_info,  				      unsigned long disk_size) @@ -94,12 +54,6 @@ static inline int compressed_bio_size(struct btrfs_fs_info *fs_info,  		(DIV_ROUND_UP(disk_size, fs_info->sectorsize)) * csum_size;  } -static struct bio *compressed_bio_alloc(struct block_device *bdev, -					u64 first_byte, gfp_t gfp_flags) -{ -	return btrfs_bio_alloc(bdev, first_byte >> 9, BIO_MAX_PAGES, gfp_flags); -} -  static int check_compressed_csum(struct btrfs_inode *inode,  				 struct compressed_bio *cb,  				 u64 disk_start) @@ -155,7 +109,7 @@ static void end_compressed_bio_read(struct bio *bio)  	unsigned long index;  	int ret; -	if (bio->bi_error) +	if (bio->bi_status)  		cb->errors = 1;  	/* if there are more bios still pending for this compressed @@ -173,11 +127,8 @@ static void end_compressed_bio_read(struct bio *bio)  	/* ok, we're the last bio for this extent, lets start  	 * the decompression.  	 */ -	ret = btrfs_decompress_bio(cb->compress_type, -				      cb->compressed_pages, -				      cb->start, -				      cb->orig_bio, -				      cb->compressed_len); +	ret = btrfs_decompress_bio(cb); +  csum_failed:  	if (ret)  		cb->errors = 1; @@ -268,7 +219,7 @@ static void end_compressed_bio_write(struct bio *bio)  	struct page *page;  	unsigned long index; -	if (bio->bi_error) +	if (bio->bi_status)  		cb->errors = 1;  	/* if there are more bios still pending for this compressed @@ -287,7 +238,7 @@ static void end_compressed_bio_write(struct bio *bio)  					 cb->start,  					 cb->start + cb->len - 1,  					 NULL, -					 bio->bi_error ? 0 : 1); +					 bio->bi_status ? 0 : 1);  	cb->compressed_pages[0]->mapping = NULL;  	end_compressed_writeback(inode, cb); @@ -320,7 +271,7 @@ out:   * This also checksums the file bytes and gets things ready for   * the end io hooks.   */ -int btrfs_submit_compressed_write(struct inode *inode, u64 start, +blk_status_t btrfs_submit_compressed_write(struct inode *inode, u64 start,  				 unsigned long len, u64 disk_start,  				 unsigned long compressed_len,  				 struct page **compressed_pages, @@ -335,13 +286,13 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,  	struct page *page;  	u64 first_byte = disk_start;  	struct block_device *bdev; -	int ret; +	blk_status_t ret;  	int skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;  	WARN_ON(start & ((u64)PAGE_SIZE - 1));  	cb = kmalloc(compressed_bio_size(fs_info, compressed_len), GFP_NOFS);  	if (!cb) -		return -ENOMEM; +		return BLK_STS_RESOURCE;  	refcount_set(&cb->pending_bios, 0);  	cb->errors = 0;  	cb->inode = inode; @@ -355,11 +306,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,  	bdev = fs_info->fs_devices->latest_bdev; -	bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); -	if (!bio) { -		kfree(cb); -		return -ENOMEM; -	} +	bio = btrfs_bio_alloc(bdev, first_byte);  	bio_set_op_attrs(bio, REQ_OP_WRITE, 0);  	bio->bi_private = cb;  	bio->bi_end_io = end_compressed_bio_write; @@ -368,17 +315,17 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,  	/* create and submit bios for the compressed pages */  	bytes_left = compressed_len;  	for (pg_index = 0; pg_index < cb->nr_pages; pg_index++) { +		int submit = 0; +  		page = compressed_pages[pg_index];  		page->mapping = inode->i_mapping;  		if (bio->bi_iter.bi_size) -			ret = io_tree->ops->merge_bio_hook(page, 0, +			submit = io_tree->ops->merge_bio_hook(page, 0,  							   PAGE_SIZE,  							   bio, 0); -		else -			ret = 0;  		page->mapping = NULL; -		if (ret || bio_add_page(bio, page, PAGE_SIZE, 0) < +		if (submit || bio_add_page(bio, page, PAGE_SIZE, 0) <  		    PAGE_SIZE) {  			bio_get(bio); @@ -400,14 +347,13 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,  			ret = btrfs_map_bio(fs_info, bio, 0, 1);  			if (ret) { -				bio->bi_error = ret; +				bio->bi_status = ret;  				bio_endio(bio);  			}  			bio_put(bio); -			bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); -			BUG_ON(!bio); +			bio = btrfs_bio_alloc(bdev, first_byte);  			bio_set_op_attrs(bio, REQ_OP_WRITE, 0);  			bio->bi_private = cb;  			bio->bi_end_io = end_compressed_bio_write; @@ -434,7 +380,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,  	ret = btrfs_map_bio(fs_info, bio, 0, 1);  	if (ret) { -		bio->bi_error = ret; +		bio->bi_status = ret;  		bio_endio(bio);  	} @@ -569,7 +515,7 @@ next:   * After the compressed pages are read, we copy the bytes into the   * bio we were passed and then call the bio end_io calls   */ -int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, +blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,  				 int mirror_num, unsigned long bio_flags)  {  	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); @@ -586,7 +532,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,  	u64 em_len;  	u64 em_start;  	struct extent_map *em; -	int ret = -ENOMEM; +	blk_status_t ret = BLK_STS_RESOURCE;  	int faili = 0;  	u32 *sums; @@ -600,7 +546,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,  				   PAGE_SIZE);  	read_unlock(&em_tree->lock);  	if (!em) -		return -EIO; +		return BLK_STS_IOERR;  	compressed_len = em->block_len;  	cb = kmalloc(compressed_bio_size(fs_info, compressed_len), GFP_NOFS); @@ -638,7 +584,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,  							      __GFP_HIGHMEM);  		if (!cb->compressed_pages[pg_index]) {  			faili = pg_index - 1; -			ret = -ENOMEM; +			ret = BLK_STS_RESOURCE;  			goto fail2;  		}  	} @@ -650,28 +596,26 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,  	/* include any pages we added in add_ra-bio_pages */  	cb->len = bio->bi_iter.bi_size; -	comp_bio = compressed_bio_alloc(bdev, cur_disk_byte, GFP_NOFS); -	if (!comp_bio) -		goto fail2; +	comp_bio = btrfs_bio_alloc(bdev, cur_disk_byte);  	bio_set_op_attrs (comp_bio, REQ_OP_READ, 0);  	comp_bio->bi_private = cb;  	comp_bio->bi_end_io = end_compressed_bio_read;  	refcount_set(&cb->pending_bios, 1);  	for (pg_index = 0; pg_index < nr_pages; pg_index++) { +		int submit = 0; +  		page = cb->compressed_pages[pg_index];  		page->mapping = inode->i_mapping;  		page->index = em_start >> PAGE_SHIFT;  		if (comp_bio->bi_iter.bi_size) -			ret = tree->ops->merge_bio_hook(page, 0, +			submit = tree->ops->merge_bio_hook(page, 0,  							PAGE_SIZE,  							comp_bio, 0); -		else -			ret = 0;  		page->mapping = NULL; -		if (ret || bio_add_page(comp_bio, page, PAGE_SIZE, 0) < +		if (submit || bio_add_page(comp_bio, page, PAGE_SIZE, 0) <  		    PAGE_SIZE) {  			bio_get(comp_bio); @@ -697,15 +641,13 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,  			ret = btrfs_map_bio(fs_info, comp_bio, mirror_num, 0);  			if (ret) { -				comp_bio->bi_error = ret; +				comp_bio->bi_status = ret;  				bio_endio(comp_bio);  			}  			bio_put(comp_bio); -			comp_bio = compressed_bio_alloc(bdev, cur_disk_byte, -							GFP_NOFS); -			BUG_ON(!comp_bio); +			comp_bio = btrfs_bio_alloc(bdev, cur_disk_byte);  			bio_set_op_attrs(comp_bio, REQ_OP_READ, 0);  			comp_bio->bi_private = cb;  			comp_bio->bi_end_io = end_compressed_bio_read; @@ -726,7 +668,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,  	ret = btrfs_map_bio(fs_info, comp_bio, mirror_num, 0);  	if (ret) { -		comp_bio->bi_error = ret; +		comp_bio->bi_status = ret;  		bio_endio(comp_bio);  	} @@ -801,6 +743,7 @@ static struct list_head *find_workspace(int type)  	struct list_head *workspace;  	int cpus = num_online_cpus();  	int idx = type - 1; +	unsigned nofs_flag;  	struct list_head *idle_ws	= &btrfs_comp_ws[idx].idle_ws;  	spinlock_t *ws_lock		= &btrfs_comp_ws[idx].ws_lock; @@ -830,7 +773,15 @@ again:  	atomic_inc(total_ws);  	spin_unlock(ws_lock); +	/* +	 * Allocation helpers call vmalloc that can't use GFP_NOFS, so we have +	 * to turn it off here because we might get called from the restricted +	 * context of btrfs_compress_bio/btrfs_compress_pages +	 */ +	nofs_flag = memalloc_nofs_save();  	workspace = btrfs_compress_op[idx]->alloc_workspace(); +	memalloc_nofs_restore(nofs_flag); +  	if (IS_ERR(workspace)) {  		atomic_dec(total_ws);  		wake_up(ws_wait); @@ -961,19 +912,16 @@ int btrfs_compress_pages(int type, struct address_space *mapping,   * be contiguous.  They all correspond to the range of bytes covered by   * the compressed extent.   */ -static int btrfs_decompress_bio(int type, struct page **pages_in, -				   u64 disk_start, struct bio *orig_bio, -				   size_t srclen) +static int btrfs_decompress_bio(struct compressed_bio *cb)  {  	struct list_head *workspace;  	int ret; +	int type = cb->compress_type;  	workspace = find_workspace(type); - -	ret = btrfs_compress_op[type-1]->decompress_bio(workspace, pages_in, -							 disk_start, orig_bio, -							 srclen); +	ret = btrfs_compress_op[type - 1]->decompress_bio(workspace, cb);  	free_workspace(type, workspace); +  	return ret;  } |