[PATCH v2 16/17] erofs-utils: support decompress in-place

Gao Xiang gaoxiang25 at huawei.com
Tue Jul 16 17:04:18 AEST 2019


In the view of kernel, it usually loads compressed data into
last pages of the extent (the last page for 4k) for in-place
decompression (more specifically, in-place IO), as ilustration
below,

         start of compressed logical extent
           |                          end of this logical extent
           |                           |
     ______v___________________________v________
... |  page 6  |  page 7  |  page 8  |  page 9  | ...
    |__________|__________|__________|__________|
           .                         ^ .        ^
           .                         |compressed|
           .                         |   data   |
           .                           .        .
           |<          dstsize        >|<margin>|
                                       oend     iend
           op                        ip

It's natural to think it further, why not decompressing in-place?

1) Decompressing in-place can be easily implemented since oend is
   _strictly_ not greater than iend for fixed-output decompression;
2) Decompressing in-place can be guaranteed with a appropriate
   minimum margin rather than do decompress simulatation
   for all extents;
*) Many implementations of memcpy can perform overlapped copy
   well if op <= ip (it'd better to use memmove, of course).

This patch enables 0PADDING in order to support decompress in-place.

Signed-off-by: Gao Xiang <gaoxiang25 at huawei.com>
---
 include/erofs/internal.h |  2 ++
 include/erofs_fs.h       | 14 +++++++--
 lib/compress.c           | 61 +++++++++++++++++++++++++++-------------
 lib/config.c             |  2 ++
 mkfs/main.c              |  1 +
 5 files changed, 57 insertions(+), 23 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 07a6f72..b7ce6f8 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -51,6 +51,8 @@ struct erofs_buffer_head;
 struct erofs_sb_info {
 	erofs_blk_t meta_blkaddr;
 	erofs_blk_t xattr_blkaddr;
+
+	u32 requirements;
 };
 
 /* global sbi */
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index d9999bb..ad01494 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -17,10 +17,17 @@
 #define EROFS_SUPER_MAGIC_V1    0xE0F5E1E2
 #define EROFS_SUPER_OFFSET      1024
 
+/*
+ * Any bits that aren't in EROFS_ALL_REQUIREMENTS should be
+ * incompatible with this kernel version.
+ */
+#define EROFS_REQUIREMENT_LZ4_0PADDING	0x00000001
+#define EROFS_ALL_REQUIREMENTS		EROFS_REQUIREMENT_LZ4_0PADDING
+
 struct erofs_super_block {
 /*  0 */__le32 magic;           /* in the little endian */
 /*  4 */__le32 checksum;        /* crc32c(super_block) */
-/*  8 */__le32 features;
+/*  8 */__le32 features;        /* (aka. feature_compat) */
 /* 12 */__u8 blkszbits;         /* support block_size == PAGE_SIZE only */
 /* 13 */__u8 reserved;
 
@@ -34,9 +41,10 @@ struct erofs_super_block {
 /* 44 */__le32 xattr_blkaddr;
 /* 48 */__u8 uuid[16];          /* 128-bit uuid for volume */
 /* 64 */__u8 volume_name[16];   /* volume name */
+/* 80 */__le32 requirements;    /* (aka. feature_incompat) */
 
-/* 80 */__u8 reserved2[48];     /* 128 bytes */
-} __packed;
+/* 84 */__u8 reserved2[44];
+} __packed;                     /* 128 bytes */
 
 /*
  * erofs inode data mapping:
diff --git a/lib/compress.c b/lib/compress.c
index 0063b97..bb799b4 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -110,6 +110,36 @@ static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
 	ctx->clusterofs = clusterofs + count;
 }
 
+static int write_uncompressed_block(struct z_erofs_vle_compress_ctx *ctx,
+				    unsigned int *len,
+				    char *dst)
+{
+	int ret;
+	unsigned int count;
+
+	if (!(sbi.requirements & EROFS_REQUIREMENT_LZ4_0PADDING)) {
+		/* fix up clusterofs to 0 if possable */
+		if (ctx->head >= ctx->clusterofs) {
+			ctx->head -= ctx->clusterofs;
+			*len += ctx->clusterofs;
+			ctx->clusterofs = 0;
+		}
+	}
+
+	/* write uncompressed data */
+	count = min(EROFS_BLKSIZ, *len);
+
+	memcpy(dst, ctx->queue + ctx->head, count);
+	memset(dst + count, 0, EROFS_BLKSIZ - count);
+
+	erofs_dbg("Writing %u uncompressed data to block %u",
+		  count, ctx->blkaddr);
+	ret = blk_write(dst, ctx->blkaddr, 1);
+	if (ret)
+		return ret;
+	return count;
+}
+
 static int vle_compress_one(struct erofs_inode *inode,
 			    struct z_erofs_vle_compress_ctx *ctx,
 			    bool final)
