Currently mkfs writes the lcluster indexes(with on-disk format) in an
extent by extent manner during the compression of a file, which is
inflexible if we want to modify the indexes later in the multi-threaded
compression scenario.

In order to support the multi-threaded compression feature of mkfs,
this patch moves the writing of the lcluster indexes to take place after
the file's compression is completed.

Signed-off-by: Yifan Zhao <[email protected]>
---
 include/erofs/dedupe.h |   4 +-
 lib/compress.c         | 366 ++++++++++++++++++++++++-----------------
 lib/dedupe.c           |   1 +
 3 files changed, 223 insertions(+), 148 deletions(-)

diff --git a/include/erofs/dedupe.h b/include/erofs/dedupe.h
index 153bd4c..a3e365b 100644
--- a/include/erofs/dedupe.h
+++ b/include/erofs/dedupe.h
@@ -16,7 +16,9 @@ struct z_erofs_inmem_extent {
        erofs_blk_t blkaddr;
        unsigned int compressedblks;
        unsigned int length;
-       bool raw, partial;
+       bool raw, partial, reset_clusterofs;
+
+       struct list_head list;
 };
 
 struct z_erofs_dedupe_ctx {
diff --git a/lib/compress.c b/lib/compress.c
index 4eac363..07ba186 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -30,7 +30,7 @@ struct erofs_compress_cfg {
 
 struct z_erofs_vle_compress_ctx {
        u8 queue[EROFS_CONFIG_COMPR_MAX_SZ * 2];
-       struct z_erofs_inmem_extent e;  /* (lookahead) extent */
+       struct list_head elist;         /* (lookahead) extent list */
 
        struct erofs_inode *inode;
        struct erofs_compress_cfg *ccfg;
@@ -49,121 +49,151 @@ struct z_erofs_vle_compress_ctx {
 
 #define Z_EROFS_LEGACY_MAP_HEADER_SIZE Z_EROFS_FULL_INDEX_ALIGN(0)
 
-static void z_erofs_write_indexes_final(struct z_erofs_vle_compress_ctx *ctx)
+static void z_erofs_update_clusterofs(struct z_erofs_vle_compress_ctx *ctx)
 {
-       const unsigned int type = Z_EROFS_LCLUSTER_TYPE_PLAIN;
-       struct z_erofs_lcluster_index di;
+       struct z_erofs_inmem_extent *e;
+       unsigned int blksz = erofs_blksiz(ctx->inode->sbi);
+       unsigned int offset;
+
+       if (list_empty(&ctx->elist))
+               return;
 
-       if (!ctx->clusterofs)
+       e = list_last_entry(&ctx->elist, struct z_erofs_inmem_extent, list);
+       if (e->length == 0)
                return;
 
-       di.di_clusterofs = cpu_to_le16(ctx->clusterofs);
-       di.di_u.blkaddr = 0;
-       di.di_advise = cpu_to_le16(type << Z_EROFS_LI_LCLUSTER_TYPE_BIT);
+       offset = e->length + ctx->clusterofs;
 
-       memcpy(ctx->metacur, &di, sizeof(di));
-       ctx->metacur += sizeof(di);
+       if (offset < blksz)
+               ctx->clusterofs = 0;
+       else
+               ctx->clusterofs = offset % blksz;
 }
 
 static void z_erofs_write_indexes(struct z_erofs_vle_compress_ctx *ctx)
 {
        struct erofs_inode *inode = ctx->inode;
        struct erofs_sb_info *sbi = inode->sbi;
-       unsigned int clusterofs = ctx->clusterofs;
-       unsigned int count = ctx->e.length;
-       unsigned int d0 = 0, d1 = (clusterofs + count) / erofs_blksiz(sbi);
+       struct z_erofs_inmem_extent *e, *n;
+       unsigned int clusterofs = 0;
+       unsigned int count;
+       unsigned int d0, d1;
        struct z_erofs_lcluster_index di;
        unsigned int type, advise;
 
-       if (!count)
+       if (list_empty(&ctx->elist))
                return;
+       
+       list_for_each_entry_safe(e, n, &ctx->elist, list) {
+               count = e->length;
+               if (!count)
+                       goto free_entry;
 
-       ctx->e.length = 0;      /* mark as written first */
-       di.di_clusterofs = cpu_to_le16(ctx->clusterofs);
+               if (e->reset_clusterofs)
+                       clusterofs = 0;
 
-       /* whether the tail-end (un)compressed block or not */
-       if (!d1) {
-               /*
-                * A lcluster cannot have three parts with the middle one which
-                * is well-compressed for !ztailpacking cases.
-                */
-               DBG_BUGON(!ctx->e.raw && !cfg.c_ztailpacking && 
!cfg.c_fragments);
-               DBG_BUGON(ctx->e.partial);
-               type = ctx->e.raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
-                       Z_EROFS_LCLUSTER_TYPE_HEAD1;
-               advise = type << Z_EROFS_LI_LCLUSTER_TYPE_BIT;
-               di.di_advise = cpu_to_le16(advise);
-
-               if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL &&
-                   !ctx->e.compressedblks)
-                       di.di_u.blkaddr = cpu_to_le32(inode->fragmentoff >> 32);
-               else
-                       di.di_u.blkaddr = cpu_to_le32(ctx->e.blkaddr);
-               memcpy(ctx->metacur, &di, sizeof(di));
-               ctx->metacur += sizeof(di);
+               d0 = 0;
+               d1 = (clusterofs + count) / erofs_blksiz(sbi);
 
-               /* don't add the final index if the tail-end block exists */
-               ctx->clusterofs = 0;
-               return;
-       }
-
-       do {
-               advise = 0;
-               /* XXX: big pcluster feature should be per-inode */
-               if (d0 == 1 && erofs_sb_has_big_pcluster(sbi)) {
-                       type = Z_EROFS_LCLUSTER_TYPE_NONHEAD;
-                       di.di_u.delta[0] = cpu_to_le16(ctx->e.compressedblks |
-                                                      Z_EROFS_LI_D0_CBLKCNT);
-                       di.di_u.delta[1] = cpu_to_le16(d1);
-               } else if (d0) {
-                       type = Z_EROFS_LCLUSTER_TYPE_NONHEAD;
+               di.di_clusterofs = cpu_to_le16(clusterofs);
 
+               /* whether the tail-end (un)compressed block or not */
+               if (!d1) {
                        /*
-                        * If the |Z_EROFS_VLE_DI_D0_CBLKCNT| bit is set, parser
-                        * will interpret |delta[0]| as size of pcluster, rather
-                        * than distance to last head cluster. Normally this
-                        * isn't a problem, because uncompressed extent size are
-                        * below Z_EROFS_VLE_DI_D0_CBLKCNT * BLOCK_SIZE = 8MB.
-                        * But with large pcluster it's possible to go over this
-                        * number, resulting in corrupted compressed indices.
-                        * To solve this, we replace d0 with
-                        * Z_EROFS_VLE_DI_D0_CBLKCNT-1.
-                        */
-                       if (d0 >= Z_EROFS_LI_D0_CBLKCNT)
-                               di.di_u.delta[0] = cpu_to_le16(
-                                               Z_EROFS_LI_D0_CBLKCNT - 1);
-                       else
-                               di.di_u.delta[0] = cpu_to_le16(d0);
-                       di.di_u.delta[1] = cpu_to_le16(d1);
-               } else {
-                       type = ctx->e.raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
+                       * A lcluster cannot have three parts with the middle 
one which
+                       * is well-compressed for !ztailpacking cases.
+                       */
+                       DBG_BUGON(!e->raw && !cfg.c_ztailpacking && 
!cfg.c_fragments);
+                       DBG_BUGON(e->partial);
+                       type = e->raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
                                Z_EROFS_LCLUSTER_TYPE_HEAD1;
+                       advise = type << Z_EROFS_LI_LCLUSTER_TYPE_BIT;
+                       di.di_advise = cpu_to_le16(advise);
 
                        if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL &&
-                           !ctx->e.compressedblks)
+                               !e->compressedblks)
                                di.di_u.blkaddr = 
cpu_to_le32(inode->fragmentoff >> 32);
                        else
-                               di.di_u.blkaddr = cpu_to_le32(ctx->e.blkaddr);
+                               di.di_u.blkaddr = cpu_to_le32(e->blkaddr);
+                       memcpy(ctx->metacur, &di, sizeof(di));
+                       ctx->metacur += sizeof(di);
 
-                       if (ctx->e.partial) {
-                               DBG_BUGON(ctx->e.raw);
-                               advise |= Z_EROFS_LI_PARTIAL_REF;
-                       }
+                       /* don't add the final index if the tail-end block 
exists */
+                       clusterofs = 0;
+                       goto free_entry;
                }
-               advise |= type << Z_EROFS_LI_LCLUSTER_TYPE_BIT;
-               di.di_advise = cpu_to_le16(advise);
 
-               memcpy(ctx->metacur, &di, sizeof(di));
-               ctx->metacur += sizeof(di);
+               do {
+                       advise = 0;
+                       /* XXX: big pcluster feature should be per-inode */
+                       if (d0 == 1 && erofs_sb_has_big_pcluster(sbi)) {
+                               type = Z_EROFS_LCLUSTER_TYPE_NONHEAD;
+                               di.di_u.delta[0] = 
cpu_to_le16(e->compressedblks |
+                                                               
Z_EROFS_LI_D0_CBLKCNT);
+                               di.di_u.delta[1] = cpu_to_le16(d1);
+                       } else if (d0) {
+                               type = Z_EROFS_LCLUSTER_TYPE_NONHEAD;
+
+                               /*
+                               * If the |Z_EROFS_VLE_DI_D0_CBLKCNT| bit is 
set, parser
+                               * will interpret |delta[0]| as size of 
pcluster, rather
+                               * than distance to last head cluster. Normally 
this
+                               * isn't a problem, because uncompressed extent 
size are
+                               * below Z_EROFS_VLE_DI_D0_CBLKCNT * BLOCK_SIZE 
= 8MB.
+                               * But with large pcluster it's possible to go 
over this
+                               * number, resulting in corrupted compressed 
indices.
+                               * To solve this, we replace d0 with
+                               * Z_EROFS_VLE_DI_D0_CBLKCNT-1.
+                               */
+                               if (d0 >= Z_EROFS_LI_D0_CBLKCNT)
+                                       di.di_u.delta[0] = cpu_to_le16(
+                                                       Z_EROFS_LI_D0_CBLKCNT - 
1);
+                               else
+                                       di.di_u.delta[0] = cpu_to_le16(d0);
+                               di.di_u.delta[1] = cpu_to_le16(d1);
+                       } else {
+                               type = e->raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
+                                       Z_EROFS_LCLUSTER_TYPE_HEAD1;
 
-               count -= erofs_blksiz(sbi) - clusterofs;
-               clusterofs = 0;
+                               if (inode->datalayout == 
EROFS_INODE_COMPRESSED_FULL &&
+                                       !e->compressedblks)
+                                       di.di_u.blkaddr = 
cpu_to_le32(inode->fragmentoff >> 32);
+                               else
+                                       di.di_u.blkaddr = 
cpu_to_le32(e->blkaddr);
 
-               ++d0;
-               --d1;
-       } while (clusterofs + count >= erofs_blksiz(sbi));
+                               if (e->partial) {
+                                       DBG_BUGON(e->raw);
+                                       advise |= Z_EROFS_LI_PARTIAL_REF;
+                               }
+                       }
+                       advise |= type << Z_EROFS_LI_LCLUSTER_TYPE_BIT;
+                       di.di_advise = cpu_to_le16(advise);
 
-       ctx->clusterofs = clusterofs + count;
+                       memcpy(ctx->metacur, &di, sizeof(di));
+                       ctx->metacur += sizeof(di);
+
+                       count -= erofs_blksiz(sbi) - clusterofs;
+                       clusterofs = 0;
+
+                       ++d0;
+                       --d1;
+               } while (clusterofs + count >= erofs_blksiz(sbi));
+
+               clusterofs = count;
+
+free_entry:
+               list_del(&e->list);
+               free(e);
+       }
+
+       if (clusterofs) {
+               di.di_clusterofs = cpu_to_le16(clusterofs);
+               di.di_u.blkaddr = 0;
+               di.di_advise = cpu_to_le16(Z_EROFS_LCLUSTER_TYPE_PLAIN <<
+                                          Z_EROFS_LI_LCLUSTER_TYPE_BIT);
+               memcpy(ctx->metacur, &di, sizeof(di));
+               ctx->metacur += sizeof(di);
+       }
 }
 
 static int z_erofs_compress_dedupe(struct z_erofs_vle_compress_ctx *ctx,
@@ -172,8 +202,19 @@ static int z_erofs_compress_dedupe(struct 
z_erofs_vle_compress_ctx *ctx,
        struct erofs_inode *inode = ctx->inode;
        const unsigned int lclustermask = (1 << inode->z_logical_clusterbits) - 
1;
        struct erofs_sb_info *sbi = inode->sbi;
+       struct z_erofs_inmem_extent *e, *newe;
+       int elen = 0;
        int ret = 0;
 
+       if (list_empty(&ctx->elist)) {
+               e = NULL;
+               elen = 0;
+       } else {
+               e = list_last_entry(&ctx->elist, struct z_erofs_inmem_extent,
+                                   list);
+               elen = e->length;
+       }
+
        /*
         * No need dedupe for packed inode since it is composed of
         * fragments which have already been deduplicated.
@@ -184,12 +225,12 @@ static int z_erofs_compress_dedupe(struct 
z_erofs_vle_compress_ctx *ctx,
        do {
                struct z_erofs_dedupe_ctx dctx = {
                        .start = ctx->queue + ctx->head - ({ int rc;
-                               if (ctx->e.length <= erofs_blksiz(sbi))
+                               if (elen <= erofs_blksiz(sbi))
                                        rc = 0;
-                               else if (ctx->e.length - erofs_blksiz(sbi) >= 
ctx->head)
+                               else if (elen - erofs_blksiz(sbi) >= ctx->head)
                                        rc = ctx->head;
                                else
-                                       rc = ctx->e.length - erofs_blksiz(sbi);
+                                       rc = elen - erofs_blksiz(sbi);
                                rc; }),
                        .end = ctx->queue + ctx->head + *len,
                        .cur = ctx->queue + ctx->head,
@@ -206,25 +247,25 @@ static int z_erofs_compress_dedupe(struct 
z_erofs_vle_compress_ctx *ctx,
                 * decompresssion could be done as another try in practice.
                 */
                if (dctx.e.compressedblks > 1 &&
-                   ((ctx->clusterofs + ctx->e.length - delta) & lclustermask) +
+                   ((ctx->clusterofs + elen - delta) & lclustermask) +
                        dctx.e.length < 2 * (lclustermask + 1))
                        break;
 
                if (delta) {
                        DBG_BUGON(delta < 0);
-                       DBG_BUGON(!ctx->e.length);
+                       DBG_BUGON(!e);
 
                        /*
                         * For big pcluster dedupe, if we decide to shorten the
                         * previous big pcluster, make sure that the previous
                         * CBLKCNT is still kept.
                         */
-                       if (ctx->e.compressedblks > 1 &&
-                           (ctx->clusterofs & lclustermask) + ctx->e.length
+                       if (e->compressedblks > 1 &&
+                           (ctx->clusterofs & lclustermask) + e->length
                                - delta < 2 * (lclustermask + 1))
                                break;
-                       ctx->e.partial = true;
-                       ctx->e.length -= delta;
+                       e->partial = true;
+                       e->length -= delta;
                }
 
                /* fall back to noncompact indexes for deduplication */
@@ -237,8 +278,16 @@ static int z_erofs_compress_dedupe(struct 
z_erofs_vle_compress_ctx *ctx,
                erofs_dbg("Dedupe %u %scompressed data (delta %d) to %u of %u 
blocks",
                          dctx.e.length, dctx.e.raw ? "un" : "",
                          delta, dctx.e.blkaddr, dctx.e.compressedblks);
-               z_erofs_write_indexes(ctx);
-               ctx->e = dctx.e;
+               z_erofs_update_clusterofs(ctx);
+
+               newe = malloc(sizeof(*newe));
+               if (!newe) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               memcpy(newe, &dctx.e, sizeof(*newe));
+               list_add_tail(&newe->list, &ctx->elist);
+
                ctx->head += dctx.e.length - delta;
                DBG_BUGON(*len < dctx.e.length - delta);
                *len -= dctx.e.length - delta;
@@ -258,12 +307,12 @@ static int z_erofs_compress_dedupe(struct 
z_erofs_vle_compress_ctx *ctx,
        } while (*len);
 
 out:
-       z_erofs_write_indexes(ctx);
+       z_erofs_update_clusterofs(ctx);
        return ret;
 }
 
 static int write_uncompressed_extent(struct z_erofs_vle_compress_ctx *ctx,
-                                    unsigned int *len, char *dst)
+                                    unsigned int *len, char *dst, struct 
z_erofs_inmem_extent *e)
 {
        int ret;
        struct erofs_sb_info *sbi = ctx->inode->sbi;
@@ -275,6 +324,7 @@ static int write_uncompressed_extent(struct 
z_erofs_vle_compress_ctx *ctx,
                ctx->head -= ctx->clusterofs;
                *len += ctx->clusterofs;
                ctx->clusterofs = 0;
+               e->reset_clusterofs = true;
        }
 
        count = min(erofs_blksiz(sbi), *len);
@@ -400,10 +450,11 @@ static int vle_compress_one(struct 
z_erofs_vle_compress_ctx *ctx)
        unsigned int blksz = erofs_blksiz(sbi);
        char *const dst = dstbuf + blksz;
        struct erofs_compress *const h = &ctx->ccfg->handle;
+       struct z_erofs_inmem_extent *e = NULL;
        unsigned int len = ctx->tail - ctx->head;
        bool is_packed_inode = erofs_is_packed_inode(inode);
        bool final = !ctx->remaining;
-       int ret;
+       int ret = 0;
 
        while (len) {
                bool may_packing = (cfg.c_fragments && final &&
@@ -416,39 +467,44 @@ static int vle_compress_one(struct 
z_erofs_vle_compress_ctx *ctx)
                if (z_erofs_compress_dedupe(ctx, &len) && !final)
                        break;
 
+               e = malloc(sizeof(*e));
+               if (!e)
+                       return -ENOMEM;
+               e->reset_clusterofs = false;
+
                if (len <= ctx->pclustersize) {
                        if (!final || !len)
-                               break;
+                               goto free_extent;
                        if (may_packing) {
                                if (inode->fragment_size && !fix_dedupedfrag) {
                                        ctx->pclustersize = roundup(len, blksz);
                                        goto fix_dedupedfrag;
                                }
-                               ctx->e.length = len;
+                               e->length = len;
                                goto frag_packing;
                        }
                        if (!may_inline && len <= blksz)
                                goto nocompression;
                }
 
-               ctx->e.length = min(len,
+               e->length = min(len,
                                cfg.c_max_decompressed_extent_bytes);
 
                ret = erofs_compress_destsize(h, ctx->queue + ctx->head,
-                               &ctx->e.length, dst, ctx->pclustersize);
+                               &e->length, dst, ctx->pclustersize);
                if (ret <= 0) {
                        erofs_err("failed to compress %s: %s", inode->i_srcpath,
                                  erofs_strerror(ret));
-                       return ret;
+                       goto free_extent;
                }
 
                compressedsize = ret;
                /* even compressed size is smaller, there is no real gain */
-               if (!(may_inline && ctx->e.length == len && ret < blksz))
+               if (!(may_inline && e->length == len && ret < blksz))
                        ret = roundup(ret, blksz);
 
                /* check if there is enough gain to keep the compressed data */
-               if (ret * h->compress_threshold / 100 >= ctx->e.length) {
+               if (ret * h->compress_threshold / 100 >= e->length) {
                        if (may_inline && len < blksz) {
                                ret = z_erofs_fill_inline_data(inode,
                                                ctx->queue + ctx->head,
@@ -457,21 +513,21 @@ static int vle_compress_one(struct 
z_erofs_vle_compress_ctx *ctx)
                                may_inline = false;
                                may_packing = false;
 nocompression:
-                               ret = write_uncompressed_extent(ctx, &len, dst);
+                               ret = write_uncompressed_extent(ctx, &len, dst, 
e);
                        }
 
                        if (ret < 0)
-                               return ret;
-                       ctx->e.length = ret;
+                               goto free_extent;
+                       e->length = ret;
 
                        /*
                         * XXX: For now, we have to leave `ctx->compressedblks
                         * = 1' since there is no way to generate compressed
                         * indexes after the time that ztailpacking is decided.
                         */
-                       ctx->e.compressedblks = 1;
-                       ctx->e.raw = true;
-               } else if (may_packing && len == ctx->e.length &&
+                       e->compressedblks = 1;
+                       e->raw = true;
+               } else if (may_packing && len == e->length &&
                           compressedsize < ctx->pclustersize &&
                           (!inode->fragment_size || fix_dedupedfrag)) {
 frag_packing:
@@ -479,18 +535,20 @@ frag_packing:
                                                     ctx->queue + ctx->head,
                                                     len, ctx->tof_chksum);
                        if (ret < 0)
-                               return ret;
-                       ctx->e.compressedblks = 0; /* indicate a fragment */
-                       ctx->e.raw = false;
+                               goto free_extent;
+                       e->compressedblks = 0; /* indicate a fragment */
+                       e->raw = false;
                        ctx->fragemitted = true;
                        fix_dedupedfrag = false;
                /* tailpcluster should be less than 1 block */
-               } else if (may_inline && len == ctx->e.length &&
+               } else if (may_inline && len == e->length &&
                           compressedsize < blksz) {
                        if (ctx->clusterofs + len <= blksz) {
                                inode->eof_tailraw = malloc(len);
-                               if (!inode->eof_tailraw)
-                                       return -ENOMEM;
+                               if (!inode->eof_tailraw) {
+                                       ret = -ENOMEM;
+                                       goto free_extent;
+                               }
 
                                memcpy(inode->eof_tailraw,
                                       ctx->queue + ctx->head, len);
@@ -500,9 +558,9 @@ frag_packing:
                        ret = z_erofs_fill_inline_data(inode, dst,
                                        compressedsize, false);
                        if (ret < 0)
-                               return ret;
-                       ctx->e.compressedblks = 1;
-                       ctx->e.raw = false;
+                               goto free_extent;
+                       e->compressedblks = 1;
+                       e->raw = false;
                } else {
                        unsigned int tailused, padding;
 
@@ -513,7 +571,7 @@ frag_packing:
                         * filled up. Fix up the fragment if succeeds.
                         * Otherwise, just drop it and go to packing.
                         */
-                       if (may_packing && len == ctx->e.length &&
+                       if (may_packing && len == e->length &&
                            (compressedsize & (blksz - 1)) &&
                            ctx->tail < sizeof(ctx->queue)) {
                                ctx->pclustersize =
@@ -521,15 +579,15 @@ frag_packing:
                                goto fix_dedupedfrag;
                        }
 
-                       if (may_inline && len == ctx->e.length)
+                       if (may_inline && len == e->length)
                                tryrecompress_trailing(ctx, h,
                                                ctx->queue + ctx->head,
-                                               &ctx->e.length, dst,
+                                               &e->length, dst,
                                                &compressedsize);
 
-                       ctx->e.compressedblks = BLK_ROUND_UP(sbi, 
compressedsize);
-                       DBG_BUGON(ctx->e.compressedblks * blksz >=
-                                 ctx->e.length);
+                       e->compressedblks = BLK_ROUND_UP(sbi, compressedsize);
+                       DBG_BUGON(e->compressedblks * blksz >=
+                                 e->length);
 
                        padding = 0;
                        tailused = compressedsize & (blksz - 1);
@@ -544,25 +602,27 @@ frag_packing:
 
                        /* write compressed data */
                        erofs_dbg("Writing %u compressed data to %u of %u 
blocks",
-                                 ctx->e.length, ctx->blkaddr,
-                                 ctx->e.compressedblks);
+                                 e->length, ctx->blkaddr,
+                                 e->compressedblks);
 
                        ret = blk_write(sbi, dst - padding, ctx->blkaddr,
-                                       ctx->e.compressedblks);
+                                       e->compressedblks);
                        if (ret)
-                               return ret;
-                       ctx->e.raw = false;
+                               goto free_extent;
+                       e->raw = false;
                        may_inline = false;
                        may_packing = false;
                }
-               ctx->e.partial = false;
-               ctx->e.blkaddr = ctx->blkaddr;
+               e->partial = false;
+               e->blkaddr = ctx->blkaddr;
                if (!may_inline && !may_packing && !is_packed_inode)
-                       (void)z_erofs_dedupe_insert(&ctx->e,
+                       (void)z_erofs_dedupe_insert(e,
                                                    ctx->queue + ctx->head);
-               ctx->blkaddr += ctx->e.compressedblks;
-               ctx->head += ctx->e.length;
-               len -= ctx->e.length;
+               ctx->blkaddr += e->compressedblks;
+               ctx->head += e->length;
+               len -= e->length;
+
+               list_add_tail(&e->list, &ctx->elist);
 
                if (fix_dedupedfrag &&
                    z_erofs_fixup_deduped_fragment(ctx, len))
@@ -585,9 +645,14 @@ frag_packing:
 fix_dedupedfrag:
        DBG_BUGON(!inode->fragment_size);
        ctx->remaining += inode->fragment_size;
-       ctx->e.length = 0;
        ctx->fix_dedupedfrag = true;
+       e->length = 0;
+       list_add_tail(&e->list, &ctx->elist);
        return 0;
+
+free_extent:
+       free(e);
+       return ret;
 }
 
 struct z_erofs_compressindex_vec {
@@ -874,6 +939,7 @@ int erofs_write_compressed_file(struct erofs_inode *inode, 
int fd)
        erofs_blk_t blkaddr, compressed_blocks;
        unsigned int legacymetasize;
        int ret;
+       struct z_erofs_inmem_extent *e;
        struct erofs_sb_info *sbi = inode->sbi;
        u8 *compressmeta = malloc(BLK_ROUND_UP(sbi, inode->i_size) *
                                  sizeof(struct z_erofs_lcluster_index) +
@@ -942,10 +1008,10 @@ int erofs_write_compressed_file(struct erofs_inode 
*inode, int fd)
        ctx.metacur = compressmeta + Z_EROFS_LEGACY_MAP_HEADER_SIZE;
        ctx.head = ctx.tail = 0;
        ctx.clusterofs = 0;
-       ctx.e.length = 0;
        ctx.remaining = inode->i_size - inode->fragment_size;
        ctx.fix_dedupedfrag = false;
        ctx.fragemitted = false;
+       init_list_head(&ctx.elist);
        if (cfg.c_all_fragments && !erofs_is_packed_inode(inode) &&
            !inode->fragment_size) {
                ret = z_erofs_pack_file_from_fd(inode, fd, ctx.tof_chksum);
@@ -978,17 +1044,23 @@ int erofs_write_compressed_file(struct erofs_inode 
*inode, int fd)
 
        /* generate an extent for the deduplicated fragment */
        if (inode->fragment_size && !ctx.fragemitted) {
-               z_erofs_write_indexes(&ctx);
-               ctx.e.length = inode->fragment_size;
-               ctx.e.compressedblks = 0;
-               ctx.e.raw = false;
-               ctx.e.partial = false;
-               ctx.e.blkaddr = ctx.blkaddr;
+               z_erofs_update_clusterofs(&ctx);
+               e = malloc(sizeof(*e));
+               if (!e) {
+                       ret = -ENOMEM;
+                       goto err_free_idata;
+               }
+               e->length = inode->fragment_size;
+               e->compressedblks = 0;
+               e->raw = false;
+               e->partial = false;
+               e->reset_clusterofs = false;
+               e->blkaddr = ctx.blkaddr;
+               list_add_tail(&e->list, &ctx.elist);
        }
        z_erofs_fragments_commit(inode);
 
        z_erofs_write_indexes(&ctx);
-       z_erofs_write_indexes_final(&ctx);
        legacymetasize = ctx.metacur - compressmeta;
        /* estimate if data compression saves space or not */
        if (!inode->fragment_size &&
diff --git a/lib/dedupe.c b/lib/dedupe.c
index 19a1c8d..993c7a3 100644
--- a/lib/dedupe.c
+++ b/lib/dedupe.c
@@ -138,6 +138,7 @@ int z_erofs_dedupe_match(struct z_erofs_dedupe_ctx *ctx)
                ctx->e.partial = e->partial ||
                        (window_size + extra < e->original_length);
                ctx->e.raw = e->raw;
+               ctx->e.reset_clusterofs = false;
                ctx->e.blkaddr = e->compressed_blkaddr;
                ctx->e.compressedblks = e->compressed_blks;
                return 0;
-- 
2.42.1

Reply via email to