All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philippe Liard <pliard@google.com>
To: phillip@squashfs.org.uk, hch@lst.de
Cc: linux-kernel@vger.kernel.org, groeck@chromium.org, pliard@google.com
Subject: [PATCH v2] squashfs: Migrate from ll_rw_block usage to BIO
Date: Tue,  5 Nov 2019 16:53:39 +0900	[thread overview]
Message-ID: <20191105075339.15280-1-pliard@google.com> (raw)

The 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.

Signed-off-by: Philippe Liard <pliard@google.com>
---
Changes in v2:
- changed all decompressors to take a bio pointer
- removed usage of buffer_head in block.c

 arch/x86/configs/x86_64_arcvm_defconfig |   3 +
 fs/squashfs/block.c                     | 294 +++++++++++++-----------
 fs/squashfs/decompressor.h              |   5 +-
 fs/squashfs/decompressor_multi.c        |   9 +-
 fs/squashfs/decompressor_single.c       |   9 +-
 fs/squashfs/lz4_wrapper.c               |  17 +-
 fs/squashfs/lzo_wrapper.c               |  16 +-
 fs/squashfs/squashfs.h                  |   4 +-
 fs/squashfs/xz_wrapper.c                |  33 +--
 fs/squashfs/zlib_wrapper.c              |  34 ++-
 fs/squashfs/zstd_wrapper.c              |  33 ++-
 11 files changed, 251 insertions(+), 206 deletions(-)

diff --git a/arch/x86/configs/x86_64_arcvm_defconfig b/arch/x86/configs/x86_64_arcvm_defconfig
index 0a4872edba05..8103880713b6 100644
--- a/arch/x86/configs/x86_64_arcvm_defconfig
+++ b/arch/x86/configs/x86_64_arcvm_defconfig
@@ -542,6 +542,9 @@ CONFIG_SQUASHFS_FILE_DIRECT=y
 CONFIG_SQUASHFS_XATTR=y
 CONFIG_SQUASHFS_LZ4=y
 CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_ZSTD=y
+CONFIG_SQUASHFS_ZLIB=y
+CONFIG_SQUASHFS_XZ=y
 CONFIG_PSTORE=y
 CONFIG_PSTORE_CONSOLE=y
 CONFIG_PSTORE_RAM=y
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index f098b9f1c396..4b27e81da92e 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -26,6 +26,7 @@
  * datablocks and metadata blocks.
  */
 
+#include <linux/blkdev.h>
 #include <linux/fs.h>
 #include <linux/vfs.h>
 #include <linux/slab.h>
@@ -40,44 +41,132 @@
 #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)
 {
-	struct squashfs_sb_info *msblk = sb->s_fs_info;
-	struct buffer_head *bh;
-
-	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;
+	void *actor_addr = squashfs_first_page(actor);
+	struct bio_vec bvec = bio->bi_io_vec[0];
+	int copied_bytes = 0;
+	int actor_offset = 0;
+	int bvec_index = 0;
+
+	while (actor_addr && bvec_index < bio->bi_vcnt &&
+	       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_offset = 0;
+			actor_addr = squashfs_next_page(actor);
+		}
+		if (offset >= bvec.bv_len) {
+			offset = 0;
+			++bvec_index;
+			if (bvec_index < bio->bi_vcnt)
+				bvec = bio->bi_io_vec[bvec_index];
 		}
 	}
+	squashfs_finish_page(actor);
+	return copied_bytes;
+}
+
+struct bio_read_context {
+	struct bio *bio;
+	struct page **pages;
+	int page_count;
+};
 
-	return bh;
+static void free_bio_read_context(struct bio_read_context *bio_ctx)
+{
+	if (bio_ctx->bio)
+		bio_put(bio_ctx->bio);
+
+	if (bio_ctx->pages) {
+		int i;
+
+		for (i = 0; i < bio_ctx->page_count; ++i)
+			if (bio_ctx->pages[i])
+				__free_page(bio_ctx->pages[i]);
+		kfree(bio_ctx->pages);
+	}
 }
 
