From: Andrew Morton <akpm@linux-foundation.org>
To: adrien+dev@schischi.me, akpm@linux-foundation.org,
drosen@google.com, groeck@chromium.org, hch@lst.de,
linux-mm@kvack.org, mm-commits@vger.kernel.org,
phillip@squashfs.org.uk, pliard@google.com,
torvalds@linux-foundation.org
Subject: [patch 001/128] squashfs: migrate from ll_rw_block usage to BIO
Date: Mon, 01 Jun 2020 21:45:23 -0700 [thread overview]
Message-ID: <20200602044523.w54YgfxZ_%akpm@linux-foundation.org> (raw)
In-Reply-To: <20200601214457.919c35648e96a2b46b573fe1@linux-foundation.org>
From: Philippe Liard <pliard@google.com>
Subject: squashfs: migrate from ll_rw_block usage to BIO
ll_rw_block() function has been deprecated in favor of BIO which appears
to come with large performance improvements.
This patch decreases boot time by close to 40% when using squashfs for the
root file-system. This is observed at least in the context of starting an
Android VM on Chrome OS using crosvm
(https://chromium.googlesource.com/chromiumos/platform/crosvm). The patch
was tested on 4.19 as well as master.
This patch is largely based on Adrien Schildknecht's patch that was
originally sent as https://lkml.org/lkml/2017/9/22/814 though with some
significant changes and simplifications while also taking Phillip
Lougher's feedback into account, around preserving support for FILE_CACHE
in particular.
[akpm@linux-foundation.org: fix build error reported by Randy]
Link: http://lkml.kernel.org/r/319997c2-5fc8-f889-2ea3-d913308a7c1f@infradead.org
Link: http://lkml.kernel.org/r/20191106074238.186023-1-pliard@google.com
Signed-off-by: Philippe Liard <pliard@google.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: Adrien Schildknecht <adrien+dev@schischi.me>
Cc: Phillip Lougher <phillip@squashfs.org.uk>
Cc: Guenter Roeck <groeck@chromium.org>
Cc: Daniel Rosenberg <drosen@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
fs/squashfs/block.c | 273 +++++++++++-----------
fs/squashfs/decompressor.h | 5
fs/squashfs/decompressor_multi.c | 9
fs/squashfs/decompressor_multi_percpu.c | 17 -
fs/squashfs/decompressor_single.c | 9
fs/squashfs/lz4_wrapper.c | 17 -
fs/squashfs/lzo_wrapper.c | 17 -
fs/squashfs/squashfs.h | 4
fs/squashfs/xz_wrapper.c | 51 ++--
fs/squashfs/zlib_wrapper.c | 63 ++---
fs/squashfs/zstd_wrapper.c | 62 ++--
11 files changed, 286 insertions(+), 241 deletions(-)
--- a/fs/squashfs/block.c~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/block.c
@@ -13,6 +13,7 @@
* datablocks and metadata blocks.
*/
+#include <linux/blkdev.h>
#include <linux/fs.h>
#include <linux/vfs.h>
#include <linux/slab.h>
@@ -27,45 +28,104 @@
#include "page_actor.h"
/*
- * Read the metadata block length, this is stored in the first two
- * bytes of the metadata block.
+ * Returns the amount of bytes copied to the page actor.
*/
-static struct buffer_head *get_block_length(struct super_block *sb,
- u64 *cur_index, int *offset, int *length)
+static int copy_bio_to_actor(struct bio *bio,
+ struct squashfs_page_actor *actor,
+ int offset, int req_length)
+{
+ void *actor_addr = squashfs_first_page(actor);
+ struct bvec_iter_all iter_all = {};
+ struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
+ int copied_bytes = 0;
+ int actor_offset = 0;
+
+ if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all)))
+ return 0;
+
+ while (copied_bytes < req_length) {
+ int bytes_to_copy = min_t(int, bvec->bv_len - offset,
+ PAGE_SIZE - actor_offset);
+
+ bytes_to_copy = min_t(int, bytes_to_copy,
+ req_length - copied_bytes);
+ memcpy(actor_addr + actor_offset,
+ page_address(bvec->bv_page) + bvec->bv_offset + offset,
+ bytes_to_copy);
+
+ actor_offset += bytes_to_copy;
+ copied_bytes += bytes_to_copy;
+ offset += bytes_to_copy;
+
+ if (actor_offset >= PAGE_SIZE) {
+ actor_addr = squashfs_next_page(actor);
+ if (!actor_addr)
+ break;
+ actor_offset = 0;
+ }
+ if (offset >= bvec->bv_len) {
+ if (!bio_next_segment(bio, &iter_all))
+ break;
+ offset = 0;
+ }
+ }
+ squashfs_finish_page(actor);
+ return copied_bytes;
+}
+
+static int squashfs_bio_read(struct super_block *sb, u64 index, int length,
+ struct bio **biop, int *block_offset)
{
struct squashfs_sb_info *msblk = sb->s_fs_info;
- struct buffer_head *bh;
+ const u64 read_start = round_down(index, msblk->devblksize);
+ const sector_t block = read_start >> msblk->devblksize_log2;
+ const u64 read_end = round_up(index + length, msblk->devblksize);
+ const sector_t block_end = read_end >> msblk->devblksize_log2;
+ int offset = read_start - round_down(index, PAGE_SIZE);
+ int total_len = (block_end - block) << msblk->devblksize_log2;
+ const int page_count = DIV_ROUND_UP(total_len + offset, PAGE_SIZE);
+ int error, i;
+ struct bio *bio;
- bh = sb_bread(sb, *cur_index);
- if (bh == NULL)
- return NULL;
-
- if (msblk->devblksize - *offset == 1) {
- *length = (unsigned char) bh->b_data[*offset];
- put_bh(bh);
- bh = sb_bread(sb, ++(*cur_index));
- if (bh == NULL)
- return NULL;
- *length |= (unsigned char) bh->b_data[0] << 8;
- *offset = 1;
- } else {
- *length = (unsigned char) bh->b_data[*offset] |
- (unsigned char) bh->b_data[*offset + 1] << 8;
- *offset += 2;
-
- if (*offset == msblk->devblksize) {
- put_bh(bh);
- bh = sb_bread(sb, ++(*cur_index));
- if (bh == NULL)
- return NULL;
- *offset = 0;
+ bio = bio_alloc(GFP_NOIO, page_count);
+ if (!bio)
+ return -ENOMEM;
+
+ bio_set_dev(bio, sb->s_bdev);
+ bio->bi_opf = READ;
+ bio->bi_iter.bi_sector = block * (msblk->devblksize >> SECTOR_SHIFT);
+
+ for (i = 0; i < page_count; ++i) {
+ unsigned int len =
+ min_t(unsigned int, PAGE_SIZE - offset, total_len);
+ struct page *page = alloc_page(GFP_NOIO);
+
+ if (!page) {
+ error = -ENOMEM;
+ goto out_free_bio;
}
+ if (!bio_add_page(bio, page, len, offset)) {
+ error = -EIO;
+ goto out_free_bio;
+ }
+ offset = 0;
+ total_len -= len;
}
- return bh;
+ error = submit_bio_wait(bio);
+ if (error)
+ goto out_free_bio;
+
+ *biop = bio;
+ *block_offset = index & ((1 << msblk->devblksize_log2) - 1);
+ return 0;
+
+out_free_bio:
+ bio_free_pages(bio);
+ bio_put(bio);
+ return error;
}
-
/*
* Read and decompress a metadata block or datablock. Length is non-zero
* if a datablock is being read (the size is stored elsewhere in the
@@ -76,129 +136,88 @@ static struct buffer_head *get_block_len
* algorithms).
*/
int squashfs_read_data(struct super_block *sb, u64 index, int length,
- u64 *next_index, struct squashfs_page_actor *output)
+ u64 *next_index, struct squashfs_page_actor *output)
{
struct squashfs_sb_info *msblk = sb->s_fs_info;
- struct buffer_head **bh;
- int offset = index & ((1 << msblk->devblksize_log2) - 1);
- u64 cur_index = index >> msblk->devblksize_log2;
- int bytes, compressed, b = 0, k = 0, avail, i;
-
- bh = kcalloc(((output->length + msblk->devblksize - 1)
- >> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL);
- if (bh == NULL)
- return -ENOMEM;
+ struct bio *bio = NULL;
+ int compressed;
+ int res;
+ int offset;
if (length) {
/*
* Datablock.
*/
- bytes = -offset;
compressed = SQUASHFS_COMPRESSED_BLOCK(length);
length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
- if (next_index)
- *next_index = index + length;
-
TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
index, compressed ? "" : "un", length, output->length);
-
- if (length < 0 || length > output->length ||
- (index + length) > msblk->bytes_used)
- goto read_failure;
-
- for (b = 0; bytes < length; b++, cur_index++) {
- bh[b] = sb_getblk(sb, cur_index);
- if (bh[b] == NULL)
- goto block_release;
- bytes += msblk->devblksize;
- }
- ll_rw_block(REQ_OP_READ, 0, b, bh);
} else {
/*
* Metadata block.
*/
- if ((index + 2) > msblk->bytes_used)
- goto read_failure;
-
- bh[0] = get_block_length(sb, &cur_index, &offset, &length);
- if (bh[0] == NULL)
- goto read_failure;
- b = 1;
+ const u8 *data;
+ struct bvec_iter_all iter_all = {};
+ struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
+
+ if (index + 2 > msblk->bytes_used) {
+ res = -EIO;
+ goto out;
+ }
+ res = squashfs_bio_read(sb, index, 2, &bio, &offset);
+ if (res)
+ goto out;
+
+ if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) {
+ res = -EIO;
+ goto out_free_bio;
+ }
+ /* Extract the length of the metadata block */
+ data = page_address(bvec->bv_page) + bvec->bv_offset;
+ length = data[offset];
+ if (offset <= bvec->bv_len - 1) {
+ length |= data[offset + 1] << 8;
+ } else {
+ if (WARN_ON_ONCE(!bio_next_segment(bio, &iter_all))) {
+ res = -EIO;
+ goto out_free_bio;
+ }
+ data = page_address(bvec->bv_page) + bvec->bv_offset;
+ length |= data[0] << 8;
+ }
+ bio_free_pages(bio);
+ bio_put(bio);
- bytes = msblk->devblksize - offset;
compressed = SQUASHFS_COMPRESSED(length);
length = SQUASHFS_COMPRESSED_SIZE(length);
- if (next_index)
- *next_index = index + length + 2;
+ index += 2;
TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
- compressed ? "" : "un", length);
-
- if (length < 0 || length > output->length ||
- (index + length) > msblk->bytes_used)
- goto block_release;
-
- for (; bytes < length; b++) {
- bh[b] = sb_getblk(sb, ++cur_index);
- if (bh[b] == NULL)
- goto block_release;
- bytes += msblk->devblksize;
- }
- ll_rw_block(REQ_OP_READ, 0, b - 1, bh + 1);
+ compressed ? "" : "un", length);
}
+ if (next_index)
+ *next_index = index + length;
- for (i = 0; i < b; i++) {
- wait_on_buffer(bh[i]);
- if (!buffer_uptodate(bh[i]))
- goto block_release;
- }
+ res = squashfs_bio_read(sb, index, length, &bio, &offset);
+ if (res)
+ goto out;
if (compressed) {
- if (!msblk->stream)
- goto read_failure;
- length = squashfs_decompress(msblk, bh, b, offset, length,
- output);
- if (length < 0)
- goto read_failure;
- } else {
- /*
- * Block is uncompressed.
- */
- int in, pg_offset = 0;
- void *data = squashfs_first_page(output);
-
- for (bytes = length; k < b; k++) {
- in = min(bytes, msblk->devblksize - offset);
- bytes -= in;
- while (in) {
- if (pg_offset == PAGE_SIZE) {
- data = squashfs_next_page(output);
- pg_offset = 0;
- }
- avail = min_t(int, in, PAGE_SIZE -
- pg_offset);
- memcpy(data + pg_offset, bh[k]->b_data + offset,
- avail);
- in -= avail;
- pg_offset += avail;
- offset += avail;
- }
- offset = 0;
- put_bh(bh[k]);
+ if (!msblk->stream) {
+ res = -EIO;
+ goto out_free_bio;
}
- squashfs_finish_page(output);
+ res = squashfs_decompress(msblk, bio, offset, length, output);
+ } else {
+ res = copy_bio_to_actor(bio, output, offset, length);
}
- kfree(bh);
- return length;
+out_free_bio:
+ bio_free_pages(bio);
+ bio_put(bio);
+out:
+ if (res < 0)
+ ERROR("Failed to read block 0x%llx: %d\n", index, res);
-block_release:
- for (; k < b; k++)
- put_bh(bh[k]);
-
-read_failure:
- ERROR("squashfs_read_data failed to read block 0x%llx\n",
- (unsigned long long) index);
- kfree(bh);
- return -EIO;
+ return res;
}
--- a/fs/squashfs/decompressor.h~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/decompressor.h
@@ -10,13 +10,14 @@
* decompressor.h
*/
+#include <linux/bio.h>
+
struct squashfs_decompressor {
void *(*init)(struct squashfs_sb_info *, void *);
void *(*comp_opts)(struct squashfs_sb_info *, void *, int);
void (*free)(void *);
int (*decompress)(struct squashfs_sb_info *, void *,
- struct buffer_head **, int, int, int,
- struct squashfs_page_actor *);
+ struct bio *, int, int, struct squashfs_page_actor *);
int id;
char *name;
int supported;
--- a/fs/squashfs/decompressor_multi.c~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/decompressor_multi.c
@@ -6,7 +6,7 @@
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/buffer_head.h>
+#include <linux/bio.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/cpumask.h>
@@ -180,14 +180,15 @@ wait:
}
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
- int b, int offset, int length, struct squashfs_page_actor *output)
+int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
+ int offset, int length,
+ struct squashfs_page_actor *output)
{
int res;
struct squashfs_stream *stream = msblk->stream;
struct decomp_stream *decomp_stream = get_decomp_stream(msblk, stream);
res = msblk->decompressor->decompress(msblk, decomp_stream->stream,
- bh, b, offset, length, output);
+ bio, offset, length, output);
put_decomp_stream(decomp_stream, stream);
if (res < 0)
ERROR("%s decompression failed, data probably corrupt\n",
--- a/fs/squashfs/decompressor_multi_percpu.c~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/decompressor_multi_percpu.c
@@ -72,14 +72,17 @@ void squashfs_decompressor_destroy(struc
}
}
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
- int b, int offset, int length, struct squashfs_page_actor *output)
+int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
+ int offset, int length, struct squashfs_page_actor *output)
{
- struct squashfs_stream __percpu *percpu =
- (struct squashfs_stream __percpu *) msblk->stream;
- struct squashfs_stream *stream = get_cpu_ptr(percpu);
- int res = msblk->decompressor->decompress(msblk, stream->stream, bh, b,
- offset, length, output);
+ struct squashfs_stream __percpu *percpu;
+ struct squashfs_stream *stream;
+ int res;
+
+ percpu = (struct squashfs_stream __percpu *)msblk->stream;
+ stream = get_cpu_ptr(percpu);
+ res = msblk->decompressor->decompress(msblk, stream->stream, bio,
+ offset, length, output);
put_cpu_ptr(stream);
if (res < 0)
--- a/fs/squashfs/decompressor_single.c~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/decompressor_single.c
@@ -7,7 +7,7 @@
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/buffer_head.h>
+#include <linux/bio.h>
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
@@ -59,14 +59,15 @@ void squashfs_decompressor_destroy(struc
}
}
-int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh,
- int b, int offset, int length, struct squashfs_page_actor *output)
+int squashfs_decompress(struct squashfs_sb_info *msblk, struct bio *bio,
+ int offset, int length,
+ struct squashfs_page_actor *output)
{
int res;
struct squashfs_stream *stream = msblk->stream;
mutex_lock(&stream->mutex);
- res = msblk->decompressor->decompress(msblk, stream->stream, bh, b,
+ res = msblk->decompressor->decompress(msblk, stream->stream, bio,
offset, length, output);
mutex_unlock(&stream->mutex);
--- a/fs/squashfs/lz4_wrapper.c~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/lz4_wrapper.c
@@ -4,7 +4,7 @@
* Phillip Lougher <phillip@squashfs.org.uk>
*/
-#include <linux/buffer_head.h>
+#include <linux/bio.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -89,20 +89,23 @@ static void lz4_free(void *strm)
static int lz4_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct buffer_head **bh, int b, int offset, int length,
+ struct bio *bio, int offset, int length,
struct squashfs_page_actor *output)
{
+ struct bvec_iter_all iter_all = {};
+ struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
struct squashfs_lz4 *stream = strm;
void *buff = stream->input, *data;
- int avail, i, bytes = length, res;
+ int bytes = length, res;
- for (i = 0; i < b; i++) {
- avail = min(bytes, msblk->devblksize - offset);
- memcpy(buff, bh[i]->b_data + offset, avail);
+ while (bio_next_segment(bio, &iter_all)) {
+ int avail = min(bytes, ((int)bvec->bv_len) - offset);
+
+ data = page_address(bvec->bv_page) + bvec->bv_offset;
+ memcpy(buff, data + offset, avail);
buff += avail;
bytes -= avail;
offset = 0;
- put_bh(bh[i]);
}
res = LZ4_decompress_safe(stream->input, stream->output,
--- a/fs/squashfs/lzo_wrapper.c~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/lzo_wrapper.c
@@ -9,7 +9,7 @@
*/
#include <linux/mutex.h>
-#include <linux/buffer_head.h>
+#include <linux/bio.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/lzo.h>
@@ -63,21 +63,24 @@ static void lzo_free(void *strm)
static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct buffer_head **bh, int b, int offset, int length,
+ struct bio *bio, int offset, int length,
struct squashfs_page_actor *output)
{
+ struct bvec_iter_all iter_all = {};
+ struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
struct squashfs_lzo *stream = strm;
void *buff = stream->input, *data;
- int avail, i, bytes = length, res;
+ int bytes = length, res;
size_t out_len = output->length;
- for (i = 0; i < b; i++) {
- avail = min(bytes, msblk->devblksize - offset);
- memcpy(buff, bh[i]->b_data + offset, avail);
+ while (bio_next_segment(bio, &iter_all)) {
+ int avail = min(bytes, ((int)bvec->bv_len) - offset);
+
+ data = page_address(bvec->bv_page) + bvec->bv_offset;
+ memcpy(buff, data + offset, avail);
buff += avail;
bytes -= avail;
offset = 0;
- put_bh(bh[i]);
}
res = lzo1x_decompress_safe(stream->input, (size_t)length,
--- a/fs/squashfs/squashfs.h~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/squashfs.h
@@ -40,8 +40,8 @@ extern void *squashfs_decompressor_setup
/* decompressor_xxx.c */
extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *);
extern void squashfs_decompressor_destroy(struct squashfs_sb_info *);
-extern int squashfs_decompress(struct squashfs_sb_info *, struct buffer_head **,
- int, int, int, struct squashfs_page_actor *);
+extern int squashfs_decompress(struct squashfs_sb_info *, struct bio *,
+ int, int, struct squashfs_page_actor *);
extern int squashfs_max_decompressors(void);
/* export.c */
--- a/fs/squashfs/xz_wrapper.c~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/xz_wrapper.c
@@ -10,7 +10,7 @@
#include <linux/mutex.h>
-#include <linux/buffer_head.h>
+#include <linux/bio.h>
#include <linux/slab.h>
#include <linux/xz.h>
#include <linux/bitops.h>
@@ -117,11 +117,12 @@ static void squashfs_xz_free(void *strm)
static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct buffer_head **bh, int b, int offset, int length,
+ struct bio *bio, int offset, int length,
struct squashfs_page_actor *output)
{
- enum xz_ret xz_err;
- int avail, total = 0, k = 0;
+ struct bvec_iter_all iter_all = {};
+ struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
+ int total = 0, error = 0;
struct squashfs_xz *stream = strm;
xz_dec_reset(stream->state);
@@ -131,11 +132,23 @@ static int squashfs_xz_uncompress(struct
stream->buf.out_size = PAGE_SIZE;
stream->buf.out = squashfs_first_page(output);
- do {
- if (stream->buf.in_pos == stream->buf.in_size && k < b) {
- avail = min(length, msblk->devblksize - offset);
+ for (;;) {
+ enum xz_ret xz_err;
+
+ if (stream->buf.in_pos == stream->buf.in_size) {
+ const void *data;
+ int avail;
+
+ if (!bio_next_segment(bio, &iter_all)) {
+ /* XZ_STREAM_END must be reached. */
+ error = -EIO;
+ break;
+ }
+
+ avail = min(length, ((int)bvec->bv_len) - offset);
+ data = page_address(bvec->bv_page) + bvec->bv_offset;
length -= avail;
- stream->buf.in = bh[k]->b_data + offset;
+ stream->buf.in = data + offset;
stream->buf.in_size = avail;
stream->buf.in_pos = 0;
offset = 0;
@@ -150,23 +163,17 @@ static int squashfs_xz_uncompress(struct
}
xz_err = xz_dec_run(stream->state, &stream->buf);
-
- if (stream->buf.in_pos == stream->buf.in_size && k < b)
- put_bh(bh[k++]);
- } while (xz_err == XZ_OK);
+ if (xz_err == XZ_STREAM_END)
+ break;
+ if (xz_err != XZ_OK) {
+ error = -EIO;
+ break;
+ }
+ }
squashfs_finish_page(output);
- if (xz_err != XZ_STREAM_END || k < b)
- goto out;
-
- return total + stream->buf.out_pos;
-
-out:
- for (; k < b; k++)
- put_bh(bh[k]);
-
- return -EIO;
+ return error ? error : total + stream->buf.out_pos;
}
const struct squashfs_decompressor squashfs_xz_comp_ops = {
--- a/fs/squashfs/zlib_wrapper.c~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/zlib_wrapper.c
@@ -10,7 +10,7 @@
#include <linux/mutex.h>
-#include <linux/buffer_head.h>
+#include <linux/bio.h>
#include <linux/slab.h>
#include <linux/zlib.h>
#include <linux/vmalloc.h>
@@ -50,21 +50,35 @@ static void zlib_free(void *strm)
static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct buffer_head **bh, int b, int offset, int length,
+ struct bio *bio, int offset, int length,
struct squashfs_page_actor *output)
{
- int zlib_err, zlib_init = 0, k = 0;
+ struct bvec_iter_all iter_all = {};
+ struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
+ int zlib_init = 0, error = 0;
z_stream *stream = strm;
stream->avail_out = PAGE_SIZE;
stream->next_out = squashfs_first_page(output);
stream->avail_in = 0;
- do {
- if (stream->avail_in == 0 && k < b) {
- int avail = min(length, msblk->devblksize - offset);
+ for (;;) {
+ int zlib_err;
+
+ if (stream->avail_in == 0) {
+ const void *data;
+ int avail;
+
+ if (!bio_next_segment(bio, &iter_all)) {
+ /* Z_STREAM_END must be reached. */
+ error = -EIO;
+ break;
+ }
+
+ avail = min(length, ((int)bvec->bv_len) - offset);
+ data = page_address(bvec->bv_page) + bvec->bv_offset;
length -= avail;
- stream->next_in = bh[k]->b_data + offset;
+ stream->next_in = data + offset;
stream->avail_in = avail;
offset = 0;
}
@@ -78,37 +92,28 @@ static int zlib_uncompress(struct squash
if (!zlib_init) {
zlib_err = zlib_inflateInit(stream);
if (zlib_err != Z_OK) {
- squashfs_finish_page(output);
- goto out;
+ error = -EIO;
+ break;
}
zlib_init = 1;
}
zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
-
- if (stream->avail_in == 0 && k < b)
- put_bh(bh[k++]);
- } while (zlib_err == Z_OK);
+ if (zlib_err == Z_STREAM_END)
+ break;
+ if (zlib_err != Z_OK) {
+ error = -EIO;
+ break;
+ }
+ }
squashfs_finish_page(output);
- if (zlib_err != Z_STREAM_END)
- goto out;
-
- zlib_err = zlib_inflateEnd(stream);
- if (zlib_err != Z_OK)
- goto out;
-
- if (k < b)
- goto out;
-
- return stream->total_out;
-
-out:
- for (; k < b; k++)
- put_bh(bh[k]);
+ if (!error)
+ if (zlib_inflateEnd(stream) != Z_OK)
+ error = -EIO;
- return -EIO;
+ return error ? error : stream->total_out;
}
const struct squashfs_decompressor squashfs_zlib_comp_ops = {
--- a/fs/squashfs/zstd_wrapper.c~squashfs-migrate-from-ll_rw_block-usage-to-bio
+++ a/fs/squashfs/zstd_wrapper.c
@@ -9,7 +9,7 @@
*/
#include <linux/mutex.h>
-#include <linux/buffer_head.h>
+#include <linux/bio.h>
#include <linux/slab.h>
#include <linux/zstd.h>
#include <linux/vmalloc.h>
@@ -59,33 +59,44 @@ static void zstd_free(void *strm)
static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
- struct buffer_head **bh, int b, int offset, int length,
+ struct bio *bio, int offset, int length,
struct squashfs_page_actor *output)
{
struct workspace *wksp = strm;
ZSTD_DStream *stream;
size_t total_out = 0;
- size_t zstd_err;
- int k = 0;
+ int error = 0;
ZSTD_inBuffer in_buf = { NULL, 0, 0 };
ZSTD_outBuffer out_buf = { NULL, 0, 0 };
+ struct bvec_iter_all iter_all = {};
+ struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
stream = ZSTD_initDStream(wksp->window_size, wksp->mem, wksp->mem_size);
if (!stream) {
ERROR("Failed to initialize zstd decompressor\n");
- goto out;
+ return -EIO;
}
out_buf.size = PAGE_SIZE;
out_buf.dst = squashfs_first_page(output);
- do {
- if (in_buf.pos == in_buf.size && k < b) {
- int avail = min(length, msblk->devblksize - offset);
+ for (;;) {
+ size_t zstd_err;
+ if (in_buf.pos == in_buf.size) {
+ const void *data;
+ int avail;
+
+ if (!bio_next_segment(bio, &iter_all)) {
+ error = -EIO;
+ break;
+ }
+
+ avail = min(length, ((int)bvec->bv_len) - offset);
+ data = page_address(bvec->bv_page) + bvec->bv_offset;
length -= avail;
- in_buf.src = bh[k]->b_data + offset;
+ in_buf.src = data + offset;
in_buf.size = avail;
in_buf.pos = 0;
offset = 0;
@@ -97,8 +108,8 @@ static int zstd_uncompress(struct squash
/* Shouldn't run out of pages
* before stream is done.
*/
- squashfs_finish_page(output);
- goto out;
+ error = -EIO;
+ break;
}
out_buf.pos = 0;
out_buf.size = PAGE_SIZE;
@@ -107,29 +118,20 @@ static int zstd_uncompress(struct squash
total_out -= out_buf.pos;
zstd_err = ZSTD_decompressStream(stream, &out_buf, &in_buf);
total_out += out_buf.pos; /* add the additional data produced */
+ if (zstd_err == 0)
+ break;
- if (in_buf.pos == in_buf.size && k < b)
- put_bh(bh[k++]);
- } while (zstd_err != 0 && !ZSTD_isError(zstd_err));
-
- squashfs_finish_page(output);
-
- if (ZSTD_isError(zstd_err)) {
- ERROR("zstd decompression error: %d\n",
- (int)ZSTD_getErrorCode(zstd_err));
- goto out;
+ if (ZSTD_isError(zstd_err)) {
+ ERROR("zstd decompression error: %d\n",
+ (int)ZSTD_getErrorCode(zstd_err));
+ error = -EIO;
+ break;
+ }
}
- if (k < b)
- goto out;
-
- return (int)total_out;
next prev parent reply other threads:[~2020-06-02 4:45 UTC|newest]
Thread overview: 134+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-02 4:44 incoming Andrew Morton
2020-06-02 4:45 ` Andrew Morton [this message]
2020-06-02 4:45 ` [patch 002/128] ocfs2: add missing annotation for dlm_empty_lockres() Andrew Morton
2020-06-02 4:45 ` [patch 003/128] ocfs2: mount shared volume without ha stack Andrew Morton
2020-06-02 4:45 ` [patch 004/128] arch/parisc/include/asm/pgtable.h: remove unused `old_pte' Andrew Morton
2020-06-02 4:45 ` [patch 005/128] vfs: track per-sb writeback errors and report them to syncfs Andrew Morton
2020-06-02 4:45 ` [patch 006/128] fs/buffer.c: record blockdev write errors in super_block that it backs Andrew Morton
2020-06-02 4:45 ` [patch 007/128] usercopy: mark dma-kmalloc caches as usercopy caches Andrew Morton
2020-06-02 4:45 ` [patch 008/128] mm/slub.c: fix corrupted freechain in deactivate_slab() Andrew Morton
2020-06-02 4:45 ` [patch 009/128] slub: Remove userspace notifier for cache add/remove Andrew Morton
2020-06-02 4:45 ` [patch 010/128] slub: remove kmalloc under list_lock from list_slab_objects() V2 Andrew Morton
2020-06-02 4:45 ` [patch 011/128] mm/slub: fix stack overruns with SLUB_STATS Andrew Morton
2020-06-02 4:46 ` [patch 012/128] Documentation/vm/slub.rst: s/Toggle/Enable/ Andrew Morton
2020-06-02 4:46 ` [patch 013/128] mm, dump_page(): do not crash with invalid mapping pointer Andrew Morton
2020-06-02 4:46 ` [patch 014/128] mm: move readahead prototypes from mm.h Andrew Morton
2020-06-02 4:46 ` [patch 015/128] mm: return void from various readahead functions Andrew Morton
2020-06-02 4:46 ` [patch 016/128] mm: ignore return value of ->readpages Andrew Morton
2020-06-02 4:46 ` [patch 017/128] mm: move readahead nr_pages check into read_pages Andrew Morton
2020-06-02 4:46 ` [patch 018/128] mm: add new readahead_control API Andrew Morton
2020-06-02 4:46 ` [patch 019/128] mm: use readahead_control to pass arguments Andrew Morton
2020-06-02 4:46 ` [patch 020/128] mm: rename various 'offset' parameters to 'index' Andrew Morton
2020-06-02 4:46 ` [patch 021/128] mm: rename readahead loop variable to 'i' Andrew Morton
2020-06-02 4:46 ` [patch 022/128] mm: remove 'page_offset' from readahead loop Andrew Morton
2020-06-02 4:46 ` [patch 023/128] mm: put readahead pages in cache earlier Andrew Morton
2020-06-02 4:46 ` [patch 024/128] mm: add readahead address space operation Andrew Morton
2020-06-02 4:46 ` [patch 025/128] mm: move end_index check out of readahead loop Andrew Morton
2020-06-02 4:46 ` [patch 026/128] mm: add page_cache_readahead_unbounded Andrew Morton
2020-06-02 4:46 ` [patch 027/128] mm: document why we don't set PageReadahead Andrew Morton
2020-06-02 4:46 ` [patch 028/128] mm: use memalloc_nofs_save in readahead path Andrew Morton
2020-06-02 4:47 ` [patch 029/128] fs: convert mpage_readpages to mpage_readahead Andrew Morton
2020-06-02 4:47 ` [patch 030/128] btrfs: convert from readpages to readahead Andrew Morton
2020-06-02 4:47 ` [patch 031/128] erofs: convert uncompressed files " Andrew Morton
2020-06-02 4:47 ` [patch 032/128] erofs: convert compressed " Andrew Morton
2020-06-02 4:47 ` [patch 033/128] ext4: convert " Andrew Morton
2020-06-02 4:47 ` [patch 034/128] ext4: pass the inode to ext4_mpage_readpages Andrew Morton
2020-06-02 4:47 ` [patch 035/128] f2fs: convert from readpages to readahead Andrew Morton
2020-06-02 4:47 ` [patch 036/128] f2fs: pass the inode to f2fs_mpage_readpages Andrew Morton
2020-06-02 4:47 ` [patch 037/128] fuse: convert from readpages to readahead Andrew Morton
2020-06-02 4:47 ` [patch 038/128] iomap: " Andrew Morton
2020-06-02 4:47 ` [patch 039/128] include/linux/pagemap.h: introduce attach/detach_page_private Andrew Morton
2020-06-02 4:47 ` [patch 040/128] md: remove __clear_page_buffers and use attach/detach_page_private Andrew Morton
2020-06-02 4:47 ` [patch 041/128] btrfs: " Andrew Morton
2020-06-02 4:47 ` [patch 042/128] fs/buffer.c: " Andrew Morton
2020-06-02 4:47 ` [patch 043/128] f2fs: " Andrew Morton
2020-06-02 4:47 ` [patch 044/128] iomap: " Andrew Morton
2020-06-02 4:47 ` [patch 045/128] ntfs: replace attach_page_buffers with attach_page_private Andrew Morton
2020-06-02 4:48 ` [patch 046/128] orangefs: use attach/detach_page_private Andrew Morton
2020-06-02 4:48 ` [patch 047/128] buffer_head.h: remove attach_page_buffers Andrew Morton
2020-06-02 4:48 ` [patch 048/128] mm/migrate.c: call detach_page_private to cleanup code Andrew Morton
2020-06-02 4:48 ` [patch 049/128] mm_types.h: change set_page_private to inline function Andrew Morton
2020-06-02 4:48 ` [patch 050/128] mm/filemap.c: remove misleading comment Andrew Morton
2020-06-02 4:48 ` [patch 051/128] mm/page-writeback.c: remove unused variable Andrew Morton
2020-06-02 4:48 ` [patch 052/128] mm/writeback: replace PF_LESS_THROTTLE with PF_LOCAL_THROTTLE Andrew Morton
2020-06-02 4:48 ` [patch 053/128] mm/writeback: discard NR_UNSTABLE_NFS, use NR_WRITEBACK instead Andrew Morton
2020-06-02 4:48 ` [patch 054/128] mm/gup.c: update the documentation Andrew Morton
2020-06-02 4:48 ` [patch 055/128] mm/gup: introduce pin_user_pages_unlocked Andrew Morton
2020-06-02 4:48 ` [patch 056/128] ivtv: convert get_user_pages() --> pin_user_pages() Andrew Morton
2020-06-02 4:48 ` [patch 057/128] mm/gup.c: further document vma_permits_fault() Andrew Morton
2020-06-02 4:48 ` [patch 058/128] mm/swapfile: use list_{prev,next}_entry() instead of open-coding Andrew Morton
2020-06-02 4:48 ` [patch 059/128] mm/swap_state: fix a data race in swapin_nr_pages Andrew Morton
2020-06-02 4:48 ` [patch 060/128] mm: swap: properly update readahead statistics in unuse_pte_range() Andrew Morton
2020-06-02 4:48 ` [patch 061/128] mm/swapfile.c: offset is only used when there is more slots Andrew Morton
2020-06-02 4:48 ` [patch 062/128] mm/swapfile.c: explicitly show ssd/non-ssd is handled mutually exclusive Andrew Morton
2020-06-02 4:48 ` [patch 063/128] mm/swapfile.c: remove the unnecessary goto for SSD case Andrew Morton
2020-06-02 4:48 ` [patch 064/128] mm/swapfile.c: simplify the calculation of n_goal Andrew Morton
2020-06-02 4:48 ` [patch 065/128] mm/swapfile.c: remove the extra check in scan_swap_map_slots() Andrew Morton
2020-06-02 4:49 ` [patch 066/128] mm/swapfile.c: found_free could be represented by (tmp < max) Andrew Morton
2020-06-02 4:49 ` [patch 067/128] mm/swapfile.c: tmp is always smaller than max Andrew Morton
2020-06-02 4:49 ` [patch 068/128] mm/swapfile.c: omit a duplicate code by compare tmp and max first Andrew Morton
2020-06-02 4:49 ` [patch 069/128] swap: try to scan more free slots even when fragmented Andrew Morton
2020-06-02 4:49 ` [patch 070/128] mm/swapfile.c: classify SWAP_MAP_XXX to make it more readable Andrew Morton
2020-06-02 4:49 ` [patch 071/128] mm/swapfile.c: __swap_entry_free() always free 1 entry Andrew Morton
2020-06-02 4:49 ` [patch 072/128] mm/swapfile.c: use prandom_u32_max() Andrew Morton
2020-06-02 4:49 ` [patch 073/128] swap: reduce lock contention on swap cache from swap slots allocation Andrew Morton
2020-06-02 4:49 ` [patch 074/128] mm: swapfile: fix /proc/swaps heading and Size/Used/Priority alignment Andrew Morton
2020-06-02 4:49 ` [patch 075/128] include/linux/swap.h: delete meaningless __add_to_swap_cache() declaration Andrew Morton
2020-06-02 4:49 ` [patch 076/128] mm, memcg: add workingset_restore in memory.stat Andrew Morton
2020-06-02 4:49 ` [patch 077/128] mm: memcontrol: simplify value comparison between count and limit Andrew Morton
2020-06-02 4:49 ` [patch 078/128] memcg: expose root cgroup's memory.stat Andrew Morton
2020-06-02 4:49 ` [patch 079/128] mm/memcg: prepare for swap over-high accounting and penalty calculation Andrew Morton
2020-06-02 4:49 ` [patch 080/128] mm/memcg: move penalty delay clamping out of calculate_high_delay() Andrew Morton
2020-06-02 4:49 ` [patch 081/128] mm/memcg: move cgroup high memory limit setting into struct page_counter Andrew Morton
2020-06-02 4:49 ` [patch 082/128] mm/memcg: automatically penalize tasks with high swap use Andrew Morton
2020-06-02 4:49 ` [patch 083/128] memcg: fix memcg_kmem_bypass() for remote memcg charging Andrew Morton
2020-06-02 4:49 ` [patch 084/128] x86: mm: ptdump: calculate effective permissions correctly Andrew Morton
2020-06-02 4:50 ` [patch 085/128] mm: ptdump: expand type of 'val' in note_page() Andrew Morton
2020-06-02 4:50 ` [patch 086/128] /proc/PID/smaps: Add PMD migration entry parsing Andrew Morton
2020-06-02 4:50 ` [patch 087/128] mm/memory: remove unnecessary pte_devmap case in copy_one_pte() Andrew Morton
2020-06-02 4:50 ` [patch 088/128] mm, memory_failure: don't send BUS_MCEERR_AO for action required error Andrew Morton
2020-06-02 4:50 ` [patch 089/128] x86/hyperv: use vmalloc_exec for the hypercall page Andrew Morton
2020-06-02 4:50 ` [patch 090/128] x86: fix vmap arguments in map_irq_stack Andrew Morton
2020-06-02 4:50 ` [patch 091/128] staging: android: ion: use vmap instead of vm_map_ram Andrew Morton
2020-06-02 4:50 ` [patch 092/128] staging: media: ipu3: use vmap instead of reimplementing it Andrew Morton
2020-06-02 4:50 ` [patch 093/128] dma-mapping: use vmap insted " Andrew Morton
2020-06-02 4:50 ` [patch 094/128] powerpc: add an ioremap_phb helper Andrew Morton
2020-06-02 4:50 ` [patch 095/128] powerpc: remove __ioremap_at and __iounmap_at Andrew Morton
2020-06-02 4:50 ` [patch 096/128] mm: remove __get_vm_area Andrew Morton
2020-06-02 4:50 ` [patch 097/128] mm: unexport unmap_kernel_range_noflush Andrew Morton
2020-06-02 4:50 ` [patch 098/128] mm: rename CONFIG_PGTABLE_MAPPING to CONFIG_ZSMALLOC_PGTABLE_MAPPING Andrew Morton
2020-06-02 4:50 ` [patch 099/128] mm: only allow page table mappings for built-in zsmalloc Andrew Morton
2020-06-02 4:51 ` [patch 100/128] mm: pass addr as unsigned long to vb_free Andrew Morton
2020-06-02 4:51 ` [patch 101/128] mm: remove vmap_page_range_noflush and vunmap_page_range Andrew Morton
2020-06-02 4:51 ` [patch 102/128] mm: rename vmap_page_range to map_kernel_range Andrew Morton
2020-06-02 4:51 ` [patch 103/128] mm: don't return the number of pages from map_kernel_range{,_noflush} Andrew Morton
2020-06-02 4:51 ` [patch 104/128] mm: remove map_vm_range Andrew Morton
2020-06-02 4:51 ` [patch 105/128] mm: remove unmap_vmap_area Andrew Morton
2020-06-02 4:51 ` [patch 106/128] mm: remove the prot argument from vm_map_ram Andrew Morton
2020-06-02 4:51 ` [patch 107/128] mm: enforce that vmap can't map pages executable Andrew Morton
2020-06-02 4:51 ` [patch 108/128] gpu/drm: remove the powerpc hack in drm_legacy_sg_alloc Andrew Morton
2020-06-02 4:51 ` [patch 109/128] mm: remove the pgprot argument to __vmalloc Andrew Morton
2020-06-02 4:51 ` [patch 110/128] mm: remove the prot argument to __vmalloc_node Andrew Morton
2020-06-02 4:51 ` [patch 111/128] mm: remove both instances of __vmalloc_node_flags Andrew Morton
2020-06-02 4:51 ` [patch 112/128] mm: remove __vmalloc_node_flags_caller Andrew Morton
2020-06-02 4:51 ` [patch 113/128] mm: switch the test_vmalloc module to use __vmalloc_node Andrew Morton
2020-06-02 4:52 ` [patch 114/128] mm: remove vmalloc_user_node_flags Andrew Morton
2020-06-02 4:52 ` [patch 115/128] arm64: use __vmalloc_node in arch_alloc_vmap_stack Andrew Morton
2020-06-02 4:52 ` [patch 116/128] powerpc: use __vmalloc_node in alloc_vm_stack Andrew Morton
2020-06-02 4:52 ` [patch 117/128] s390: use __vmalloc_node in stack_alloc Andrew Morton
2020-06-02 4:52 ` [patch 118/128] mm: add functions to track page directory modifications Andrew Morton
2020-06-02 4:52 ` [patch 119/128] mm/vmalloc: track which page-table levels were modified Andrew Morton
2020-06-02 4:52 ` [patch 120/128] mm/ioremap: " Andrew Morton
2020-06-02 4:52 ` [patch 121/128] x86/mm/64: implement arch_sync_kernel_mappings() Andrew Morton
2020-06-02 4:52 ` [patch 122/128] x86/mm/32: " Andrew Morton
2020-06-02 4:52 ` [patch 123/128] mm: remove vmalloc_sync_(un)mappings() Andrew Morton
2020-06-02 4:52 ` [patch 124/128] x86/mm: remove vmalloc faulting Andrew Morton
2020-06-02 4:52 ` [patch 125/128] kasan: fix clang compilation warning due to stack protector Andrew Morton
2020-06-02 4:52 ` [patch 126/128] ubsan: entirely disable alignment checks under UBSAN_TRAP Andrew Morton
2020-06-02 4:52 ` [patch 127/128] mm/mm_init.c: report kasan-tag information stored in page->flags Andrew Morton
2020-06-02 4:52 ` [patch 128/128] kasan: move kasan_report() into report.c Andrew Morton
2020-06-02 19:05 ` + mm-slub-fix-a-memory-leak-in-sysfs_slab_add.patch added to -mm tree Andrew Morton
2020-06-02 19:14 ` [obsolete] sh-drop-config_mtd_m25p80-in-sh7757lcr_defconfig.patch removed from " Andrew Morton
2020-06-02 20:08 ` incoming Andrew Morton
[not found] ` <CAHk-=wgRV=SaiMn3L5u5mG0WfvB2VfEQadtudzDV3KRz5HnFrQ@mail.gmail.com>
2020-06-02 21:38 ` incoming Andrew Morton
2020-06-02 20:09 incoming Andrew Morton
2020-06-02 20:09 ` [patch 001/128] squashfs: migrate from ll_rw_block usage to BIO Andrew Morton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200602044523.w54YgfxZ_%akpm@linux-foundation.org \
--to=akpm@linux-foundation.org \
--cc=adrien+dev@schischi.me \
--cc=drosen@google.com \
--cc=groeck@chromium.org \
--cc=hch@lst.de \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mm-commits@vger.kernel.org \
--cc=phillip@squashfs.org.uk \
--cc=pliard@google.com \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).