erofs-utils: support decompress in-place
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@huawei.com>
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_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 3c34f5b..601b477 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -13,10 +13,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;
@@ -30,9 +37,10 @@
/* 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 ed4dba4..a977c87 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -113,6 +113,36 @@
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)
@@ -121,7 +151,8 @@
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;
@@ -143,32 +174,22 @@
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 @@
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 f67edde..17e4d09 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -107,6 +107,7 @@
.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);