+static int squashfs_bio_read(struct super_block *sb, u64 index, int length,
+			     struct bio_read_context *bio_ctx,
+			     int *block_offset)
+{
+	struct squashfs_sb_info *msblk = sb->s_fs_info;
+	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;
+
+	const int blksz = msblk->devblksize;
+	const int block_count = block_end - block;
+	const int bio_max_pages = min_t(int, block_count, BIO_MAX_PAGES);
+	int offset = read_start - round_down(index, PAGE_SIZE);
+	int res = 0;
+	int i, page_index;
+
+	memset(bio_ctx, 0, sizeof(*bio_ctx));
+	*block_offset = index & ((1 << msblk->devblksize_log2) - 1);
+	bio_ctx->page_count =
+		DIV_ROUND_UP(block_count * blksz + offset, PAGE_SIZE);
+	bio_ctx->pages =
+		kcalloc(bio_ctx->page_count, sizeof(struct page *), GFP_NOIO);
+	if (!bio_ctx->pages)
+		return -ENOMEM;
+
+	for (i = 0; i < bio_ctx->page_count; ++i) {
+		bio_ctx->pages[i] = alloc_page(GFP_NOIO);
+		if (!bio_ctx->pages[i]) {
+			res = -ENOMEM;
+			goto out;
+		}
+	}
+
+	bio_ctx->bio = bio_alloc(GFP_NOIO, bio_max_pages);
+	if (!bio_ctx->bio) {
+		res = -ENOMEM;
+		goto out;
+	}
+	bio_set_dev(bio_ctx->bio, sb->s_bdev);
+	bio_ctx->bio->bi_opf = READ;
+	bio_ctx->bio->bi_iter.bi_sector =
+		block * (msblk->devblksize >> SECTOR_SHIFT);
+
+	for (i = 0, page_index = 0; i < block_count; ++i) {
+		if (!bio_add_page(bio_ctx->bio, bio_ctx->pages[page_index],
+				  blksz, offset)) {
+			res = -EIO;
+			goto out;
+		}
+		offset += blksz;
+		if (offset >= PAGE_SIZE) {
+			offset = 0;
+			++page_index;
+		}
+	}
+	res = submit_bio_wait(bio_ctx->bio);
+out:
+	if (res)
+		free_bio_read_context(bio_ctx);
+
+	return res;
+}
 
 /*
  * Read and decompress a metadata block or datablock.  Length is non-zero
@@ -89,129 +178,78 @@ static struct buffer_head *get_block_length(struct super_block *sb,
  * 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_read_context bio_ctx;
+	struct bio_vec bvec;
+	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;
+		const u8 *data;
 
-		bh[0] = get_block_length(sb, &cur_index, &offset, &length);
-		if (bh[0] == NULL)
-			goto read_failure;
-		b = 1;
+		if (index + 2 > msblk->bytes_used) {
+			res = -EIO;
+			goto out;
+		}
+		res = squashfs_bio_read(sb, index, 2, &bio_ctx, &offset);
+		if (res)
+			goto out;
+
+		/* Extract the length of the metadata block */
+		bvec = bio_ctx.bio->bi_io_vec[0];
+		data = page_address(bvec.bv_page) + bvec.bv_offset;
+		length = data[offset];
+		if (offset == bvec.bv_len - 1) {
+			bvec = bio_ctx.bio->bi_io_vec[1];
+			data = page_address(bvec.bv_page) + bvec.bv_offset;
+			length |= data[0] << 8;
+		} else {
+			length |= data[offset + 1] << 8;
+		}
+		free_bio_read_context(&bio_ctx);
 
-		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_ctx, &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 = squashfs_decompress(msblk, bio_ctx.bio, offset,
+						  length, output);
+		} else {
+			res = -EIO;
 		}
-		squashfs_finish_page(output);
+	} else {
+		res = copy_bio_to_actor(bio_ctx.bio, output, offset, length);
 	}
+	free_bio_read_context(&bio_ctx);
+out:
+	if (res < 0)
+		ERROR("Failed to read block 0x%llx: %d\n", index, res);
 
-	kfree(bh);
-	return length;
-
-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;
 }
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h
index 0f5a8e4e58da..420fedd82f14 100644
--- a/fs/squashfs/decompressor.h
+++ b/fs/squashfs/decompressor.h
@@ -23,13 +23,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;
diff --git a/fs/squashfs/decompressor_multi.c b/fs/squashfs/decompressor_multi.c
index d6008a636479..0bf1ac0f554e 100644
--- a/fs/squashfs/decompressor_multi.c
+++ b/fs/squashfs/decompressor_multi.c
@@ -8,7 +8,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>
@@ -182,14 +182,15 @@ static struct decomp_stream *get_decomp_stream(struct squashfs_sb_info *msblk,
 }
 
 
-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",
diff --git a/fs/squashfs/decompressor_single.c b/fs/squashfs/decompressor_single.c
index a6c75929a00e..43dcfeadc33e 100644
--- a/fs/squashfs/decompressor_single.c
+++ b/fs/squashfs/decompressor_single.c
@@ -9,7 +9,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"
@@ -61,14 +61,15 @@ void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk)
 	}
 }
 
-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);
 
diff --git a/fs/squashfs/lz4_wrapper.c b/fs/squashfs/lz4_wrapper.c
index 95da65366548..ae014118cb7a 100644
--- a/fs/squashfs/lz4_wrapper.c
+++ b/fs/squashfs/lz4_wrapper.c
@@ -6,7 +6,7 @@
  * the COPYING file in the top-level directory.
  */
 
-#include <linux/buffer_head.h>
+#include <linux/bio.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -91,20 +91,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 squashfs_lz4 *stream = strm;
 	void *buff = stream->input, *data;
-	int avail, i, bytes = length, res;
+	int bytes = length, res;
+	int i;
 
-	for (i = 0; i < b; i++) {
-		avail = min(bytes, msblk->devblksize - offset);
-		memcpy(buff, bh[i]->b_data + offset, avail);
+	for (i = 0; i < bio->bi_vcnt; ++i) {
+		struct bio_vec bvec = bio->bi_io_vec[i];
+		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,
diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c
index 934c17e96590..572e0faca290 100644
--- a/fs/squashfs/lzo_wrapper.c
+++ b/fs/squashfs/lzo_wrapper.c
@@ -22,7 +22,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>
@@ -76,21 +76,23 @@ 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 squashfs_lzo *stream = strm;
 	void *buff = stream->input, *data;
-	int avail, i, bytes = length, res;
+	int i, 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);
+	for (i = 0; i < bio->bi_vcnt; ++i) {
+		struct bio_vec bvec = bio->bi_io_vec[i];
+		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,
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
index f89f8a74c6ce..b2f2c1fa2d17 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -53,8 +53,8 @@ extern void *squashfs_decompressor_setup(struct super_block *, unsigned short);
 /* 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 */
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c
index 6bfaef73d065..78ccaf9c5459 100644
--- a/fs/squashfs/xz_wrapper.c
+++ b/fs/squashfs/xz_wrapper.c
@@ -23,7 +23,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>
@@ -130,11 +130,11 @@ 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;
+	int total = 0, k = 0;
 	struct squashfs_xz *stream = strm;
 
 	xz_dec_reset(stream->state);
@@ -145,10 +145,15 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
 	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);
+		if (stream->buf.in_pos == stream->buf.in_size &&
+		    k < bio->bi_vcnt) {
+			struct bio_vec bvec = bio->bi_io_vec[k];
+			int avail = min(length, ((int)bvec.bv_len) - offset);
+			const void *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;
@@ -164,22 +169,18 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm,
 
 		xz_err = xz_dec_run(stream->state, &stream->buf);
 
-		if (stream->buf.in_pos == stream->buf.in_size && k < b)
-			put_bh(bh[k++]);
+		if (stream->buf.in_pos == stream->buf.in_size &&
+		    k < bio->bi_vcnt) {
+			k++;
+		}
 	} while (xz_err == XZ_OK);
 
 	squashfs_finish_page(output);
 
-	if (xz_err != XZ_STREAM_END || k < b)
-		goto out;
+	if (xz_err != XZ_STREAM_END || k < bio->bi_vcnt)
+		return -EIO;
 
 	return total + stream->buf.out_pos;
-
-out:
-	for (; k < b; k++)
-		put_bh(bh[k]);
-
-	return -EIO;
 }
 
 const struct squashfs_decompressor squashfs_xz_comp_ops = {
diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c
index 2ec24d128bce..c620f342d31e 100644
--- a/fs/squashfs/zlib_wrapper.c
+++ b/fs/squashfs/zlib_wrapper.c
@@ -23,7 +23,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>
@@ -63,7 +63,7 @@ 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;
@@ -74,10 +74,14 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
 	stream->avail_in = 0;
 
 	do {
-		if (stream->avail_in == 0 && k < b) {
-			int avail = min(length, msblk->devblksize - offset);
+		if (stream->avail_in == 0 && k < bio->bi_vcnt) {
+			struct bio_vec bvec = bio->bi_io_vec[k];
+			int avail = min(length, ((int)bvec.bv_len) - offset);
+			const void *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;
 		}
@@ -92,36 +96,30 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm,
 			zlib_err = zlib_inflateInit(stream);
 			if (zlib_err != Z_OK) {
 				squashfs_finish_page(output);
-				goto out;
+				return -EIO;
 			}
 			zlib_init = 1;
 		}
 
 		zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
 
-		if (stream->avail_in == 0 && k < b)
-			put_bh(bh[k++]);
+		if (stream->avail_in == 0 && k < bio->bi_vcnt)
+			k++;
 	} while (zlib_err == Z_OK);
 
 	squashfs_finish_page(output);
 
 	if (zlib_err != Z_STREAM_END)
-		goto out;
+		return -EIO;
 
 	zlib_err = zlib_inflateEnd(stream);
 	if (zlib_err != Z_OK)
-		goto out;
+		return -EIO;
 
-	if (k < b)
-		goto out;
+	if (k < bio->bi_vcnt)
+		return -EIO;
 
 	return stream->total_out;
-
-out:
-	for (; k < b; k++)
-		put_bh(bh[k]);
-
-	return -EIO;
 }
 
 const struct squashfs_decompressor squashfs_zlib_comp_ops = {
diff --git a/fs/squashfs/zstd_wrapper.c b/fs/squashfs/zstd_wrapper.c
index eeaabf881159..0531d8b3a930 100644
--- a/fs/squashfs/zstd_wrapper.c
+++ b/fs/squashfs/zstd_wrapper.c
@@ -18,7 +18,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>
@@ -68,7 +68,7 @@ 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;
@@ -83,18 +83,21 @@ static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
 
 	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);
