diff options
Diffstat (limited to 'fs/btrfs/compression.c')
| -rw-r--r-- | fs/btrfs/compression.c | 51 | 
1 files changed, 43 insertions, 8 deletions
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index d3220d31d3cb..e9df8862012c 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -224,16 +224,19 @@ out:   * Clear the writeback bits on all of the file   * pages for a compressed write   */ -static noinline void end_compressed_writeback(struct inode *inode, u64 start, -					      unsigned long ram_size) +static noinline void end_compressed_writeback(struct inode *inode, +					      const struct compressed_bio *cb)  { -	unsigned long index = start >> PAGE_CACHE_SHIFT; -	unsigned long end_index = (start + ram_size - 1) >> PAGE_CACHE_SHIFT; +	unsigned long index = cb->start >> PAGE_CACHE_SHIFT; +	unsigned long end_index = (cb->start + cb->len - 1) >> PAGE_CACHE_SHIFT;  	struct page *pages[16];  	unsigned long nr_pages = end_index - index + 1;  	int i;  	int ret; +	if (cb->errors) +		mapping_set_error(inode->i_mapping, -EIO); +  	while (nr_pages > 0) {  		ret = find_get_pages_contig(inode->i_mapping, index,  				     min_t(unsigned long, @@ -244,6 +247,8 @@ static noinline void end_compressed_writeback(struct inode *inode, u64 start,  			continue;  		}  		for (i = 0; i < ret; i++) { +			if (cb->errors) +				SetPageError(pages[i]);  			end_page_writeback(pages[i]);  			page_cache_release(pages[i]);  		} @@ -287,10 +292,11 @@ static void end_compressed_bio_write(struct bio *bio, int err)  	tree->ops->writepage_end_io_hook(cb->compressed_pages[0],  					 cb->start,  					 cb->start + cb->len - 1, -					 NULL, 1); +					 NULL, +					 err ? 0 : 1);  	cb->compressed_pages[0]->mapping = NULL; -	end_compressed_writeback(inode, cb->start, cb->len); +	end_compressed_writeback(inode, cb);  	/* note, our inode could be gone now */  	/* @@ -1011,8 +1017,6 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,  		bytes = min(bytes, working_bytes);  		kaddr = kmap_atomic(page_out);  		memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); -		if (*pg_index == (vcnt - 1) && *pg_offset == 0) -			memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);  		kunmap_atomic(kaddr);  		flush_dcache_page(page_out); @@ -1054,3 +1058,34 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,  	return 1;  } + +/* + * When uncompressing data, we need to make sure and zero any parts of + * the biovec that were not filled in by the decompression code.  pg_index + * and pg_offset indicate the last page and the last offset of that page + * that have been filled in.  This will zero everything remaining in the + * biovec. + */ +void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt, +				   unsigned long pg_index, +				   unsigned long pg_offset) +{ +	while (pg_index < vcnt) { +		struct page *page = bvec[pg_index].bv_page; +		unsigned long off = bvec[pg_index].bv_offset; +		unsigned long len = bvec[pg_index].bv_len; + +		if (pg_offset < off) +			pg_offset = off; +		if (pg_offset < off + len) { +			unsigned long bytes = off + len - pg_offset; +			char *kaddr; + +			kaddr = kmap_atomic(page); +			memset(kaddr + pg_offset, 0, bytes); +			kunmap_atomic(kaddr); +		} +		pg_index++; +		pg_offset = 0; +	} +}  |