Skip to content

Commit

Permalink
btrfs: use bio iterators for the decompression handlers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Christoph Hellwig authored and David Sterba committed Nov 30, 2016
1 parent 0c476a5 commit 974b1ad
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 112 deletions.
123 changes: 42 additions & 81 deletions fs/btrfs/compression.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ struct compressed_bio {
u32 sums;
};

static int btrfs_decompress_biovec(int type, struct page **pages_in,
u64 disk_start, struct bio_vec *bvec,
int vcnt, size_t srclen);
static int btrfs_decompress_bio(int type, struct page **pages_in,
u64 disk_start, struct bio *orig_bio,
size_t srclen);

static inline int compressed_bio_size(struct btrfs_root *root,
unsigned long disk_size)
Expand Down Expand Up @@ -175,11 +175,10 @@ 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_biovec(cb->compress_type,
ret = btrfs_decompress_bio(cb->compress_type,
cb->compressed_pages,
cb->start,
cb->orig_bio->bi_io_vec,
cb->orig_bio->bi_vcnt,
cb->orig_bio,
cb->compressed_len);
csum_failed:
if (ret)
Expand Down Expand Up @@ -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
*
* bvec is a bio_vec of pages from the file that we want to decompress into
*
* vcnt is the count of pages in the biovec
* orig_bio contains the pages from the file that we want to decompress into
*
* srclen is the number of bytes in pages_in
*
Expand All @@ -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
* the compressed extent.
*/
static int btrfs_decompress_biovec(int type, struct page **pages_in,
u64 disk_start, struct bio_vec *bvec,
int vcnt, size_t srclen)
static int btrfs_decompress_bio(int type, struct page **pages_in,
u64 disk_start, struct bio *orig_bio,
size_t srclen)
{
struct list_head *workspace;
int ret;

workspace = find_workspace(type);

ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in,
disk_start,
bvec, vcnt, srclen);
ret = btrfs_compress_op[type-1]->decompress_bio(workspace, pages_in,
disk_start, orig_bio,
srclen);
free_workspace(type, workspace);
return ret;
}
Expand Down Expand Up @@ -1021,23 +1018,21 @@ void btrfs_exit_compress(void)
*/
int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
unsigned long total_out, u64 disk_start,
struct bio_vec *bvec, int vcnt,
unsigned long *pg_index,
unsigned long *pg_offset)
struct bio *bio)
{
unsigned long buf_offset;
unsigned long current_buf_start;
unsigned long start_byte;
unsigned long working_bytes = total_out - buf_start;
unsigned long bytes;
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
* 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 */
if (total_out <= start_byte)
Expand All @@ -1057,80 +1052,46 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,

/* copy bytes from the working buffer into the pages */
while (working_bytes > 0) {
bytes = min(PAGE_SIZE - *pg_offset,
PAGE_SIZE - buf_offset);
bytes = min_t(unsigned long, bvec.bv_len,
PAGE_SIZE - buf_offset);
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);
flush_dcache_page(page_out);
flush_dcache_page(bvec.bv_page);

*pg_offset += bytes;
buf_offset += bytes;
working_bytes -= bytes;
current_buf_start += bytes;

/* check if we need to pick another page */
if (*pg_offset == PAGE_SIZE) {
(*pg_index)++;
if (*pg_index >= vcnt)
return 0;
bio_advance(bio, bytes);
if (!bio->bi_iter.bi_size)
return 0;
bvec = bio_iter_iovec(bio, bio->bi_iter);

page_out = bvec[*pg_index].bv_page;
*pg_offset = 0;
start_byte = page_offset(page_out) - disk_start;
start_byte = page_offset(bvec.bv_page) - disk_start;

/*
* make sure our new page is covered by this
* working buffer
*/
if (total_out <= start_byte)
return 1;
/*
* make sure our new page is covered by this
* working buffer
*/
if (total_out <= start_byte)
return 1;

/*
* the next page in the biovec might not be adjacent
* to the last page, but it might still be found
* inside this working buffer. bump our offset pointer
*/
if (total_out > start_byte &&
current_buf_start < start_byte) {
buf_offset = start_byte - buf_start;
working_bytes = total_out - start_byte;
current_buf_start = buf_start + buf_offset;
}
/*
* the next page in the biovec might not be adjacent
* to the last page, but it might still be found
* inside this working buffer. bump our offset pointer
*/
if (total_out > start_byte &&
current_buf_start < start_byte) {
buf_offset = start_byte - buf_start;
working_bytes = total_out - start_byte;
current_buf_start = buf_start + buf_offset;
}
}

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;
}
}
12 changes: 3 additions & 9 deletions fs/btrfs/compression.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
int btrfs_decompress_buf2page(char *buf, unsigned long buf_start,
unsigned long total_out, u64 disk_start,
struct bio_vec *bvec, int vcnt,
unsigned long *pg_index,
unsigned long *pg_offset);
struct bio *bio);

