* [PATCH v2 2/2] erofs-utils: mkfs: enable `--blobdev` for compressed inode layouts
2026-09-11 3:59 [PATCH v2 1/2] erofs-utils: mkfs: defer compressed metadata generation Gao Xiang
@ 2026-09-11 3:59 ` Gao Xiang
2026-09-11 8:35 ` [PATCH v2 1/2] erofs-utils: mkfs: defer compressed metadata generation Yifan Zhao
1 sibling, 0 replies; 4+ messages in thread
From: Gao Xiang @ 2026-09-11 3:59 UTC (permalink / raw)
To: linux-erofs; +Cc: Gao Xiang
Add metadata-only image support for compressed inode layouts, e.g.:
$ mkfs.erofs -zlz4 --blobdev blob.erofs fsmeta.erofs foo/
Note that `-Efragments` and `-Ededupe` haven't supported yet.
Follow-up: support rebuild mode for compressed inode layouts.
Signed-off-by: Gao Xiang <xiang@kernel.org>
---
include/erofs/dedupe.h | 1 +
include/erofs/internal.h | 12 ++----
lib/compress.c | 83 +++++++++++++++++++++++++++++-----------
lib/data.c | 16 ++++++++
lib/inode.c | 5 ++-
lib/super.c | 6 +--
lib/tar.c | 2 +-
lib/xattr.c | 2 +-
8 files changed, 89 insertions(+), 38 deletions(-)
diff --git a/include/erofs/dedupe.h b/include/erofs/dedupe.h
index 267d9b9..14dd7dc 100644
--- a/include/erofs/dedupe.h
+++ b/include/erofs/dedupe.h
@@ -16,6 +16,7 @@ struct z_erofs_inmem_extent {
erofs_off_t pstart;
unsigned int plen;
unsigned int length;
+ unsigned short device_id;
bool raw, partial, inlined;
};
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 0de71fb..3ca5553 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -513,6 +513,8 @@ static inline int erofs_get_occupied_size(const struct erofs_inode *inode,
}
/* data.c */
+int erofs_dev_write(struct erofs_sb_info *sbi, int device_id,
+ const void *buf, u64 offset, size_t len);
int erofs_getxattr(struct erofs_inode *vi, const char *name, char *buffer,
size_t buffer_size);
int erofs_listxattr(struct erofs_inode *vi, char *buffer, size_t buffer_size);
@@ -533,18 +535,10 @@ int erofs_blob_open_ro(struct erofs_sb_info *sbi, const char *dev);
ssize_t erofs_dev_read(struct erofs_sb_info *sbi, int device_id,
void *buf, u64 offset, size_t len);
-static inline int erofs_dev_write(struct erofs_sb_info *sbi, const void *buf,
- u64 offset, size_t len)
-{
- if (erofs_io_pwrite(&sbi->bdev, buf, offset, len) != (ssize_t)len)
- return -EIO;
- return 0;
-}
-
static inline int erofs_blk_write(struct erofs_sb_info *sbi, const void *buf,
erofs_blk_t blkaddr, u32 nblocks)
{
- return erofs_dev_write(sbi, buf, erofs_pos(sbi, blkaddr),
+ return erofs_dev_write(sbi, 0, buf, erofs_pos(sbi, blkaddr),
erofs_pos(sbi, nblocks));
}
diff --git a/lib/compress.c b/lib/compress.c
index df97eb9..c9b268f 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -51,6 +51,7 @@ struct z_erofs_compress_ictx { /* inode context */
/* fields for write indexes */
u8 *metacur;
struct list_head extents;
+ u16 device_id;
u16 clusterofs;
int seg_num;
u32 max_compressed_extent_size;
@@ -172,6 +173,7 @@ static void z_erofs_write_full_indexes(struct z_erofs_index_writer *ctx,
unsigned int d0 = 0, d1 = (clusterofs + count) >> bbits;
struct z_erofs_lcluster_index di;
unsigned int type, advise;
+ erofs_blk_t blkaddr;
DBG_BUGON(!count);
DBG_BUGON(e->pstart & (BIT(bbits) - 1));
@@ -190,10 +192,14 @@ static void z_erofs_write_full_indexes(struct z_erofs_index_writer *ctx,
Z_EROFS_LCLUSTER_TYPE_HEAD1;
di.di_advise = cpu_to_le16(type);
- if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL && !e->plen)
+ if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL && !e->plen) {
di.di_u.blkaddr = cpu_to_le32(inode->fragmentoff >> 32);
- else
- di.di_u.blkaddr = cpu_to_le32(e->pstart >> bbits);
+ } else {
+ blkaddr = e->pstart >> bbits;
+ if (e->device_id)
+ blkaddr += sbi->devs[e->device_id - 1].uniaddr;
+ di.di_u.blkaddr = cpu_to_le32(blkaddr);
+ }
memcpy(ctx->metacur, &di, sizeof(di));
ctx->metacur += sizeof(di);
@@ -235,10 +241,14 @@ static void z_erofs_write_full_indexes(struct z_erofs_index_writer *ctx,
Z_EROFS_LCLUSTER_TYPE_HEAD1;
if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL &&
- !e->plen)
+ !e->plen) {
di.di_u.blkaddr = cpu_to_le32(inode->fragmentoff >> 32);
- else
- di.di_u.blkaddr = cpu_to_le32(e->pstart >> bbits);
+ } else {
+ blkaddr = e->pstart >> bbits;
+ if (e->device_id)
+ blkaddr += sbi->devs[e->device_id - 1].uniaddr;
+ di.di_u.blkaddr = cpu_to_le32(blkaddr);
+ }
if (e->partial) {
DBG_BUGON(e->raw);
@@ -255,7 +265,7 @@ static void z_erofs_write_full_indexes(struct z_erofs_index_writer *ctx,
++d0;
--d1;
- } while (clusterofs + count >= 1 << bbits);
+ } while (clusterofs + count >= (1 << bbits));
ctx->clusterofs = clusterofs + count;
}
@@ -394,6 +404,8 @@ static int write_uncompressed_block(struct z_erofs_compress_sctx *ctx,
struct erofs_sb_info *sbi = inode->sbi;
unsigned int count = min(erofs_blksiz(sbi), len);
unsigned int interlaced_offset, rightpart;
+ unsigned int device_id = ctx->ictx->device_id;
+ unsigned int bs = erofs_blksiz(sbi);
int ret;
/* write interlaced uncompressed data if needed */
@@ -415,7 +427,7 @@ static int write_uncompressed_block(struct z_erofs_compress_sctx *ctx,
} else {
erofs_dbg("Writing %u uncompressed data to %llu", count,
ctx->pstart | 0ULL);
- ret = erofs_dev_write(sbi, dst, ctx->pstart, erofs_blksiz(sbi));
+ ret = erofs_dev_write(sbi, device_id, dst, ctx->pstart, bs);
if (ret)
return ret;
}
@@ -452,6 +464,7 @@ static int write_uncompressed_extents(struct z_erofs_compress_sctx *ctx,
.plen = round_up(count, erofs_blksiz(inode->sbi)),
.raw = true,
.pstart = ctx->pstart,
+ .device_id = ctx->ictx->device_id,
};
if (ctx->pstart != EROFS_NULL_ADDR)
ctx->pstart += ei->e.plen;
@@ -584,6 +597,7 @@ static int __z_erofs_compress_one(struct z_erofs_compress_sctx *ctx,
bool may_inline = (params->ztailpacking && !data_unaligned && tsg &&
final && !may_packing);
unsigned int compressedsize;
+ int device_id = ictx->device_id;
int ret;
DBG_BUGON(ctx->pivot);
@@ -734,8 +748,8 @@ frag_packing:
erofs_dbg("Writing %u compressed data to %llu of %u bytes",
e->length, ctx->pstart, e->plen);
- ret = erofs_dev_write(sbi, dst - padding, ctx->pstart,
- e->plen);
+ ret = erofs_dev_write(sbi, device_id, dst - padding,
+ ctx->pstart, e->plen);
if (ret)
return ret;
}
@@ -748,6 +762,7 @@ frag_packing:
e->pstart = ctx->pstart;
if (ctx->pstart != EROFS_NULL_ADDR)
ctx->pstart += e->plen;
+ e->device_id = device_id;
if (!may_inline && !may_packing && !is_packed_inode)
(void)z_erofs_dedupe_insert(e, ctx->queue + ctx->head);
ctx->head += e->length;
@@ -1087,17 +1102,19 @@ static int z_erofs_prepare_layout(struct erofs_inode *inode,
struct z_erofs_extent_item *ei;
erofs_off_t pstart, pend;
unsigned int recsz, moff;
+ int devid;
ei = list_first_entry(&ctx->extents, struct z_erofs_extent_item,
list);
lclusterbits = max_t(u8, ilog2(ei->e.length - 1) + 1, sbi->blkszbits);
pend = pstart = ei->e.pstart;
+ devid = ei->e.device_id;
nexts = 0;
list_for_each_entry(ei, &ctx->extents, list) {
pstart_hi |= (ei->e.pstart > UINT32_MAX);
if ((ei->e.pstart | ei->e.plen) & ((1U << sbi->blkszbits) - 1))
unaligned_data = true;
- if (pend != ei->e.pstart)
+ if (pend != ei->e.pstart || devid != ei->e.device_id)
pend = EROFS_NULL_ADDR;
else
pend += ei->e.plen;
@@ -1181,11 +1198,13 @@ static void z_erofs_write_extents(struct erofs_inode *inode,
struct list_head *extents, u8 *metabuf)
{
unsigned int recsz = z_erofs_extent_recsize(inode->z_advise);
+ struct erofs_sb_info *sbi = inode->sbi;
struct z_erofs_extent_item *ei, *n;
erofs_off_t pstart, lstart;
unsigned int moff;
u8 *metacur;
u64 nexts;
+ int devid;
moff = Z_EROFS_MAP_HEADER_END(inode->inode_isize + inode->xattr_isize);
moff = round_up(moff, recsz) -
@@ -1194,6 +1213,10 @@ static void z_erofs_write_extents(struct erofs_inode *inode,
if (recsz <= 4) {
ei = list_first_entry(extents, struct z_erofs_extent_item, list);
pstart = ei->e.pstart;
+ devid = ei->e.device_id;
+ if (devid)
+ pstart += (erofs_off_t)sbi->devs[devid - 1].uniaddr
+ << sbi->blkszbits;
*(__le64 *)metacur = cpu_to_le64(pstart);
metacur += sizeof(__le64);
}
@@ -1207,18 +1230,23 @@ static void z_erofs_write_extents(struct erofs_inode *inode,
plen = ei->e.plen;
if (!plen) {
plen = inode->fragmentoff;
- ei->e.pstart = inode->fragmentoff >> 32;
+ pstart = inode->fragmentoff >> 32;
} else {
fmt = ei->e.raw ? 0 : inode->z_algorithmtype[0] + 1;
plen |= fmt << Z_EROFS_EXTENT_PLEN_FMT_BIT;
if (ei->e.partial)
plen |= Z_EROFS_EXTENT_PLEN_PARTIAL;
+ pstart = ei->e.pstart;
+ devid = ei->e.device_id;
+ if (devid)
+ pstart += (erofs_off_t)sbi->devs[devid - 1].uniaddr
+ << sbi->blkszbits;
}
de = (struct z_erofs_extent) {
.plen = cpu_to_le32(plen),
- .pstart_lo = cpu_to_le32(ei->e.pstart),
+ .pstart_lo = cpu_to_le32(pstart),
.lstart_lo = cpu_to_le32(lstart),
- .pstart_hi = cpu_to_le32(ei->e.pstart >> 32),
+ .pstart_hi = cpu_to_le32(pstart >> 32),
.lstart_hi = cpu_to_le32(lstart >> 32),
};
memcpy(metacur, &de, recsz);
@@ -1467,6 +1495,8 @@ char *z_erofs_write_metadata(struct erofs_inode *inode)
DBG_BUGON(list_empty(&mctx->extents));
ei = list_first_entry(&mctx->extents, struct z_erofs_extent_item, list);
pstart = ei->e.pstart;
+ if (ei->e.device_id)
+ pstart += sbi->devs[ei->e.device_id - 1].uniaddr << sbi->blkszbits;
list_for_each_entry_safe(ei, n, &mctx->extents, list) {
DBG_BUGON(ei->list.next != &mctx->extents &&
@@ -1663,8 +1693,8 @@ int z_erofs_merge_segment(struct z_erofs_compress_ictx *ictx,
}
erofs_dbg("Writing %u %scompressed data of %s to %llu", ei->e.length,
ei->e.raw ? "un" : "", ictx->inode->i_srcpath, ei->e.pstart);
- ret2 = erofs_dev_write(sbi, sctx->membuf + off, ei->e.pstart,
- ei->e.plen);
+ ret2 = erofs_dev_write(sbi, ei->e.device_id, sctx->membuf + off,
+ ei->e.pstart, ei->e.plen);
off += ei->e.plen;
if (ret2)
ret = ret2;
@@ -1757,9 +1787,11 @@ int erofs_mt_write_compressed_file(struct z_erofs_compress_ictx *ictx)
struct erofs_buffer_head *bh = NULL;
struct erofs_compress_work *head = ictx->mtworks, *cur;
erofs_off_t pstart, ptotal = 0;
+ struct erofs_bufmgr *bmgr = ictx->device_id ?
+ sbi->devs[ictx->device_id - 1].bmgr : sbi->bmgr;
int ret;
- bh = erofs_balloc(sbi->bmgr, DATA, 0, 0);
+ bh = erofs_balloc(bmgr, DATA, 0, 0);
if (IS_ERR(bh)) {
ret = PTR_ERR(bh);
goto out;
@@ -1916,6 +1948,11 @@ void *erofs_prepare_compressed_file(struct erofs_importer *im,
}
ictx->im = im;
ictx->inode = inode;
+ ictx->device_id = !params->fragments && !params->dedupe &&
+ !erofs_is_packed_inode(inode) &&
+ !erofs_is_metabox_inode(inode) &&
+ params->ddev_id_def && S_ISREG(inode->i_mode) ?
+ params->ddev_id_def : 0;
if (erofs_is_metabox_inode(inode))
ictx->ccfg = &sbi->zmgr->ccfg[cfg.c_mkfs_metabox_algid];
else
@@ -2047,6 +2084,8 @@ int erofs_write_compressed_file(struct z_erofs_compress_ictx *ictx)
struct erofs_compress_cfg *ccfg = ictx->ccfg;
struct erofs_inode *inode = ictx->inode;
struct erofs_sb_info *sbi = inode->sbi;
+ struct erofs_bufmgr *bmgr = ictx->device_id ?
+ sbi->devs[ictx->device_id - 1].bmgr : sbi->bmgr;
erofs_off_t pstart;
int ret;
@@ -2056,7 +2095,7 @@ int erofs_write_compressed_file(struct z_erofs_compress_ictx *ictx)
#endif
/* allocate main data buffer */
- bh = erofs_balloc(inode->sbi->bmgr, DATA, 0, 0);
+ bh = erofs_balloc(bmgr, DATA, 0, 0);
if (IS_ERR(bh)) {
ret = PTR_ERR(bh);
goto err_free_idata;
@@ -2167,7 +2206,7 @@ static int z_erofs_build_compr_cfgs(struct erofs_importer *im,
return PTR_ERR(bh);
}
erofs_mapbh(NULL, bh->block);
- ret = erofs_dev_write(sbi, &lz4alg, erofs_btell(bh, false),
+ ret = erofs_dev_write(sbi, 0, &lz4alg, erofs_btell(bh, false),
sizeof(lz4alg));
bh->op = &erofs_drop_directly_bhops;
}
@@ -2191,7 +2230,7 @@ static int z_erofs_build_compr_cfgs(struct erofs_importer *im,
return PTR_ERR(bh);
}
erofs_mapbh(NULL, bh->block);
- ret = erofs_dev_write(sbi, &lzmaalg, erofs_btell(bh, false),
+ ret = erofs_dev_write(sbi, 0, &lzmaalg, erofs_btell(bh, false),
sizeof(lzmaalg));
bh->op = &erofs_drop_directly_bhops;
}
@@ -2215,7 +2254,7 @@ static int z_erofs_build_compr_cfgs(struct erofs_importer *im,
return PTR_ERR(bh);
}
erofs_mapbh(NULL, bh->block);
- ret = erofs_dev_write(sbi, &zalg, erofs_btell(bh, false),
+ ret = erofs_dev_write(sbi, 0, &zalg, erofs_btell(bh, false),
sizeof(zalg));
bh->op = &erofs_drop_directly_bhops;
}
@@ -2238,7 +2277,7 @@ static int z_erofs_build_compr_cfgs(struct erofs_importer *im,
return PTR_ERR(bh);
}
erofs_mapbh(NULL, bh->block);
- ret = erofs_dev_write(sbi, &zalg, erofs_btell(bh, false),
+ ret = erofs_dev_write(sbi, 0, &zalg, erofs_btell(bh, false),
sizeof(zalg));
bh->op = &erofs_drop_directly_bhops;
}
diff --git a/lib/data.c b/lib/data.c
index fa2907b..c73cbe3 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -8,8 +8,24 @@
#include "erofs/internal.h"
#include "erofs/trace.h"
#include "erofs/decompress.h"
+#include "liberofs_cache.h"
#include "liberofs_fragments.h"
+int erofs_dev_write(struct erofs_sb_info *sbi, int device_id,
+ const void *buf, u64 offset, size_t len)
+{
+ ssize_t ret;
+
+ ret = erofs_io_pwrite(device_id ?
+ sbi->devs[device_id - 1].bmgr->vf : &sbi->bdev,
+ buf, offset, len);
+ if (ret < 0)
+ return ret;
+ if (ret != (ssize_t)len)
+ return -EIO;
+ return 0;
+}
+
void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)
{
struct erofs_sb_info *sbi = buf->sbi;
diff --git a/lib/inode.c b/lib/inode.c
index 6f3748a..62958d1 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -511,7 +511,7 @@ static int erofs_rebuild_inode_fix_pnid(struct erofs_inode *parent,
if (!fixed)
continue;
- err = erofs_dev_write(dir.sbi, buf,
+ err = erofs_dev_write(dir.sbi, 0, buf,
(off + bsz > dir.i_size &&
dir.datalayout == EROFS_INODE_FLAT_INLINE ?
erofs_iloc(&dir) + isz : boff + off), count);
@@ -2488,7 +2488,8 @@ int erofs_fixup_root_inode(struct erofs_inode *root)
return -ENOMEM;
err = erofs_dev_read(sbi, 0, ibuf, erofs_iloc(root), ondisk_size);
if (err >= 0)
- err = erofs_dev_write(sbi, ibuf, erofs_iloc(&oi), ondisk_size);
+ err = erofs_dev_write(sbi, 0, ibuf, erofs_iloc(&oi),
+ ondisk_size);
free(ibuf);
return err;
}
diff --git a/lib/super.c b/lib/super.c
index 1358101..71b9f4f 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -270,7 +270,7 @@ int erofs_writesb(struct erofs_sb_info *sbi)
}
memcpy(buf + EROFS_SUPER_OFFSET, &sb, sbi->sb_size);
- ret = erofs_dev_write(sbi, buf, sb_bh ? erofs_btell(sb_bh, false) : 0,
+ ret = erofs_dev_write(sbi, 0, buf, sb_bh ? erofs_btell(sb_bh, false) : 0,
EROFS_SUPER_OFFSET + sbi->sb_size);
free(buf);
if (sb_bh)
@@ -352,7 +352,7 @@ int erofs_enable_sb_chksum(struct erofs_sb_info *sbi, u32 *crc)
/* set up checksum field to erofs_super_block */
sb->checksum = cpu_to_le32(*crc);
- ret = erofs_dev_write(sbi, buf, EROFS_SUPER_OFFSET, len);
+ ret = erofs_dev_write(sbi, 0, buf, EROFS_SUPER_OFFSET, len);
if (ret) {
erofs_err("failed to write checksummed superblock: %s",
erofs_strerror(ret));
@@ -460,7 +460,7 @@ int erofs_write_device_table(struct erofs_sb_info *sbi)
};
memcpy(dis.tag, di->tag, sizeof(dis.tag));
- ret = erofs_dev_write(sbi, &dis, pos, sizeof(dis));
+ ret = erofs_dev_write(sbi, 0, &dis, pos, sizeof(dis));
if (ret)
return ret;
pos += sizeof(dis);
diff --git a/lib/tar.c b/lib/tar.c
index f027532..f24ad95 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -705,7 +705,7 @@ static int tarerofs_write_uncompressed_file(struct erofs_inode *inode,
ret = -EIO;
break;
}
- if (erofs_dev_write(sbi, buf,
+ if (erofs_dev_write(sbi, 0, buf,
erofs_pos(sbi, inode->u.i_blkaddr) + pos,
ret)) {
ret = -EIO;
diff --git a/lib/xattr.c b/lib/xattr.c
index af45075..3cf8c79 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -1055,7 +1055,7 @@ int erofs_load_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *pa
xamgr->shared_xattrs = sorted_n[0];
free(sorted_n);
bh->op = &erofs_drop_directly_bhops;
- ret = erofs_dev_write(sbi, buf, erofs_btell(bh, false), shared_xattrs_size);
+ ret = erofs_dev_write(sbi, 0, buf, erofs_btell(bh, false), shared_xattrs_size);
free(buf);
erofs_bdrop(bh, false);
return ret;
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v2 1/2] erofs-utils: mkfs: defer compressed metadata generation
2026-09-11 3:59 [PATCH v2 1/2] erofs-utils: mkfs: defer compressed metadata generation Gao Xiang
2026-09-11 3:59 ` [PATCH v2 2/2] erofs-utils: mkfs: enable `--blobdev` for compressed inode layouts Gao Xiang
@ 2026-09-11 8:35 ` Yifan Zhao
2026-09-11 10:33 ` Gao Xiang
1 sibling, 1 reply; 4+ messages in thread
From: Yifan Zhao @ 2026-09-11 8:35 UTC (permalink / raw)
To: Gao Xiang, linux-erofs
On 11/9/26 11:59, Gao Xiang wrote:
> Generally, unique addresses should be assigned after the size of
> the primary device is decided.
>
> Defer compressed metadata generation until after
> erofs_update_all_devices(). This is used to support multi-device
> compressed filesystems (including fsmerge support for compressed
> images.)
>
> Signed-off-by: Gao Xiang <xiang@kernel.org>
> ---
> include/erofs/internal.h | 1 -
> lib/compress.c | 484 +++++++++++++++++++++------------------
> lib/inode.c | 10 +-
> lib/liberofs_compress.h | 2 +
> 4 files changed, 277 insertions(+), 220 deletions(-)
>
> diff --git a/include/erofs/internal.h b/include/erofs/internal.h
> index 84a7590..0de71fb 100644
> --- a/include/erofs/internal.h
> +++ b/include/erofs/internal.h
> @@ -212,7 +212,6 @@ struct erofs_diskbuf;
> enum erofs_idata_type {
> EROFS_IDATA_TYPE_RAW,
> EROFS_IDATA_TYPE_COMPRESSED_DEFAULT,
> - EROFS_IDATA_TYPE_COMPRESSED_END_OF_2B,
> };
>
> #define EROFS_I_BLKADDR_DEV_ID_BIT 48
> diff --git a/lib/compress.c b/lib/compress.c
> index 9bbb127..df97eb9 100644
> --- a/lib/compress.c
> +++ b/lib/compress.c
> @@ -139,9 +139,13 @@ struct z_erofs_mgr {
>
> static bool z_erofs_mt_enabled;
>
> -#define Z_EROFS_LEGACY_MAP_HEADER_SIZE Z_EROFS_FULL_INDEX_START(0)
> +struct z_erofs_index_writer {
> + struct erofs_inode *inode;
> + u8 *metacur;
> + unsigned short clusterofs;
> +};
>
> -static void z_erofs_fini_full_indexes(struct z_erofs_compress_ictx *ctx)
> +static void z_erofs_fini_full_indexes(struct z_erofs_index_writer *ctx)
> {
> const unsigned int type = Z_EROFS_LCLUSTER_TYPE_PLAIN;
> struct z_erofs_lcluster_index di;
> @@ -157,10 +161,9 @@ static void z_erofs_fini_full_indexes(struct z_erofs_compress_ictx *ctx)
> ctx->metacur += sizeof(di);
> }
>
> -static void z_erofs_write_full_indexes(struct z_erofs_compress_ictx *ctx,
> +static void z_erofs_write_full_indexes(struct z_erofs_index_writer *ctx,
> struct z_erofs_inmem_extent *e)
> {
> - const struct erofs_importer_params *params = ctx->im->params;
> struct erofs_inode *inode = ctx->inode;
> struct erofs_sb_info *sbi = inode->sbi;
> unsigned int clusterofs = ctx->clusterofs;
> @@ -181,7 +184,7 @@ static void z_erofs_write_full_indexes(struct z_erofs_compress_ictx *ctx,
> * A lcluster cannot have three parts with the middle one which
> * is well-compressed for !ztailpacking cases.
> */
> - DBG_BUGON(!e->raw && !params->ztailpacking && !params->fragments);
> + DBG_BUGON(!e->raw && !inode->idata_size && !inode->fragment_size);
> DBG_BUGON(e->partial);
> type = e->raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
> Z_EROFS_LCLUSTER_TYPE_HEAD1;
> @@ -895,16 +898,16 @@ static void *write_compacted_indexes(u8 *out,
> return out + destsize * vcnt;
> }
>
> -int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
> - erofs_off_t pstart,
> - unsigned int legacymetasize,
> - void *compressmeta)
> +int z_erofs_convert_to_compact_format(struct erofs_inode *inode,
> + erofs_off_t pstart,
> + unsigned int fullmetasz,
> + void *metabuf)
> {
> const unsigned int mpos = roundup(inode->inode_isize +
> inode->xattr_isize, 8) +
> sizeof(struct z_erofs_map_header);
> - const unsigned int totalidx = (legacymetasize -
> - Z_EROFS_LEGACY_MAP_HEADER_SIZE) /
> + const unsigned int totalidx = (fullmetasz -
> + Z_EROFS_FULL_INDEX_START(0)) /
> sizeof(struct z_erofs_lcluster_index);
> const unsigned int logical_clusterbits = inode->z_lclusterbits;
> u8 *out, *in;
> @@ -953,10 +956,18 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
> compacted_4b_end = totalidx;
> }
>
> - out = in = compressmeta;
> + if (!metabuf) {
> + out = (u8 *)sizeof(struct z_erofs_map_header);
> + out += 4 * compacted_4b_initial;
> + out += 2 * compacted_2b;
> + out += 4 * round_up(compacted_4b_end, 2);
> + return out - (u8 *)metabuf;
> + }
> +
> + out = in = metabuf;
>
> out += sizeof(struct z_erofs_map_header);
> - in += Z_EROFS_LEGACY_MAP_HEADER_SIZE;
> + in += Z_EROFS_FULL_INDEX_START(0);
>
> dummy_head = false;
> /* prior to bigpcluster, blkaddr was bumped up once coming into HEAD */
> @@ -977,9 +988,6 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
>
> /* generate compacted_2b */
> if (compacted_2b) {
> - if (!compacted_4b_end && inode->idata_size &&
> - inode->idata_type != EROFS_IDATA_TYPE_RAW)
> - inode->idata_type = EROFS_IDATA_TYPE_COMPRESSED_END_OF_2B;
> do {
> in = parse_legacy_indexes(cv, 16, in);
> out = write_compacted_indexes(out, cv, &blkaddr,
> @@ -1006,8 +1014,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
> 4, logical_clusterbits, true,
> &dummy_head, big_pcluster);
> }
> - inode->extent_isize = out - (u8 *)compressmeta;
> - return 0;
> + return out - (u8 *)metabuf;
> }
>
> static void z_erofs_write_mapheader(struct erofs_inode *inode,
> @@ -1044,78 +1051,156 @@ static void z_erofs_write_mapheader(struct erofs_inode *inode,
> h.h_fragmentoff = cpu_to_le32(inode->fragmentoff);
> else
> h.h_idata_size = cpu_to_le16(inode->idata_size);
> -
> - memset(compressmeta, 0, Z_EROFS_LEGACY_MAP_HEADER_SIZE);
> }
> + memset(compressmeta, 0, Z_EROFS_FULL_INDEX_START(0));
> /* write out map header */
> memcpy(compressmeta, &h, sizeof(struct z_erofs_map_header));
> }
>
> #define EROFS_FULL_INDEXES_SZ(inode) \
> (BLK_ROUND_UP(inode->sbi, inode->i_size) * \
> - sizeof(struct z_erofs_lcluster_index) + Z_EROFS_LEGACY_MAP_HEADER_SIZE)
> + sizeof(struct z_erofs_lcluster_index) + Z_EROFS_FULL_INDEX_START(0))
> +
> +struct z_erofs_metadata_ctx {
> + struct list_head extents;
> +};
>
> -static void *z_erofs_write_extents(struct z_erofs_compress_ictx *ctx)
> +static int z_erofs_prepare_layout(struct erofs_inode *inode,
> + struct list_head *extents,
> + bool consecutive, bool no_compact)
> {
> - struct erofs_inode *inode = ctx->inode;
> struct erofs_sb_info *sbi = inode->sbi;
> - struct z_erofs_extent_item *ei, *n;
> - unsigned int lclusterbits, nexts;
> - bool pstart_hi = false, unaligned_data = false;
> - erofs_off_t pstart, pend, lstart;
> - unsigned int recsz, metasz, moff;
> - void *metabuf;
> -
> - ei = list_first_entry(&ctx->extents, struct z_erofs_extent_item,
> - list);
> - lclusterbits = max_t(u8, ilog2(ei->e.length - 1) + 1, sbi->blkszbits);
> - pend = pstart = ei->e.pstart;
> - nexts = 0;
> - list_for_each_entry(ei, &ctx->extents, list) {
> - pstart_hi |= (ei->e.pstart > UINT32_MAX);
> - if ((ei->e.pstart | ei->e.plen) & ((1U << sbi->blkszbits) - 1))
> - unaligned_data = true;
> - if (pend != ei->e.pstart)
> - pend = EROFS_NULL_ADDR;
> - else
> - pend += ei->e.plen;
> - if (ei->e.length != 1 << lclusterbits) {
> - if (ei->list.next != &ctx->extents ||
> - ei->e.length > 1 << lclusterbits)
> - lclusterbits = 0;
> + struct z_erofs_metadata_ctx *ctx;
> + unsigned int metasz;
> + int ret;
> +
> + ctx = malloc(sizeof(*ctx));
> + if (!ctx)
> + return -ENOMEM;
> + init_list_head(&ctx->extents);
> + list_splice_tail(extents, &ctx->extents);
> +
> + /* TODO: support writing encoded extents for ztailpacking later. */
> + if (erofs_sb_has_48bit(sbi) && !inode->idata_size) {
> + bool pstart_hi = false, unaligned_data = false;
> + unsigned int lclusterbits, nexts;
> + struct z_erofs_extent_item *ei;
> + erofs_off_t pstart, pend;
> + unsigned int recsz, moff;
> +
> + ei = list_first_entry(&ctx->extents, struct z_erofs_extent_item,
> + list);
> + lclusterbits = max_t(u8, ilog2(ei->e.length - 1) + 1, sbi->blkszbits);
> + pend = pstart = ei->e.pstart;
> + nexts = 0;
> + list_for_each_entry(ei, &ctx->extents, list) {
> + pstart_hi |= (ei->e.pstart > UINT32_MAX);
> + if ((ei->e.pstart | ei->e.plen) & ((1U << sbi->blkszbits) - 1))
> + unaligned_data = true;
> + if (pend != ei->e.pstart)
> + pend = EROFS_NULL_ADDR;
> + else
> + pend += ei->e.plen;
> + if (ei->e.length != 1 << lclusterbits) {
> + if (ei->list.next != &ctx->extents ||
> + ei->e.length > 1 << lclusterbits)
> + lclusterbits = 0;
> + }
> + ++nexts;
> }
> - ++nexts;
> + inode->z_extents = nexts;
Hi Xiang,
I think this line seems redundant as `z_extents` is not used with
encoded extents disabled.
> + recsz = inode->i_size > UINT32_MAX ? 32 : 16;
> + if (lclusterbits) {
> + if (pend != EROFS_NULL_ADDR)
> + recsz = 4;
> + else if (recsz <= 16 && !pstart_hi)
> + recsz = 8;
> + }
> +
> + moff = Z_EROFS_MAP_HEADER_END(inode->inode_isize + inode->xattr_isize);
> + moff = round_up(moff, recsz) -
> + Z_EROFS_MAP_HEADER_START(inode->inode_isize + inode->xattr_isize);
> + metasz = moff + recsz * nexts + 8 * (recsz <= 4);
> + if (unaligned_data || metasz < EROFS_FULL_INDEXES_SZ(inode)) {
> + inode->z_lclusterbits = lclusterbits;
> + inode->z_extents = nexts;
> + inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
> + inode->z_advise |= Z_EROFS_ADVISE_EXTENTS |
> + ((ilog2(recsz) - 2) << Z_EROFS_ADVISE_EXTRECSZ_BIT);
> + goto out;
> + }
> + }
> +
> + /* if the entire file is a fragment, a simplified form is used. */
> + if (inode->i_size <= inode->fragment_size) {
> + DBG_BUGON(inode->i_size < inode->fragment_size);
> + DBG_BUGON(inode->fragmentoff >> 63);
> + inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
> + metasz = Z_EROFS_FULL_INDEX_START(0);
> + goto out;
> + }
> +
Consider moving this entire-fragment-file-check before the encoded
extent selection above?
Otherwise once encoded extent selected, this check will be bypassed and
`metasz` will not be set as Z_EROFS_FULL_INDEX_START(0).
(Although this does not affect correctness, because
z_erofs_write_metadata() will check and set entire-fragment-file-check
again)
> + /*
> + * If the packed inode is larger than 4GiB, the full fragmentoff
> + * will be recorded by switching to the noncompact layout anyway.
> + */
> + if (inode->fragment_size && inode->fragmentoff >> 32) {
> + inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
> + } else if (!no_compact && consecutive &&
> + inode->z_lclusterbits <= 14) {
> + if (inode->z_lclusterbits <= 12)
> + inode->z_advise |= Z_EROFS_ADVISE_COMPACTED_2B;
> + inode->datalayout = EROFS_INODE_COMPRESSED_COMPACT;
> + } else {
> + inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
> + }
> +
> + if (erofs_sb_has_big_pcluster(sbi)) {
> + inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_1;
> + if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT)
> + inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_2;
> }
>
> - recsz = inode->i_size > UINT32_MAX ? 32 : 16;
> - if (lclusterbits) {
> - if (pend != EROFS_NULL_ADDR)
> - recsz = 4;
> - else if (recsz <= 16 && !pstart_hi)
> - recsz = 8;
> + metasz = EROFS_FULL_INDEXES_SZ(inode);
> +
> + if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT) {
> + ret = z_erofs_convert_to_compact_format(inode, 0, metasz,
> + NULL);
> + if (ret < 0)
> + return ret;
> + metasz = ret;
> }
>
> +out:
> + inode->extent_isize = metasz;
> + inode->compressmeta = ctx;
> + return 0;
> +}
> +
> +static void z_erofs_write_extents(struct erofs_inode *inode,
> + struct list_head *extents, u8 *metabuf)
> +{
> + unsigned int recsz = z_erofs_extent_recsize(inode->z_advise);
> + struct z_erofs_extent_item *ei, *n;
> + erofs_off_t pstart, lstart;
> + unsigned int moff;
> + u8 *metacur;
> + u64 nexts;
> +
> moff = Z_EROFS_MAP_HEADER_END(inode->inode_isize + inode->xattr_isize);
> moff = round_up(moff, recsz) -
> Z_EROFS_MAP_HEADER_START(inode->inode_isize + inode->xattr_isize);
> - metasz = moff + recsz * nexts + 8 * (recsz <= 4);
> - if (!unaligned_data && metasz > EROFS_FULL_INDEXES_SZ(inode))
> - return ERR_PTR(-EAGAIN);
> -
> - metabuf = malloc(metasz);
> - if (!metabuf)
> - return ERR_PTR(-ENOMEM);
> - inode->z_lclusterbits = lclusterbits;
> - inode->z_extents = nexts;
> - ctx->metacur = metabuf + moff;
> + metacur = metabuf + moff;
> if (recsz <= 4) {
> - *(__le64 *)ctx->metacur = cpu_to_le64(pstart);
> - ctx->metacur += sizeof(__le64);
> + ei = list_first_entry(extents, struct z_erofs_extent_item, list);
> + pstart = ei->e.pstart;
> + *(__le64 *)metacur = cpu_to_le64(pstart);
> + metacur += sizeof(__le64);
> }
>
> nexts = 0;
> lstart = 0;
> - list_for_each_entry_safe(ei, n, &ctx->extents, list) {
> + list_for_each_entry_safe(ei, n, extents, list) {
> struct z_erofs_extent de;
> u32 fmt, plen;
>
> @@ -1136,128 +1221,30 @@ static void *z_erofs_write_extents(struct z_erofs_compress_ictx *ctx)
> .pstart_hi = cpu_to_le32(ei->e.pstart >> 32),
> .lstart_hi = cpu_to_le32(lstart >> 32),
> };
> - memcpy(ctx->metacur, &de, recsz);
> - ctx->metacur += recsz;
> + memcpy(metacur, &de, recsz);
> + metacur += recsz;
> lstart += ei->e.length;
> list_del(&ei->list);
> free(ei);
> + ++nexts;
> }
> - inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
> - inode->z_advise |= Z_EROFS_ADVISE_EXTENTS |
> - ((ilog2(recsz) - 2) << Z_EROFS_ADVISE_EXTRECSZ_BIT);
> - return metabuf;
> -}
> -
> -static void *z_erofs_write_indexes(struct z_erofs_compress_ictx *ctx)
> -{
> - const struct erofs_importer_params *params = ctx->im->params;
> - struct erofs_inode *inode = ctx->inode;
> - struct erofs_sb_info *sbi = inode->sbi;
> - struct z_erofs_extent_item *ei, *n;
> - void *metabuf;
> -
> - /* TODO: support writing encoded extents for ztailpacking later. */
> - if (erofs_sb_has_48bit(sbi) && !inode->idata_size) {
> - metabuf = z_erofs_write_extents(ctx);
> - if (metabuf != ERR_PTR(-EAGAIN)) {
> - if (IS_ERR(metabuf))
> - return metabuf;
> - goto out;
> - }
> - }
> -
> - /*
> - * If the packed inode is larger than 4GiB, the full fragmentoff
> - * will be recorded by switching to the noncompact layout anyway.
> - */
> - if (inode->fragment_size && inode->fragmentoff >> 32) {
> - inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
> - } else if (!params->no_zcompact && !ctx->dedupe &&
> - inode->z_lclusterbits <= 14) {
> - if (inode->z_lclusterbits <= 12)
> - inode->z_advise |= Z_EROFS_ADVISE_COMPACTED_2B;
> - inode->datalayout = EROFS_INODE_COMPRESSED_COMPACT;
> - } else {
> - inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
> - }
> -
> - if (erofs_sb_has_big_pcluster(sbi)) {
> - inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_1;
> - if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT)
> - inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_2;
> - }
> -
> - metabuf = malloc(BLK_ROUND_UP(inode->sbi, inode->i_size) *
> - sizeof(struct z_erofs_lcluster_index) +
> - Z_EROFS_LEGACY_MAP_HEADER_SIZE);
> - if (!metabuf)
> - return ERR_PTR(-ENOMEM);
> -
> - ctx->metacur = metabuf + Z_EROFS_LEGACY_MAP_HEADER_SIZE;
> - ctx->clusterofs = 0;
> - list_for_each_entry_safe(ei, n, &ctx->extents, list) {
> - DBG_BUGON(ei->list.next != &ctx->extents &&
> - ctx->clusterofs + ei->e.length < erofs_blksiz(sbi));
> - z_erofs_write_full_indexes(ctx, &ei->e);
> -
> - list_del(&ei->list);
> - free(ei);
> - }
> - z_erofs_fini_full_indexes(ctx);
> -out:
> - z_erofs_write_mapheader(inode, metabuf);
> - return metabuf;
> + DBG_BUGON(inode->z_extents && nexts != inode->z_extents);
> + DBG_BUGON(metacur - metabuf != inode->extent_isize);
> }
>
> void z_erofs_drop_inline_pcluster(struct erofs_inode *inode)
> {
> - struct erofs_sb_info *sbi = inode->sbi;
> - const unsigned int type = Z_EROFS_LCLUSTER_TYPE_PLAIN;
> - struct z_erofs_map_header *h = inode->compressmeta;
> + struct z_erofs_metadata_ctx *ctx = inode->compressmeta;
> + struct z_erofs_extent_item *ei;
>
> - h->h_advise = cpu_to_le16(le16_to_cpu(h->h_advise) &
> - ~Z_EROFS_ADVISE_INLINE_PCLUSTER);
> - DBG_BUGON(inode->idata_size != le16_to_cpu(h->h_idata_size));
> - h->h_idata_size = 0;
> + inode->z_advise &= ~Z_EROFS_ADVISE_INLINE_PCLUSTER;
> if (!inode->eof_tailraw)
> return;
> DBG_BUGON(inode->idata_type == EROFS_IDATA_TYPE_RAW);
>
> - /* patch the EOF lcluster to uncompressed type first */
> - if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL) {
> - struct z_erofs_lcluster_index *di =
> - (inode->compressmeta + inode->extent_isize) -
> - sizeof(struct z_erofs_lcluster_index);
> -
> - di->di_advise = cpu_to_le16(type);
> - } else if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT) {
> - /* handle the last compacted 4B/2B pack */
> - unsigned int lclusterbits = inode->z_lclusterbits;
> - unsigned int lobits, eofs, base, pos, v;
> - u8 *out;
> -
> - lobits = max(lclusterbits, ilog2(Z_EROFS_LI_D0_CBLKCNT) + 1U);
> -
> - if (inode->idata_type == EROFS_IDATA_TYPE_COMPRESSED_DEFAULT) {
> - eofs = inode->extent_isize -
> - (4 << (BLK_ROUND_UP(sbi, inode->i_size) & 1));
> - base = round_down(eofs, 8);
> - pos = 16 /* encodebits */ * ((eofs - base) / 4);
> - out = inode->compressmeta + base + pos / 8;
> - } else {
> - out = inode->compressmeta + inode->extent_isize -
> - sizeof(__le32) - sizeof(__le16);
> - lobits = 16 - 14 /* encodebits */ + lobits;
> - }
> -
> - v = (get_unaligned_le16(out) & (BIT(lobits) - 1)) |
> - (type << lobits);
> - *out = v & 0xff;
> - *(out + 1) = v >> 8;
> - } else {
> - DBG_BUGON(1);
> - return;
> - }
> + ei = list_last_entry(&ctx->extents, struct z_erofs_extent_item, list);
> + DBG_BUGON(ei->e.raw);
> + ei->e.raw = true;
> free(inode->idata);
> /* replace idata with prepared uncompressed data */
> inode->idata = inode->eof_tailraw;
> @@ -1341,6 +1328,22 @@ int z_erofs_compress_segment(struct z_erofs_compress_sctx *ctx,
> return 0;
> }
>
> +void z_erofs_free_metadata(struct erofs_inode *inode)
> +{
> + struct z_erofs_metadata_ctx *mctx = inode->compressmeta;
> + struct z_erofs_extent_item *ei, *n;
> +
> + if (!mctx)
> + return;
> +
> + list_for_each_entry_safe(ei, n, &mctx->extents, list) {
> + list_del(&ei->list);
> + free(ei);
> + }
> + free(mctx);
> + inode->compressmeta = NULL;
> +}
> +
> int erofs_commit_compressed_file(struct z_erofs_compress_ictx *ictx,
> struct erofs_buffer_head *bh,
> erofs_off_t pstart, erofs_off_t ptotal)
> @@ -1348,8 +1351,7 @@ int erofs_commit_compressed_file(struct z_erofs_compress_ictx *ictx,
> struct erofs_inode *inode = ictx->inode;
> const struct erofs_importer_params *params = ictx->im->params;
> struct erofs_sb_info *sbi = inode->sbi;
> - unsigned int legacymetasize, bbits = sbi->blkszbits;
> - u8 *compressmeta;
> + unsigned int bbits = sbi->blkszbits;
> int ret;
>
> if (inode->fragment_size) {
> @@ -1367,16 +1369,14 @@ int erofs_commit_compressed_file(struct z_erofs_compress_ictx *ictx,
> DBG_BUGON(pstart < (!!inode->idata_size) << bbits);
> ptotal -= (u64)(!!inode->idata_size) << bbits;
>
> - compressmeta = z_erofs_write_indexes(ictx);
> - if (!compressmeta) {
> - ret = -ENOMEM;
> + ret = z_erofs_prepare_layout(inode, &ictx->extents, !ictx->dedupe,
> + params->no_zcompact);
> + if (ret)
> goto err_free_idata;
> - }
>
> - legacymetasize = ictx->metacur - compressmeta;
> /* estimate if data compression saves space or not */
> if (!inode->fragment_size && ptotal + inode->idata_size +
> - legacymetasize >= inode->i_size) {
> + inode->extent_isize >= inode->i_size) {
> z_erofs_dedupe_ext_commit(true);
> z_erofs_dedupe_commit(true);
> ret = EROFS_RETVAL_FALLBACK;
> @@ -1388,16 +1388,6 @@ int erofs_commit_compressed_file(struct z_erofs_compress_ictx *ictx,
> if (!ictx->fragemitted)
> sbi->saved_by_deduplication += inode->fragment_size;
>
> - /* if the entire file is a fragment, a simplified form is used. */
> - if (inode->i_size <= inode->fragment_size) {
> - DBG_BUGON(inode->i_size < inode->fragment_size);
> - DBG_BUGON(inode->fragmentoff >> 63);
> - *(__le64 *)compressmeta =
> - cpu_to_le64(inode->fragmentoff | 1ULL << 63);
> - inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
> - legacymetasize = Z_EROFS_LEGACY_MAP_HEADER_SIZE;
> - }
> -
> if (ptotal)
> (void)erofs_bh_balloon(bh, ptotal);
> else if (!params->fragments && params->dedupe != EROFS_DEDUPE_FORCE_ON)
> @@ -1414,21 +1404,11 @@ int erofs_commit_compressed_file(struct z_erofs_compress_ictx *ictx,
> }
>
> inode->u.i_blocks = BLK_ROUND_UP(sbi, ptotal);
> -
> - if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL) {
> - inode->extent_isize = legacymetasize;
> - } else {
> - ret = z_erofs_convert_to_compacted_format(inode, pstart,
> - legacymetasize,
> - compressmeta);
> - DBG_BUGON(ret);
> - }
> - inode->compressmeta = compressmeta;
> return 0;
>
> err_free_meta:
> - free(compressmeta);
> - inode->compressmeta = NULL;
> + z_erofs_free_metadata(inode);
> + inode->extent_isize = 0;
> err_free_idata:
> erofs_bdrop(bh, true); /* revoke buffer */
> if (inode->idata) {
> @@ -1438,6 +1418,82 @@ err_free_idata:
> return ret;
> }
>
> +char *z_erofs_write_metadata(struct erofs_inode *inode)
> +{
> + struct erofs_sb_info *sbi = inode->sbi;
> + struct z_erofs_metadata_ctx *mctx = inode->compressmeta;
> + struct z_erofs_extent_item *ei, *n;
> + struct z_erofs_index_writer ctx;
> + unsigned int metasz =
> + inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT ?
> + EROFS_FULL_INDEXES_SZ(inode) : inode->extent_isize;
> + erofs_off_t pstart;
> + u8 *metabuf;
> + int err = 0;
> +
> + metabuf = malloc(metasz);
> + if (!metabuf) {
> + err = -ENOMEM;
> + goto out;
> + }
> +
> + /* if the entire file is a fragment, a simplified form is used. */
> + if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL &&
> + inode->i_size <= inode->fragment_size) {
> + DBG_BUGON(inode->i_size < inode->fragment_size);
> + DBG_BUGON(inode->fragmentoff >> 63);
How about add `DBG_BUGON(metasz != Z_EROFS_FULL_INDEX_START(0))` here?
Also, We should initialize all 16 bytes of metabuf here, rather than
just the first 8 bytes and leave the remaining 8 bytes uninitialized,
because this logic bypasses z_erofs_write_mapheader() below, which clear
16-byte-metadata before this patch.
( FYI `Z_EROFS_FULL_INDEX_START(0)` equals to 16)
Thanks,
Yifan
> + *(__le64 *)metabuf = cpu_to_le64(inode->fragmentoff | 1ULL << 63);
> + goto out;
> + }
> +
> + if (__erofs_unlikely(!mctx)) {
> + DBG_BUGON(1);
> + return ERR_PTR(-EINVAL);
> + }
> +
> + z_erofs_write_mapheader(inode, metabuf);
> +
> + if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL &&
> + (inode->z_advise & Z_EROFS_ADVISE_EXTENTS)) {
> + z_erofs_write_extents(inode, &mctx->extents, metabuf);
> + goto out;
> + }
> +
> + ctx = (struct z_erofs_index_writer) {
> + .inode = inode,
> + .metacur = metabuf + Z_EROFS_FULL_INDEX_START(0),
> + };
> +
> + DBG_BUGON(list_empty(&mctx->extents));
> + ei = list_first_entry(&mctx->extents, struct z_erofs_extent_item, list);
> + pstart = ei->e.pstart;
> +
> + list_for_each_entry_safe(ei, n, &mctx->extents, list) {
> + DBG_BUGON(ei->list.next != &mctx->extents &&
> + ctx.clusterofs + ei->e.length < erofs_blksiz(sbi));
> + z_erofs_write_full_indexes(&ctx, &ei->e);
> +
> + list_del(&ei->list);
> + free(ei);
> + }
> + z_erofs_fini_full_indexes(&ctx);
> + DBG_BUGON(metasz != ctx.metacur - metabuf);
> +
> + if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT) {
> + err = z_erofs_convert_to_compact_format(inode, pstart,
> + metasz, metabuf);
> + if (err < 0) {
> + DBG_BUGON(1);
> + goto out;
> + }
> + metasz = err;
> + }
> + DBG_BUGON(metasz != inode->extent_isize);
> +out:
> + z_erofs_free_metadata(inode);
> + return err < 0 ? ERR_PTR(err) : metabuf;
> +}
> +
> static struct z_erofs_compress_ictx g_ictx;
>
> #ifdef EROFS_MT_ENABLED
> @@ -2053,24 +2109,23 @@ int erofs_begin_compress_dir(struct erofs_importer *im,
>
> {
> if (!im->params->compress_dir ||
> - inode->i_size < Z_EROFS_LEGACY_MAP_HEADER_SIZE)
> + inode->i_size < Z_EROFS_FULL_INDEX_START(0))
> return EROFS_RETVAL_FALLBACK;
>
> inode->z_advise |= Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
> erofs_sb_set_fragments(inode->sbi);
> inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
> - inode->extent_isize = Z_EROFS_LEGACY_MAP_HEADER_SIZE;
> + inode->extent_isize = Z_EROFS_FULL_INDEX_START(0);
> inode->compressmeta = NULL;
> return 0;
> }
>
> int erofs_write_compress_dir(struct erofs_inode *inode, struct erofs_vfile *vf)
> {
> - void *compressmeta;
> int err;
>
> if (inode->datalayout != EROFS_INODE_COMPRESSED_FULL ||
> - inode->extent_isize < Z_EROFS_LEGACY_MAP_HEADER_SIZE) {
> + inode->extent_isize < Z_EROFS_FULL_INDEX_START(0)) {
> DBG_BUGON(1);
> return -EINVAL;
> }
> @@ -2081,13 +2136,8 @@ int erofs_write_compress_dir(struct erofs_inode *inode, struct erofs_vfile *vf)
> err = erofs_fragment_commit(inode, ~0);
> if (err)
> return err;
> -
> - compressmeta = calloc(1, Z_EROFS_LEGACY_MAP_HEADER_SIZE);
> - if (!compressmeta)
> - return -ENOMEM;
> - *(__le64 *)compressmeta =
> - cpu_to_le64(inode->fragmentoff | 1ULL << 63);
> - inode->compressmeta = compressmeta;
> + DBG_BUGON(inode->fragment_size != inode->i_size);
> + DBG_BUGON(inode->compressmeta);
> return 0;
> }
>
> diff --git a/lib/inode.c b/lib/inode.c
> index 2cd7bed..6f3748a 100644
> --- a/lib/inode.c
> +++ b/lib/inode.c
> @@ -149,7 +149,7 @@ unsigned int erofs_iput(struct erofs_inode *inode)
> list_for_each_entry_safe(d, t, &inode->i_subdirs, d_child)
> free(d);
>
> - free(inode->compressmeta);
> + z_erofs_free_metadata(inode);
> free(inode->eof_tailraw);
> erofs_remove_ihash(inode);
> if (!erofs_is_special_identifier(inode->i_srcpath))
> @@ -925,9 +925,15 @@ int erofs_iflush(struct erofs_inode *inode)
> if (inode->datalayout == EROFS_INODE_CHUNK_BASED) {
> ret = erofs_write_chunk_indexes(inode, ibmgr->vf, off);
> } else { /* write compression metadata */
> + char *metabuf;
> +
> off = roundup(off, 8);
> - ret = erofs_io_pwrite(ibmgr->vf, inode->compressmeta,
> + metabuf = z_erofs_write_metadata(inode);
> + if (IS_ERR(metabuf))
> + return PTR_ERR(metabuf);
> + ret = erofs_io_pwrite(ibmgr->vf, metabuf,
> off, inode->extent_isize);
> + free(metabuf);
> }
> if (ret != inode->extent_isize)
> return ret < 0 ? ret : -EIO;
> diff --git a/lib/liberofs_compress.h b/lib/liberofs_compress.h
> index da6eb1a..50b3804 100644
> --- a/lib/liberofs_compress.h
> +++ b/lib/liberofs_compress.h
> @@ -19,6 +19,8 @@ void *erofs_prepare_compressed_file(struct erofs_importer *im,
> struct erofs_inode *inode);
> void erofs_bind_compressed_file_with_fd(struct z_erofs_compress_ictx *ictx,
> int fd, u64 fpos);
> +void z_erofs_free_metadata(struct erofs_inode *inode);
> +char *z_erofs_write_metadata(struct erofs_inode *inode);
> int erofs_begin_compressed_file(struct z_erofs_compress_ictx *ictx);
> int erofs_write_compressed_file(struct z_erofs_compress_ictx *ictx);
>
^ permalink raw reply [flat|nested] 4+ messages in thread