[PATCH v2 09/10] erofs-utils: lib: implement encoded extent metadata
Gao Xiang
hsiangkao at linux.alibaba.com
Thu Apr 10 02:32:58 AEST 2025
Source kernel commit: efb2aef569b35b415c232c4e9fdecd0e540e1f60
Source kernel commit: 1d191b4ca51d73699cb127386b95ac152af2b930
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
fsck/main.c | 2 +-
include/erofs/internal.h | 3 +-
lib/compress.c | 14 +--
lib/zmap.c | 178 ++++++++++++++++++++++++++++++++++-----
4 files changed, 166 insertions(+), 31 deletions(-)
diff --git a/fsck/main.c b/fsck/main.c
index f7e33c0..cb4758b 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -572,7 +572,7 @@ static int erofs_verify_inode_data(struct erofs_inode *inode, int outfd)
}
if (map.m_plen > Z_EROFS_PCLUSTER_MAX_SIZE) {
- if (compressed) {
+ if (compressed && !(map.m_flags & EROFS_MAP_FRAGMENT)) {
erofs_err("invalid pcluster size %" PRIu64 " @ offset %" PRIu64 " of nid %" PRIu64,
map.m_plen, map.m_la,
inode->nid | 0ULL);
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 94bca2d..676f63d 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -262,11 +262,12 @@ struct erofs_inode {
struct {
uint16_t z_advise;
uint8_t z_algorithmtype[2];
- uint8_t z_logical_clusterbits;
+ uint8_t z_lclusterbits;
uint8_t z_physical_clusterblks;
union {
uint64_t z_tailextent_headlcn;
erofs_off_t fragment_size;
+ u64 z_extents;
};
union {
erofs_off_t fragmentoff;
diff --git a/lib/compress.c b/lib/compress.c
index 30bcdd4..f81539a 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -272,7 +272,7 @@ static void z_erofs_commit_extent(struct z_erofs_compress_sctx *ctx,
static int z_erofs_compress_dedupe(struct z_erofs_compress_sctx *ctx)
{
struct erofs_inode *inode = ctx->ictx->inode;
- const unsigned int lclustermask = (1 << inode->z_logical_clusterbits) - 1;
+ const unsigned int lclustermask = (1 << inode->z_lclusterbits) - 1;
struct erofs_sb_info *sbi = inode->sbi;
struct z_erofs_extent_item *ei = ctx->pivot;
@@ -405,7 +405,7 @@ static int write_uncompressed_extents(struct z_erofs_compress_sctx *ctx,
char *dst)
{
struct erofs_inode *inode = ctx->ictx->inode;
- unsigned int lclustersize = 1 << inode->z_logical_clusterbits;
+ unsigned int lclustersize = 1 << inode->z_lclusterbits;
struct z_erofs_extent_item *ei;
int count;
@@ -875,7 +875,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
const unsigned int totalidx = (legacymetasize -
Z_EROFS_LEGACY_MAP_HEADER_SIZE) /
sizeof(struct z_erofs_lcluster_index);
- const unsigned int logical_clusterbits = inode->z_logical_clusterbits;
+ const unsigned int logical_clusterbits = inode->z_lclusterbits;
u8 *out, *in;
struct z_erofs_compressindex_vec cv[16];
struct erofs_sb_info *sbi = inode->sbi;
@@ -984,7 +984,7 @@ static void z_erofs_write_mapheader(struct erofs_inode *inode,
.h_algorithmtype = inode->z_algorithmtype[1] << 4 |
inode->z_algorithmtype[0],
/* lclustersize */
- .h_clusterbits = inode->z_logical_clusterbits - sbi->blkszbits,
+ .h_clusterbits = inode->z_lclusterbits - sbi->blkszbits,
};
if (inode->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER)
@@ -1011,8 +1011,8 @@ static void *z_erofs_write_indexes(struct z_erofs_compress_ictx *ctx)
if (inode->fragment_size && inode->fragmentoff >> 32) {
inode->datalayout = EROFS_INODE_COMPRESSED_FULL;
} else if (!cfg.c_legacy_compress && !ctx->dedupe &&
- inode->z_logical_clusterbits <= 14) {
- if (inode->z_logical_clusterbits <= 12)
+ inode->z_lclusterbits <= 14) {
+ if (inode->z_lclusterbits <= 12)
inode->z_advise |= Z_EROFS_ADVISE_COMPACTED_2B;
inode->datalayout = EROFS_INODE_COMPRESSED_COMPACT;
} else {
@@ -1584,7 +1584,7 @@ void *erofs_begin_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
/* initialize per-file compression setting */
inode->z_advise = 0;
- inode->z_logical_clusterbits = sbi->blkszbits;
+ inode->z_lclusterbits = sbi->blkszbits;
if (cfg.c_fragments && !cfg.c_dedupe)
inode->z_advise |= Z_EROFS_ADVISE_INTERLACED_PCLUSTER;
diff --git a/lib/zmap.c b/lib/zmap.c
index 8383385..99f4088 100644
--- a/lib/zmap.c
+++ b/lib/zmap.c
@@ -51,7 +51,7 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
advise = le16_to_cpu(di->di_advise);
m->type = advise & Z_EROFS_LI_LCLUSTER_TYPE_MASK;
if (m->type == Z_EROFS_LCLUSTER_TYPE_NONHEAD) {
- m->clusterofs = 1 << vi->z_logical_clusterbits;
+ m->clusterofs = 1 << vi->z_lclusterbits;
m->delta[0] = le16_to_cpu(di->di_u.delta[0]);
if (m->delta[0] & Z_EROFS_LI_D0_CBLKCNT) {
if (!(vi->z_advise & (Z_EROFS_ADVISE_BIG_PCLUSTER_1 |
@@ -66,7 +66,7 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
} else {
m->partialref = !!(advise & Z_EROFS_LI_PARTIAL_REF);
m->clusterofs = le16_to_cpu(di->di_clusterofs);
- if (m->clusterofs >= 1 << vi->z_logical_clusterbits) {
+ if (m->clusterofs >= 1 << vi->z_lclusterbits) {
DBG_BUGON(1);
return -EFSCORRUPTED;
}
@@ -115,7 +115,7 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m,
struct erofs_sb_info *sbi = vi->sbi;
const erofs_off_t ebase = sizeof(struct z_erofs_map_header) +
round_up(erofs_iloc(vi) + vi->inode_isize + vi->xattr_isize, 8);
- const unsigned int lclusterbits = vi->z_logical_clusterbits;
+ const unsigned int lclusterbits = vi->z_lclusterbits;
const unsigned int totalidx = BLK_ROUND_UP(sbi, vi->i_size);
unsigned int compacted_4b_initial, compacted_2b, amortizedshift;
unsigned int vcnt, base, lo, lobits, encodebits, nblk, eofs;
@@ -272,7 +272,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
unsigned int lookback_distance)
{
struct erofs_inode *const vi = m->inode;
- const unsigned int lclusterbits = vi->z_logical_clusterbits;
+ const unsigned int lclusterbits = vi->z_lclusterbits;
while (m->lcn >= lookback_distance) {
unsigned long lcn = m->lcn - lookback_distance;
@@ -320,7 +320,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
if ((m->headtype == Z_EROFS_LCLUSTER_TYPE_HEAD1 && !bigpcl1) ||
((m->headtype == Z_EROFS_LCLUSTER_TYPE_PLAIN ||
m->headtype == Z_EROFS_LCLUSTER_TYPE_HEAD2) && !bigpcl2) ||
- (lcn << vi->z_logical_clusterbits) >= vi->i_size)
+ (lcn << vi->z_lclusterbits) >= vi->i_size)
m->compressedblks = 1;
if (m->compressedblks)
@@ -371,7 +371,7 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)
{
struct erofs_inode *const vi = m->inode;
struct erofs_map_blocks *map = m->map;
- unsigned int lclusterbits = vi->z_logical_clusterbits;
+ unsigned int lclusterbits = vi->z_lclusterbits;
u64 lcn = m->lcn, headlcn = map->m_la >> lclusterbits;
int err;
@@ -409,25 +409,33 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)
return 0;
}
-static int z_erofs_do_map_blocks(struct erofs_inode *vi,
+static int z_erofs_map_blocks_fo(struct erofs_inode *vi,
struct erofs_map_blocks *map,
int flags)
{
struct erofs_sb_info *sbi = vi->sbi;
bool fragment = vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
bool ztailpacking = vi->z_idata_size;
+ unsigned int lclusterbits = vi->z_lclusterbits;
struct z_erofs_maprecorder m = {
.inode = vi,
.map = map,
.kaddr = map->mpage,
};
int err = 0;
- unsigned int lclusterbits, endoff, afmt;
+ unsigned int endoff, afmt;
unsigned long initial_lcn;
unsigned long long ofs, end;
- lclusterbits = vi->z_logical_clusterbits;
ofs = flags & EROFS_GET_BLOCKS_FINDTAIL ? vi->i_size - 1 : map->m_la;
+ if (fragment && !(flags & EROFS_GET_BLOCKS_FINDTAIL) &&
+ !vi->z_tailextent_headlcn) {
+ map->m_la = 0;
+ map->m_llen = vi->i_size;
+ map->m_flags = EROFS_MAP_MAPPED |
+ EROFS_MAP_FULL_MAPPED | EROFS_MAP_FRAGMENT;
+ return 0;
+ }
initial_lcn = ofs >> lclusterbits;
endoff = ofs & ((1 << lclusterbits) - 1);
@@ -541,6 +549,130 @@ out:
return err;
}
+static int z_erofs_map_blocks_ext(struct erofs_inode *vi,
+ struct erofs_map_blocks *map, int flags)
+{
+ struct erofs_sb_info *sbi = vi->sbi;
+ bool interlaced = vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER;
+ unsigned int recsz = z_erofs_extent_recsize(vi->z_advise);
+ erofs_off_t pos = round_up(Z_EROFS_MAP_HEADER_END(erofs_iloc(vi) +
+ vi->inode_isize + vi->xattr_isize), recsz);
+ erofs_off_t lend = vi->i_size;
+ erofs_off_t l, r, mid, pa, la, lstart;
+ erofs_blk_t eblk;
+ struct z_erofs_extent *ext;
+ unsigned int fmt;
+ bool last;
+ int err;
+
+ map->m_flags = 0;
+ if (recsz <= offsetof(struct z_erofs_extent, pstart_hi)) {
+ if (recsz <= offsetof(struct z_erofs_extent, pstart_lo)) {
+ eblk = erofs_blknr(sbi, pos);
+ if (map->index != eblk) {
+ err = erofs_blk_read(sbi, 0, map->mpage, eblk, 1);
+ if (err < 0)
+ return err;
+ map->index = eblk;
+ }
+ ext = (void *)(map->mpage + erofs_blkoff(sbi, pos));
+ pa = le64_to_cpu(*(__le64 *)ext);
+ pos += sizeof(__le64);
+ lstart = 0;
+ } else {
+ lstart = map->m_la >> vi->z_lclusterbits;
+ pa = EROFS_NULL_ADDR;
+ }
+
+ for (; lstart <= map->m_la; lstart += 1 << vi->z_lclusterbits) {
+ eblk = erofs_blknr(sbi, pos);
+ if (map->index != eblk) {
+ err = erofs_blk_read(sbi, 0, map->mpage, eblk, 1);
+ if (err < 0)
+ return err;
+ map->index = eblk;
+ }
+ ext = (void *)(map->mpage + erofs_blkoff(sbi, pos));
+ map->m_plen = le32_to_cpu(ext->plen);
+ if (pa != EROFS_NULL_ADDR) {
+ map->m_pa = pa;
+ pa += map->m_plen & Z_EROFS_EXTENT_PLEN_MASK;
+ } else {
+ map->m_pa = le32_to_cpu(ext->pstart_lo);
+ }
+ pos += recsz;
+ }
+ last = (lstart >= round_up(lend, 1 << vi->z_lclusterbits));
+ lend = min(lstart, lend);
+ lstart -= 1 << vi->z_lclusterbits;
+ } else {
+ lstart = lend;
+ for (l = 0, r = vi->z_extents; l < r; ) {
+ mid = l + (r - l) / 2;
+ eblk = erofs_blknr(sbi, pos + mid * recsz);
+ if (map->index != eblk) {
+ err = erofs_blk_read(sbi, 0, map->mpage, eblk, 1);
+ if (err < 0)
+ return err;
+ map->index = eblk;
+ }
+ ext = (void *)(map->mpage + erofs_blkoff(sbi, pos + mid * recsz));
+ la = le32_to_cpu(ext->lstart_lo);
+ pa = le32_to_cpu(ext->pstart_lo) |
+ (u64)le32_to_cpu(ext->pstart_hi) << 32;
+ if (recsz > offsetof(struct z_erofs_extent, lstart_hi))
+ la |= (u64)le32_to_cpu(ext->lstart_hi) << 32;
+
+ if (la > map->m_la) {
+ r = mid;
+ lend = la;
+ } else {
+ l = mid + 1;
+ if (map->m_la == la)
+ r = min(l + 1, r);
+ lstart = la;
+ map->m_plen = le32_to_cpu(ext->plen);
+ map->m_pa = pa;
+ }
+ }
+ last = (l >= vi->z_extents);
+ }
+
+ if (lstart < lend) {
+ map->m_la = lstart;
+ if (last && (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER)) {
+ map->m_flags |= EROFS_MAP_MAPPED | EROFS_MAP_FRAGMENT;
+ vi->z_fragmentoff = map->m_plen;
+ if (recsz > offsetof(struct z_erofs_extent, pstart_lo))
+ vi->z_fragmentoff |= map->m_pa << 32;
+ } else if (map->m_plen) {
+ map->m_flags |= EROFS_MAP_MAPPED |
+ EROFS_MAP_FULL_MAPPED | EROFS_MAP_ENCODED;
+ fmt = map->m_plen >> Z_EROFS_EXTENT_PLEN_FMT_BIT;
+ if (fmt)
+ map->m_algorithmformat = fmt - 1;
+ else if (interlaced && !erofs_blkoff(sbi, map->m_pa))
+ map->m_algorithmformat =
+ Z_EROFS_COMPRESSION_INTERLACED;
+ else
+ map->m_algorithmformat =
+ Z_EROFS_COMPRESSION_SHIFTED;
+ if (map->m_plen & Z_EROFS_EXTENT_PLEN_PARTIAL)
+ map->m_flags |= EROFS_MAP_PARTIAL_REF;
+ map->m_plen &= Z_EROFS_EXTENT_PLEN_MASK;
+ }
+ }
+ map->m_llen = lend - map->m_la;
+ if (!last && map->m_llen < erofs_blksiz(sbi)) {
+ erofs_err("extent too small %llu @ offset %llu of nid %llu",
+ map->m_llen, map->m_la, vi->nid);
+ DBG_BUGON(1);
+ return -EFSCORRUPTED;
+ }
+ return 0;
+}
+
+
static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
{
erofs_off_t pos;
@@ -566,10 +698,17 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
vi->z_advise = Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
vi->fragmentoff = le64_to_cpu(*(__le64 *)h) ^ (1ULL << 63);
vi->z_tailextent_headlcn = 0;
- goto out;
+ goto done;
}
vi->z_advise = le16_to_cpu(h->h_advise);
+ vi->z_lclusterbits = sbi->blkszbits + (h->h_clusterbits & 15);
+ if (vi->datalayout == EROFS_INODE_COMPRESSED_FULL &&
+ (vi->z_advise & Z_EROFS_ADVISE_EXTENTS)) {
+ vi->z_extents = le32_to_cpu(h->h_extents_lo) |
+ ((u64)le16_to_cpu(h->h_extents_hi) << 32);
+ goto done;
+ }
vi->z_algorithmtype[0] = h->h_algorithmtype & 15;
vi->z_algorithmtype[1] = h->h_algorithmtype >> 4;
if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER)
@@ -585,7 +724,6 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
return -EOPNOTSUPP;
}
- vi->z_logical_clusterbits = sbi->blkszbits + (h->h_clusterbits & 7);
if (vi->datalayout == EROFS_INODE_COMPRESSED_COMPACT &&
!(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1) ^
!(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_2)) {
@@ -598,12 +736,12 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
(vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER)) {
struct erofs_map_blocks map = { .index = UINT_MAX };
- err = z_erofs_do_map_blocks(vi, &map,
+ err = z_erofs_map_blocks_fo(vi, &map,
EROFS_GET_BLOCKS_FINDTAIL);
if (err < 0)
return err;
}
-out:
+done:
erofs_atomic_set_bit(EROFS_I_Z_INITED_BIT, &vi->flags);
return 0;
}
@@ -620,15 +758,11 @@ int z_erofs_map_blocks_iter(struct erofs_inode *vi,
} else {
err = z_erofs_fill_inode_lazy(vi);
if (!err) {
- if ((vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) &&
- !vi->z_tailextent_headlcn) {
- map->m_la = 0;
- map->m_llen = vi->i_size;
- map->m_flags = EROFS_MAP_MAPPED |
- EROFS_MAP_FULL_MAPPED | EROFS_MAP_FRAGMENT;
- } else {
- err = z_erofs_do_map_blocks(vi, map, flags);
- }
+ if (vi->datalayout == EROFS_INODE_COMPRESSED_FULL &&
+ (vi->z_advise & Z_EROFS_ADVISE_EXTENTS))
+ err = z_erofs_map_blocks_ext(vi, map, flags);
+ else
+ err = z_erofs_map_blocks_fo(vi, map, flags);
}
if (!err && (map->m_flags & EROFS_MAP_ENCODED) &&
__erofs_unlikely(map->m_plen > Z_EROFS_PCLUSTER_MAX_SIZE ||
--
2.43.5
More information about the Linux-erofs
mailing list