Commit 974b1adc authored by Christoph Hellwig's avatar Christoph Hellwig Committed by David Sterba

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: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 0c476a5d
...@@ -81,9 +81,9 @@ struct compressed_bio { ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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,28 +1052,26 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, ...@@ -1057,28 +1052,26 @@ 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); kaddr = kmap_atomic(bvec.bv_page);
memcpy(kaddr + bvec.bv_offset, buf + buf_offset, bytes);
kunmap_atomic(kaddr); kunmap_atomic(kaddr);
flush_dcache_page(page_out); flush_dcache_page(bvec.bv_page);
*pg_offset += bytes;
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
...@@ -1099,38 +1092,6 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, ...@@ -1099,38 +1092,6 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
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, ...@@ -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, ...@@ -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 { ...@@ -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 @@ static int lzo_compress_pages(struct list_head *ws, ...@@ -254,25 +254,21 @@ static int lzo_compress_pages(struct list_head *ws,
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, ...@@ -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 @@ static int lzo_decompress_biovec(struct list_head *ws, ...@@ -365,16 +360,14 @@ static int lzo_decompress_biovec(struct list_head *ws,
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 = { ...@@ -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 @@ static int zlib_compress_pages(struct list_head *ws, ...@@ -210,10 +210,9 @@ static int zlib_compress_pages(struct list_head *ws,
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, ...@@ -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, ...@@ -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, ...@@ -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 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in, ...@@ -301,7 +296,7 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
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 = { ...@@ -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,
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment