lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20191105075339.15280-1-pliard@google.com>
Date:   Tue,  5 Nov 2019 16:53:39 +0900
From:   Philippe Liard <pliard@...gle.com>
To:     phillip@...ashfs.org.uk, hch@....de
Cc:     linux-kernel@...r.kernel.org, groeck@...omium.org,
        pliard@...gle.com
Subject: [PATCH v2] squashfs: Migrate from ll_rw_block usage to BIO

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@...gle.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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