btrfs: use bio iterators for the decompression handlers
Pass the full bio to the decompression routines and use bio iterators to iterate over the data in the bio. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
0c476a5d7f
commit
974b1adc3b
@ -81,9 +81,9 @@ struct compressed_bio {
|
|||||||
u32 sums;
|
u32 sums;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int btrfs_decompress_biovec(int type, struct page **pages_in,
|
static int btrfs_decompress_bio(int type, struct page **pages_in,
|
||||||
u64 disk_start, struct bio_vec *bvec,
|
u64 disk_start, struct bio *orig_bio,
|
||||||
int vcnt, size_t srclen);
|
size_t srclen);
|
||||||
|
|
||||||
static inline int compressed_bio_size(struct btrfs_root *root,
|
static inline int compressed_bio_size(struct btrfs_root *root,
|
||||||
unsigned long disk_size)
|
unsigned long disk_size)
|
||||||
@ -175,11 +175,10 @@ static void end_compressed_bio_read(struct bio *bio)
|
|||||||
/* ok, we're the last bio for this extent, lets start
|
/* ok, we're the last bio for this extent, lets start
|
||||||
* the decompression.
|
* the decompression.
|
||||||
*/
|
*/
|
||||||
ret = btrfs_decompress_biovec(cb->compress_type,
|
ret = btrfs_decompress_bio(cb->compress_type,
|
||||||
cb->compressed_pages,
|
cb->compressed_pages,
|
||||||
cb->start,
|
cb->start,
|
||||||
cb->orig_bio->bi_io_vec,
|
cb->orig_bio,
|
||||||
cb->orig_bio->bi_vcnt,
|
|
||||||
cb->compressed_len);
|
cb->compressed_len);
|
||||||
csum_failed:
|
csum_failed:
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -959,9 +958,7 @@ int btrfs_compress_pages(int type, struct address_space *mapping,
|
|||||||
*
|
*
|
||||||
* disk_start is the starting logical offset of this array in the file
|
* disk_start is the starting logical offset of this array in the file
|
||||||
*
|
*
|
||||||
* bvec is a bio_vec of pages from the file that we want to decompress into
|
* orig_bio contains the pages from the file that we want to decompress into
|
||||||
*
|
|
||||||
* vcnt is the count of pages in the biovec
|
|
||||||
*
|
*
|
||||||
* srclen is the number of bytes in pages_in
|
* srclen is the number of bytes in pages_in
|
||||||
*
|
*
|
||||||
@ -970,18 +967,18 @@ int btrfs_compress_pages(int type, struct address_space *mapping,
|
|||||||
* be contiguous. They all correspond to the range of bytes covered by
|
* be contiguous. They all correspond to the range of bytes covered by
|
||||||
* the compressed extent.
|
* the compressed extent.
|
||||||
*/
|
*/
|
||||||
static int btrfs_decompress_biovec(int type, struct page **pages_in,
|
static int btrfs_decompress_bio(int type, struct page **pages_in,
|
||||||
u64 disk_start, struct bio_vec *bvec,
|
u64 disk_start, struct bio *orig_bio,
|
||||||
int vcnt, size_t srclen)
|
size_t srclen)
|
||||||
{
|
{
|
||||||
struct list_head *workspace;
|
struct list_head *workspace;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
workspace = find_workspace(type);
|
workspace = find_workspace(type);
|
||||||
|
|
||||||
ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in,
|
ret = btrfs_compress_op[type-1]->decompress_bio(workspace, pages_in,
|
||||||
disk_start,
|
disk_start, orig_bio,
|
||||||
bvec, vcnt, srclen);
|
srclen);
|
||||||
free_workspace(type, workspace);
|
free_workspace(type, workspace);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1021,9 +1018,7 @@ void btrfs_exit_compress(void)
|
|||||||
*/
|
*/
|
||||||
int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
|
int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
|
||||||
unsigned long total_out, u64 disk_start,
|
unsigned long total_out, u64 disk_start,
|
||||||
struct bio_vec *bvec, int vcnt,
|
struct bio *bio)
|
||||||
unsigned long *pg_index,
|
|
||||||
unsigned long *pg_offset)
|
|
||||||
{
|
{
|
||||||
unsigned long buf_offset;
|
unsigned long buf_offset;
|
||||||
unsigned long current_buf_start;
|
unsigned long current_buf_start;
|
||||||
@ -1031,13 +1026,13 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
|
|||||||
unsigned long working_bytes = total_out - buf_start;
|
unsigned long working_bytes = total_out - buf_start;
|
||||||
unsigned long bytes;
|
unsigned long bytes;
|
||||||
char *kaddr;
|
char *kaddr;
|
||||||
struct page *page_out = bvec[*pg_index].bv_page;
|
struct bio_vec bvec = bio_iter_iovec(bio, bio->bi_iter);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* start byte is the first byte of the page we're currently
|
* start byte is the first byte of the page we're currently
|
||||||
* copying into relative to the start of the compressed data.
|
* copying into relative to the start of the compressed data.
|
||||||
*/
|
*/
|
||||||
start_byte = page_offset(page_out) - disk_start;
|
start_byte = page_offset(bvec.bv_page) - disk_start;
|
||||||
|
|
||||||
/* we haven't yet hit data corresponding to this page */
|
/* we haven't yet hit data corresponding to this page */
|
||||||
if (total_out <= start_byte)
|
if (total_out <= start_byte)
|
||||||
@ -1057,80 +1052,46 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
|
|||||||
|
|
||||||
/* copy bytes from the working buffer into the pages */
|
/* copy bytes from the working buffer into the pages */
|
||||||
while (working_bytes > 0) {
|
while (working_bytes > 0) {
|
||||||
bytes = min(PAGE_SIZE - *pg_offset,
|
bytes = min_t(unsigned long, bvec.bv_len,
|
||||||
PAGE_SIZE - buf_offset);
|
PAGE_SIZE - buf_offset);
|
||||||
bytes = min(bytes, working_bytes);
|
bytes = min(bytes, working_bytes);
|
||||||
kaddr = kmap_atomic(page_out);
|
|
||||||
memcpy(kaddr + *pg_offset, buf + buf_offset, bytes);
|
|
||||||
kunmap_atomic(kaddr);
|
|
||||||
flush_dcache_page(page_out);
|
|
||||||
|
|
||||||
*pg_offset += bytes;
|
kaddr = kmap_atomic(bvec.bv_page);
|
||||||
|
memcpy(kaddr + bvec.bv_offset, buf + buf_offset, bytes);
|
||||||
|
kunmap_atomic(kaddr);
|
||||||
|
flush_dcache_page(bvec.bv_page);
|
||||||
|
|
||||||
buf_offset += bytes;
|
buf_offset += bytes;
|
||||||
working_bytes -= bytes;
|
working_bytes -= bytes;
|
||||||
current_buf_start += bytes;
|
current_buf_start += bytes;
|
||||||
|
|
||||||
/* check if we need to pick another page */
|
/* check if we need to pick another page */
|
||||||
if (*pg_offset == PAGE_SIZE) {
|
bio_advance(bio, bytes);
|
||||||
(*pg_index)++;
|
if (!bio->bi_iter.bi_size)
|
||||||
if (*pg_index >= vcnt)
|
return 0;
|
||||||
return 0;
|
bvec = bio_iter_iovec(bio, bio->bi_iter);
|
||||||
|
|
||||||
page_out = bvec[*pg_index].bv_page;
|
start_byte = page_offset(bvec.bv_page) - disk_start;
|
||||||
*pg_offset = 0;
|
|
||||||
start_byte = page_offset(page_out) - disk_start;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* make sure our new page is covered by this
|
* make sure our new page is covered by this
|
||||||
* working buffer
|
* working buffer
|
||||||
*/
|
*/
|
||||||
if (total_out <= start_byte)
|
if (total_out <= start_byte)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the next page in the biovec might not be adjacent
|
* the next page in the biovec might not be adjacent
|
||||||
* to the last page, but it might still be found
|
* to the last page, but it might still be found
|
||||||
* inside this working buffer. bump our offset pointer
|
* inside this working buffer. bump our offset pointer
|
||||||
*/
|
*/
|
||||||
if (total_out > start_byte &&
|
if (total_out > start_byte &&
|
||||||
current_buf_start < start_byte) {
|
current_buf_start < start_byte) {
|
||||||
buf_offset = start_byte - buf_start;
|
buf_offset = start_byte - buf_start;
|
||||||
working_bytes = total_out - start_byte;
|
working_bytes = total_out - start_byte;
|
||||||
current_buf_start = buf_start + buf_offset;
|
current_buf_start = buf_start + buf_offset;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -34,9 +34,7 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
|
|||||||
unsigned long start_byte, size_t srclen, size_t destlen);
|
unsigned long start_byte, size_t srclen, size_t destlen);
|
||||||
int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
|
int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
|
||||||
unsigned long total_out, u64 disk_start,
|
unsigned long total_out, u64 disk_start,
|
||||||
struct bio_vec *bvec, int vcnt,
|
struct bio *bio);
|
||||||
unsigned long *pg_index,
|
|
||||||
unsigned long *pg_offset);
|
|
||||||
|
|
||||||
int btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
int btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
||||||
unsigned long len, u64 disk_start,
|
unsigned long len, u64 disk_start,
|
||||||
@ -45,9 +43,6 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
|||||||
unsigned long nr_pages);
|
unsigned long nr_pages);
|
||||||
int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||||
int mirror_num, unsigned long bio_flags);
|
int mirror_num, unsigned long bio_flags);
|
||||||
void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt,
|
|
||||||
unsigned long pg_index,
|
|
||||||
unsigned long pg_offset);
|
|
||||||
|
|
||||||
enum btrfs_compression_type {
|
enum btrfs_compression_type {
|
||||||
BTRFS_COMPRESS_NONE = 0,
|
BTRFS_COMPRESS_NONE = 0,
|
||||||
@ -72,11 +67,10 @@ struct btrfs_compress_op {
|
|||||||
unsigned long *total_out,
|
unsigned long *total_out,
|
||||||
unsigned long max_out);
|
unsigned long max_out);
|
||||||
|
|
||||||
int (*decompress_biovec)(struct list_head *workspace,
|
int (*decompress_bio)(struct list_head *workspace,
|
||||||
struct page **pages_in,
|
struct page **pages_in,
|
||||||
u64 disk_start,
|
u64 disk_start,
|
||||||
struct bio_vec *bvec,
|
struct bio *orig_bio,
|
||||||
int vcnt,
|
|
||||||
size_t srclen);
|
size_t srclen);
|
||||||
|
|
||||||
int (*decompress)(struct list_head *workspace,
|
int (*decompress)(struct list_head *workspace,
|
||||||
|
@ -254,25 +254,21 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lzo_decompress_biovec(struct list_head *ws,
|
static int lzo_decompress_bio(struct list_head *ws,
|
||||||
struct page **pages_in,
|
struct page **pages_in,
|
||||||
u64 disk_start,
|
u64 disk_start,
|
||||||
struct bio_vec *bvec,
|
struct bio *orig_bio,
|
||||||
int vcnt,
|
|
||||||
size_t srclen)
|
size_t srclen)
|
||||||
{
|
{
|
||||||
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
||||||
int ret = 0, ret2;
|
int ret = 0, ret2;
|
||||||
char *data_in;
|
char *data_in;
|
||||||
unsigned long page_in_index = 0;
|
unsigned long page_in_index = 0;
|
||||||
unsigned long page_out_index = 0;
|
|
||||||
unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
|
unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
|
||||||
unsigned long buf_start;
|
unsigned long buf_start;
|
||||||
unsigned long buf_offset = 0;
|
unsigned long buf_offset = 0;
|
||||||
unsigned long bytes;
|
unsigned long bytes;
|
||||||
unsigned long working_bytes;
|
unsigned long working_bytes;
|
||||||
unsigned long pg_offset;
|
|
||||||
|
|
||||||
size_t in_len;
|
size_t in_len;
|
||||||
size_t out_len;
|
size_t out_len;
|
||||||
unsigned long in_offset;
|
unsigned long in_offset;
|
||||||
@ -292,7 +288,6 @@ static int lzo_decompress_biovec(struct list_head *ws,
|
|||||||
in_page_bytes_left = PAGE_SIZE - LZO_LEN;
|
in_page_bytes_left = PAGE_SIZE - LZO_LEN;
|
||||||
|
|
||||||
tot_out = 0;
|
tot_out = 0;
|
||||||
pg_offset = 0;
|
|
||||||
|
|
||||||
while (tot_in < tot_len) {
|
while (tot_in < tot_len) {
|
||||||
in_len = read_compress_length(data_in + in_offset);
|
in_len = read_compress_length(data_in + in_offset);
|
||||||
@ -365,16 +360,14 @@ cont:
|
|||||||
tot_out += out_len;
|
tot_out += out_len;
|
||||||
|
|
||||||
ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
|
ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
|
||||||
tot_out, disk_start,
|
tot_out, disk_start, orig_bio);
|
||||||
bvec, vcnt,
|
|
||||||
&page_out_index, &pg_offset);
|
|
||||||
if (ret2 == 0)
|
if (ret2 == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
kunmap(pages_in[page_in_index]);
|
kunmap(pages_in[page_in_index]);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
|
zero_fill_bio(orig_bio);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,6 +431,6 @@ const struct btrfs_compress_op btrfs_lzo_compress = {
|
|||||||
.alloc_workspace = lzo_alloc_workspace,
|
.alloc_workspace = lzo_alloc_workspace,
|
||||||
.free_workspace = lzo_free_workspace,
|
.free_workspace = lzo_free_workspace,
|
||||||
.compress_pages = lzo_compress_pages,
|
.compress_pages = lzo_compress_pages,
|
||||||
.decompress_biovec = lzo_decompress_biovec,
|
.decompress_bio = lzo_decompress_bio,
|
||||||
.decompress = lzo_decompress,
|
.decompress = lzo_decompress,
|
||||||
};
|
};
|
||||||
|
@ -210,10 +210,9 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
|
static int zlib_decompress_bio(struct list_head *ws, struct page **pages_in,
|
||||||
u64 disk_start,
|
u64 disk_start,
|
||||||
struct bio_vec *bvec,
|
struct bio *orig_bio,
|
||||||
int vcnt,
|
|
||||||
size_t srclen)
|
size_t srclen)
|
||||||
{
|
{
|
||||||
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
||||||
@ -222,10 +221,8 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
|
|||||||
char *data_in;
|
char *data_in;
|
||||||
size_t total_out = 0;
|
size_t total_out = 0;
|
||||||
unsigned long page_in_index = 0;
|
unsigned long page_in_index = 0;
|
||||||
unsigned long page_out_index = 0;
|
|
||||||
unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
|
unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE);
|
||||||
unsigned long buf_start;
|
unsigned long buf_start;
|
||||||
unsigned long pg_offset;
|
|
||||||
|
|
||||||
data_in = kmap(pages_in[page_in_index]);
|
data_in = kmap(pages_in[page_in_index]);
|
||||||
workspace->strm.next_in = data_in;
|
workspace->strm.next_in = data_in;
|
||||||
@ -235,7 +232,6 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
|
|||||||
workspace->strm.total_out = 0;
|
workspace->strm.total_out = 0;
|
||||||
workspace->strm.next_out = workspace->buf;
|
workspace->strm.next_out = workspace->buf;
|
||||||
workspace->strm.avail_out = PAGE_SIZE;
|
workspace->strm.avail_out = PAGE_SIZE;
|
||||||
pg_offset = 0;
|
|
||||||
|
|
||||||
/* If it's deflate, and it's got no preset dictionary, then
|
/* If it's deflate, and it's got no preset dictionary, then
|
||||||
we can tell zlib to skip the adler32 check. */
|
we can tell zlib to skip the adler32 check. */
|
||||||
@ -267,8 +263,7 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
|
|||||||
|
|
||||||
ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
|
ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
|
||||||
total_out, disk_start,
|
total_out, disk_start,
|
||||||
bvec, vcnt,
|
orig_bio);
|
||||||
&page_out_index, &pg_offset);
|
|
||||||
if (ret2 == 0) {
|
if (ret2 == 0) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto done;
|
goto done;
|
||||||
@ -301,7 +296,7 @@ done:
|
|||||||
if (data_in)
|
if (data_in)
|
||||||
kunmap(pages_in[page_in_index]);
|
kunmap(pages_in[page_in_index]);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
|
zero_fill_bio(orig_bio);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,6 +403,6 @@ const struct btrfs_compress_op btrfs_zlib_compress = {
|
|||||||
.alloc_workspace = zlib_alloc_workspace,
|
.alloc_workspace = zlib_alloc_workspace,
|
||||||
.free_workspace = zlib_free_workspace,
|
.free_workspace = zlib_free_workspace,
|
||||||
.compress_pages = zlib_compress_pages,
|
.compress_pages = zlib_compress_pages,
|
||||||
.decompress_biovec = zlib_decompress_biovec,
|
.decompress_bio = zlib_decompress_bio,
|
||||||
.decompress = zlib_decompress,
|
.decompress = zlib_decompress,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user