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 <[email protected]>
---
 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

Reply via email to