@@ -118,7 +148,8 @@ static int vle_compress_one(struct erofs_inode *inode,
 	unsigned int len = ctx->tail - ctx->head;
 	unsigned int count;
 	int ret;
-	char dst[EROFS_BLKSIZ];
+	static char dstbuf[EROFS_BLKSIZ * 2];
+	char *const dst = dstbuf + EROFS_BLKSIZ;
 
 	while (len) {
 		bool raw;
@@ -140,32 +171,22 @@ static int vle_compress_one(struct erofs_inode *inode,
 					  erofs_strerror(ret));
 			}
 nocompression:
-			/* fix up clusterofs to 0 if possable */
-			if (ctx->head >= ctx->clusterofs) {
-				ctx->head -= ctx->clusterofs;
-				len += ctx->clusterofs;
-				ctx->clusterofs = 0;
-			}
-
-			/* write uncompressed data */
-			count = min(EROFS_BLKSIZ, len);
-
-			memcpy(dst, ctx->queue + ctx->head, count);
-			memset(dst + count, 0, EROFS_BLKSIZ - count);
-
-			erofs_dbg("Writing %u uncompressed data to block %u",
-				  count, ctx->blkaddr);
-
-			ret = blk_write(dst, ctx->blkaddr, 1);
-			if (ret)
+			ret = write_uncompressed_block(ctx, &len, dst);
+			if (ret < 0)
 				return ret;
+			count = ret;
 			raw = true;
 		} else {
 			/* write compressed data */
 			erofs_dbg("Writing %u compressed data to block %u",
 				  count, ctx->blkaddr);
 
-			ret = blk_write(dst, ctx->blkaddr, 1);
+			if (sbi.requirements & EROFS_REQUIREMENT_LZ4_0PADDING)
+				ret = blk_write(dst - (EROFS_BLKSIZ - ret),
+						ctx->blkaddr, 1);
+			else
+				ret = blk_write(dst, ctx->blkaddr, 1);
+
 			if (ret)
 				return ret;
 			raw = false;
diff --git a/lib/config.c b/lib/config.c
index 07e2846..2e91b92 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -8,6 +8,7 @@
  */
 #include <string.h>
 #include "erofs/print.h"
+#include "erofs/internal.h"
 
 struct erofs_configure cfg;
 
@@ -20,6 +21,7 @@ void erofs_init_configure(void)
 	cfg.c_dry_run  = false;
 	cfg.c_legacy_compress = false;
 	cfg.c_compr_level_master = -1;
+	sbi.requirements = EROFS_REQUIREMENT_LZ4_0PADDING;
 }
 
 void erofs_show_config(void)
diff --git a/mkfs/main.c b/mkfs/main.c
index 595137b..eb75bdb 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -107,6 +107,7 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 		.blocks = 0,
 		.meta_blkaddr  = sbi.meta_blkaddr,
 		.xattr_blkaddr = 0,
+		.requirements = cpu_to_le32(sbi.requirements),
 	};
 	const unsigned int sb_blksize =
 		round_up(EROFS_SUPER_END, EROFS_BLKSIZ);
-- 
2.17.1



More information about the Linux-erofs mailing list