Skip to content

Commit 1d191b4

Browse files
committed
erofs: implement encoded extent metadata
Implement the extent metadata parsing described in the previous commit. For 16-byte and 32-byte extent records, currently it is just a trivial binary search without considering the last access footprint, but it can be optimized for better sequential performance later. Tail fragments are supported, but ztailpacking feature is not for simplicity. Signed-off-by: Gao Xiang <[email protected]> Acked-by: Chao Yu <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent efb2aef commit 1d191b4

File tree

2 files changed

+135
-12
lines changed

2 files changed

+135
-12
lines changed

fs/erofs/internal.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,10 @@ struct erofs_inode {
263263
unsigned short z_advise;
264264
unsigned char z_algorithmtype[2];
265265
unsigned char z_lclusterbits;
266-
unsigned long z_tailextent_headlcn;
266+
union {
267+
u64 z_tailextent_headlcn;
268+
u64 z_extents;
269+
};
267270
erofs_off_t z_fragmentoff;
268271
unsigned short z_idata_size;
269272
};

fs/erofs/zmap.c

Lines changed: 131 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)
391391
return 0;
392392
}
393393

394-
static int z_erofs_do_map_blocks(struct inode *inode,
394+
static int z_erofs_map_blocks_fo(struct inode *inode,
395395
struct erofs_map_blocks *map, int flags)
396396
{
397397
struct erofs_inode *vi = EROFS_I(inode);
@@ -409,6 +409,14 @@ static int z_erofs_do_map_blocks(struct inode *inode,
409409
unsigned long long ofs, end;
410410

411411
ofs = flags & EROFS_GET_BLOCKS_FINDTAIL ? inode->i_size - 1 : map->m_la;
412+
if (fragment && !(flags & EROFS_GET_BLOCKS_FINDTAIL) &&
413+
!vi->z_tailextent_headlcn) {
414+
map->m_la = 0;
415+
map->m_llen = inode->i_size;
416+
map->m_flags = EROFS_MAP_MAPPED |
417+
EROFS_MAP_FULL_MAPPED | EROFS_MAP_FRAGMENT;
418+
return 0;
419+
}
412420
initial_lcn = ofs >> lclusterbits;
413421
endoff = ofs & ((1 << lclusterbits) - 1);
414422

@@ -526,6 +534,115 @@ static int z_erofs_do_map_blocks(struct inode *inode,
526534
return err;
527535
}
528536

537+
static int z_erofs_map_blocks_ext(struct inode *inode,
538+
struct erofs_map_blocks *map, int flags)
539+
{
540+
struct erofs_inode *vi = EROFS_I(inode);
541+
struct super_block *sb = inode->i_sb;
542+
bool interlaced = vi->z_advise & Z_EROFS_ADVISE_INTERLACED_PCLUSTER;
543+
unsigned int recsz = z_erofs_extent_recsize(vi->z_advise);
544+
erofs_off_t pos = round_up(Z_EROFS_MAP_HEADER_END(erofs_iloc(inode) +
545+
vi->inode_isize + vi->xattr_isize), recsz);
546+
erofs_off_t lend = inode->i_size;
547+
erofs_off_t l, r, mid, pa, la, lstart;
548+
struct z_erofs_extent *ext;
549+
unsigned int fmt;
550+
bool last;
551+
552+
map->m_flags = 0;
553+
if (recsz <= offsetof(struct z_erofs_extent, pstart_hi)) {
554+
if (recsz <= offsetof(struct z_erofs_extent, pstart_lo)) {
555+
ext = erofs_read_metabuf(&map->buf, sb, pos, true);
556+
if (IS_ERR(ext))
557+
return PTR_ERR(ext);
558+
pa = le64_to_cpu(*(__le64 *)ext);
559+
pos += sizeof(__le64);
560+
lstart = 0;
561+
} else {
562+
lstart = map->m_la >> vi->z_lclusterbits;
563+
pa = EROFS_NULL_ADDR;
564+
}
565+
566+
for (; lstart <= map->m_la; lstart += 1 << vi->z_lclusterbits) {
567+
ext = erofs_read_metabuf(&map->buf, sb, pos, true);
568+
if (IS_ERR(ext))
569+
return PTR_ERR(ext);
570+
map->m_plen = le32_to_cpu(ext->plen);
571+
if (pa != EROFS_NULL_ADDR) {
572+
map->m_pa = pa;
573+
pa += map->m_plen & Z_EROFS_EXTENT_PLEN_MASK;
574+
} else {
575+
map->m_pa = le32_to_cpu(ext->pstart_lo);
576+
}
577+
pos += recsz;
578+
}
579+
last = (lstart >= round_up(lend, 1 << vi->z_lclusterbits));
580+
lend = min(lstart, lend);
581+
lstart -= 1 << vi->z_lclusterbits;
582+
} else {
583+
lstart = lend;
584+
for (l = 0, r = vi->z_extents; l < r; ) {
585+
mid = l + (r - l) / 2;
586+
ext = erofs_read_metabuf(&map->buf, sb,
587+
pos + mid * recsz, true);
588+
if (IS_ERR(ext))
589+
return PTR_ERR(ext);
590+
591+
la = le32_to_cpu(ext->lstart_lo);
592+
pa = le32_to_cpu(ext->pstart_lo) |
593+
(u64)le32_to_cpu(ext->pstart_hi) << 32;
594+
if (recsz > offsetof(struct z_erofs_extent, lstart_hi))
595+
la |= (u64)le32_to_cpu(ext->lstart_hi) << 32;
596+
597+
if (la > map->m_la) {
598+
r = mid;
599+
lend = la;
600+
} else {
601+
l = mid + 1;
602+
if (map->m_la == la)
603+
r = min(l + 1, r);
604+
lstart = la;
605+
map->m_plen = le32_to_cpu(ext->plen);
606+
map->m_pa = pa;
607+
}
608+
}
609+
last = (l >= vi->z_extents);
610+
}
611+
612+
if (lstart < lend) {
613+
map->m_la = lstart;
614+
if (last && (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER)) {
615+
map->m_flags |= EROFS_MAP_MAPPED | EROFS_MAP_FRAGMENT;
616+
vi->z_fragmentoff = map->m_plen;
617+
if (recsz >= offsetof(struct z_erofs_extent, pstart_lo))
618+
vi->z_fragmentoff |= map->m_pa << 32;
619+
} else if (map->m_plen) {
620+
map->m_flags |= EROFS_MAP_MAPPED |
621+
EROFS_MAP_FULL_MAPPED | EROFS_MAP_ENCODED;
622+
fmt = map->m_plen >> Z_EROFS_EXTENT_PLEN_FMT_BIT;
623+
if (fmt)
624+
map->m_algorithmformat = fmt - 1;
625+
else if (interlaced && !erofs_blkoff(sb, map->m_pa))
626+
map->m_algorithmformat =
627+
Z_EROFS_COMPRESSION_INTERLACED;
628+
else
629+
map->m_algorithmformat =
630+
Z_EROFS_COMPRESSION_SHIFTED;
631+
if (map->m_plen & Z_EROFS_EXTENT_PLEN_PARTIAL)
632+
map->m_flags |= EROFS_MAP_PARTIAL_REF;
633+
map->m_plen &= Z_EROFS_EXTENT_PLEN_MASK;
634+
}
635+
}
636+
map->m_llen = lend - map->m_la;
637+
if (!last && map->m_llen < sb->s_blocksize) {
638+
erofs_err(sb, "extent too small %llu @ offset %llu of nid %llu",
639+
map->m_llen, map->m_la, vi->nid);
640+
DBG_BUGON(1);
641+
return -EFSCORRUPTED;
642+
}
643+
return 0;
644+
}
645+
529646
static int z_erofs_fill_inode_lazy(struct inode *inode)
530647
{
531648
struct erofs_inode *const vi = EROFS_I(inode);
@@ -570,6 +687,13 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
570687
}
571688
vi->z_advise = le16_to_cpu(h->h_advise);
572689
vi->z_lclusterbits = sb->s_blocksize_bits + (h->h_clusterbits & 15);
690+
if (vi->datalayout == EROFS_INODE_COMPRESSED_FULL &&
691+
(vi->z_advise & Z_EROFS_ADVISE_EXTENTS)) {
692+
vi->z_extents = le32_to_cpu(h->h_extents_lo) |
693+
((u64)le16_to_cpu(h->h_extents_hi) << 32);
694+
goto done;
695+
}
696+
573697
vi->z_algorithmtype[0] = h->h_algorithmtype & 15;
574698
vi->z_algorithmtype[1] = h->h_algorithmtype >> 4;
575699
if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER)
@@ -609,7 +733,7 @@ static int z_erofs_fill_inode_lazy(struct inode *inode)
609733
.buf = __EROFS_BUF_INITIALIZER
610734
};
611735

612-
err = z_erofs_do_map_blocks(inode, &map,
736+
err = z_erofs_map_blocks_fo(inode, &map,
613737
EROFS_GET_BLOCKS_FINDTAIL);
614738
erofs_put_metabuf(&map.buf);
615739
if (err < 0)
@@ -640,15 +764,11 @@ int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map,
640764
} else {
641765
err = z_erofs_fill_inode_lazy(inode);
642766
if (!err) {
643-
if ((vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) &&
644-
!vi->z_tailextent_headlcn) {
645-
map->m_la = 0;
646-
map->m_llen = inode->i_size;
647-
map->m_flags = EROFS_MAP_MAPPED |
648-
EROFS_MAP_FULL_MAPPED | EROFS_MAP_FRAGMENT;
649-
} else {
650-
err = z_erofs_do_map_blocks(inode, map, flags);
651-
}
767+
if (vi->datalayout == EROFS_INODE_COMPRESSED_FULL &&
768+
(vi->z_advise & Z_EROFS_ADVISE_EXTENTS))
769+
err = z_erofs_map_blocks_ext(inode, map, flags);
770+
else
771+
err = z_erofs_map_blocks_fo(inode, map, flags);
652772
}
653773
if (!err && (map->m_flags & EROFS_MAP_ENCODED) &&
654774
unlikely(map->m_plen > Z_EROFS_PCLUSTER_MAX_SIZE ||

0 commit comments

Comments
 (0)