int btrfs_submit_compressed_write(struct inode *inode, u64 start,
unsigned long len, u64 disk_start,
Expand All @@ -45,9 +43,6 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
unsigned long nr_pages);
int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
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 {
BTRFS_COMPRESS_NONE = 0,
Expand All @@ -72,11 +67,10 @@ struct btrfs_compress_op {
unsigned long *total_out,
unsigned long max_out);

int (*decompress_biovec)(struct list_head *workspace,
int (*decompress_bio)(struct list_head *workspace,
struct page **pages_in,
u64 disk_start,
struct bio_vec *bvec,
int vcnt,
struct bio *orig_bio,
size_t srclen);

int (*decompress)(struct list_head *workspace,
Expand Down
17 changes: 5 additions & 12 deletions fs/btrfs/lzo.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,25 +254,21 @@ static int lzo_compress_pages(struct list_head *ws,
return ret;
}

static int lzo_decompress_biovec(struct list_head *ws,
static int lzo_decompress_bio(struct list_head *ws,
struct page **pages_in,
u64 disk_start,
struct bio_vec *bvec,
int vcnt,
struct bio *orig_bio,
size_t srclen)
{
struct workspace *workspace = list_entry(ws, struct workspace, list);
int ret = 0, ret2;
char *data_in;
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 buf_start;
unsigned long buf_offset = 0;
unsigned long bytes;
unsigned long working_bytes;
unsigned long pg_offset;

size_t in_len;
size_t out_len;
unsigned long in_offset;
Expand All @@ -292,7 +288,6 @@ static int lzo_decompress_biovec(struct list_head *ws,
in_page_bytes_left = PAGE_SIZE - LZO_LEN;

tot_out = 0;
pg_offset = 0;

while (tot_in < tot_len) {
in_len = read_compress_length(data_in + in_offset);
Expand Down Expand Up @@ -365,16 +360,14 @@ static int lzo_decompress_biovec(struct list_head *ws,
tot_out += out_len;

ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start,
tot_out, disk_start,
bvec, vcnt,
&page_out_index, &pg_offset);
tot_out, disk_start, orig_bio);
if (ret2 == 0)
break;
}
done:
kunmap(pages_in[page_in_index]);
if (!ret)
btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
zero_fill_bio(orig_bio);
return ret;
}

Expand Down Expand Up @@ -438,6 +431,6 @@ const struct btrfs_compress_op btrfs_lzo_compress = {
.alloc_workspace = lzo_alloc_workspace,
.free_workspace = lzo_free_workspace,
.compress_pages = lzo_compress_pages,
.decompress_biovec = lzo_decompress_biovec,
.decompress_bio = lzo_decompress_bio,
.decompress = lzo_decompress,
};
15 changes: 5 additions & 10 deletions fs/btrfs/zlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,9 @@ static int zlib_compress_pages(struct list_head *ws,
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,
struct bio_vec *bvec,
int vcnt,
struct bio *orig_bio,
size_t srclen)
{
struct workspace *workspace = list_entry(ws, struct workspace, list);
Expand All @@ -222,10 +221,8 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
char *data_in;
size_t total_out = 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 buf_start;
unsigned long pg_offset;

data_in = kmap(pages_in[page_in_index]);
workspace->strm.next_in = data_in;
Expand All @@ -235,7 +232,6 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
workspace->strm.total_out = 0;
workspace->strm.next_out = workspace->buf;
workspace->strm.avail_out = PAGE_SIZE;
pg_offset = 0;

/* If it's deflate, and it's got no preset dictionary, then
we can tell zlib to skip the adler32 check. */
Expand Down Expand Up @@ -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,
total_out, disk_start,
bvec, vcnt,
&page_out_index, &pg_offset);
orig_bio);
if (ret2 == 0) {
ret = 0;
goto done;
Expand Down Expand Up @@ -301,7 +296,7 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
if (data_in)
kunmap(pages_in[page_in_index]);
if (!ret)
btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset);
zero_fill_bio(orig_bio);
return ret;
}

Expand Down Expand Up @@ -408,6 +403,6 @@ const struct btrfs_compress_op btrfs_zlib_compress = {
.alloc_workspace = zlib_alloc_workspace,
.free_workspace = zlib_free_workspace,
.compress_pages = zlib_compress_pages,
.decompress_biovec = zlib_decompress_biovec,
.decompress_bio = zlib_decompress_bio,
.decompress = zlib_decompress,
};

0 comments on commit 974b1ad

Please sign in to comment.