+		if (in_buf.pos == in_buf.size && k < bio->bi_vcnt) {
+			struct bio_vec bvec = bio->bi_io_vec[k];
+			int avail = min(length, ((int)bvec.bv_len) - offset);
+			const void *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;
@@ -107,7 +110,7 @@ static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
 				 * before stream is done.
 				 */
 				squashfs_finish_page(output);
-				goto out;
+				return -EIO;
 			}
 			out_buf.pos = 0;
 			out_buf.size = PAGE_SIZE;
@@ -117,8 +120,8 @@ static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
 		zstd_err = ZSTD_decompressStream(stream, &out_buf, &in_buf);
 		total_out += out_buf.pos; /* add the additional data produced */
 
-		if (in_buf.pos == in_buf.size && k < b)
-			put_bh(bh[k++]);
+		if (in_buf.pos == in_buf.size && k < bio->bi_vcnt)
+			k++;
 	} while (zstd_err != 0 && !ZSTD_isError(zstd_err));
 
 	squashfs_finish_page(output);
@@ -126,19 +129,13 @@ static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
 	if (ZSTD_isError(zstd_err)) {
 		ERROR("zstd decompression error: %d\n",
 				(int)ZSTD_getErrorCode(zstd_err));
-		goto out;
+		return -EIO;
 	}
 
-	if (k < b)
-		goto out;
+	if (k < bio->bi_vcnt)
+		return -EIO;
 
 	return (int)total_out;
-
-out:
-	for (; k < b; k++)
-		put_bh(bh[k]);
-
-	return -EIO;
 }
 
 const struct squashfs_decompressor squashfs_zstd_comp_ops = {
-- 
2.24.0.rc1.363.gb1bccd3e3d-goog


             reply	other threads:[~2019-11-05  7:54 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-05  7:53 Philippe Liard [this message]
2019-11-05 15:21 ` [PATCH v2] squashfs: Migrate from ll_rw_block usage to BIO Christoph Hellwig

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=20191105075339.15280-1-pliard@google.com \
    --to=pliard@google.com \
    --cc=groeck@chromium.org \
    --cc=hch@lst.de \
    --cc=linux-kernel@vger.kernel.org \
    --cc=phillip@squashfs.org.uk \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.