FAILED: patch "[PATCH] erofs: fix large fragment handling" failed to apply to 6.12-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x b44686c8391b427fb1c85a31c35077e6947c6d90
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025071422-preview-germinate-b2de@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From b44686c8391b427fb1c85a31c35077e6947c6d90 Mon Sep 17 00:00:00 2001
From: Gao Xiang <[email protected]>
Date: Sat, 12 Jul 2025 03:58:26 +0800
Subject: [PATCH] erofs: fix large fragment handling
Fragments aren't limited by Z_EROFS_PCLUSTER_MAX_DSIZE. However, if a fragment's logical length is larger than Z_EROFS_PCLUSTER_MAX_DSIZE but the fragment is not the whole inode, it currently returns -EOPNOTSUPP because m_flags has the wrong EROFS_MAP_ENCODED flag set. It is not intended by design but should be rare, as it can only be reproduced by mkfs with -Eall-fragments in a specific case.
Let's normalize fragment m_flags using the new EROFS_MAP_FRAGMENT.
fs/erofs/internal.h +3 -1
@@ -315,10 +315,12 @@ static inline struct folio *erofs_grab_folio_nowait(struct address_space *as,/* The length of extent is full */ #define EROFS_MAP_FULL_MAPPED 0x0008/* Located in the special packed inode */ -#define EROFS_MAP_FRAGMENT 0x0010 +#define __EROFS_MAP_FRAGMENT 0x0010/* The extent refers to partial decompressed data */ #define EROFS_MAP_PARTIAL_REF 0x0020 +#define EROFS_MAP_FRAGMENT (EROFS_MAP_MAPPED | __EROFS_MAP_FRAGMENT) +struct erofs_map_blocks {struct erofs_buf buf;
fs/erofs/zdata.c +1 -1
@@ -1034,7 +1034,7 @@ static int z_erofs_scan_folio(struct z_erofs_frontend *f,if (!(map->m_flags &EROFS_MAP_MAPPED )) {folio_zero_segment (folio, cur, end); tight = false; - }else if (map->m_flags &EROFS_MAP_FRAGMENT ) { + }else if (map->m_flags & __EROFS_MAP_FRAGMENT) {erofs_off_t fpos = offset + cur - map->m_la; err = z_erofs_read_fragment(inode->i_sb, folio, cur,
fs/erofs/zmap.c +4 -5
@@ -413,8 +413,7 @@ static int z_erofs_map_blocks_fo(struct inode *inode, !vi->z_tailextent_headlcn) { map->m_la =0 ; map->m_llen = inode->i_size; - map->m_flags =EROFS_MAP_MAPPED | -EROFS_MAP_FULL_MAPPED |EROFS_MAP_FRAGMENT ; + map->m_flags =EROFS_MAP_FRAGMENT ;return 0 ; } initial_lcn = ofs >> lclusterbits;
@@ -489,7 +488,7 @@ static int z_erofs_map_blocks_fo(struct inode *inode, goto unmap_out; } }else if (fragment && m.lcn == vi->z_tailextent_headlcn) { - map->m_flags |=EROFS_MAP_FRAGMENT ; + map->m_flags =EROFS_MAP_FRAGMENT ; }else { map->m_pa =erofs_pos (sb, m.pblk); err =z_erofs_get_extent_compressedlen (&m, initial_lcn);
@@ -617,7 +616,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,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 ; + map->m_flags =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 ;
@@ -797,7 +796,7 @@ static int z_erofs_iomap_begin_report(struct inode *inode, loff_t offset, iomap->length = map.m_llen;if (map.m_flags &EROFS_MAP_MAPPED ) { iomap->type =IOMAP_MAPPED ; - iomap->addr = map.m_flags &EROFS_MAP_FRAGMENT ? + iomap->addr = map.m_flags & __EROFS_MAP_FRAGMENT ?IOMAP_NULL_ADDR : map.m_pa; }else { iomap->type =IOMAP_HOLE ;
Sasha Levin
maintainerPATCH 1/6 erofs: simplify z_erofs_load_compact_lcluster()
From: Gao Xiang <[email protected]>
[ Upstream commit 2a810ea79cd7a6d5f134ea69ca2ba726e600cbc4 ]
- Get rid of unpack_compacted_index() and fold it into z_erofs_load_compact_lcluster();
- Avoid a goto.
Stable-dep-of: b44686c8391b ("erofs: fix large fragment handling")
--- fs/erofs/zmap.c | 89 ++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 53 deletions(-)
fs/erofs/zmap.c +36 -53
@@ -97,17 +97,48 @@ static int get_compacted_la_distance(unsigned int lobits,return d1; } -static int unpack_compacted_index (struct z_erofs_maprecorder *m, -unsigned int amortizedshift, -erofs_off_t pos,bool lookahead) +static int z_erofs_load_compact_lcluster (struct z_erofs_maprecorder *m, +unsigned long lcn,bool lookahead) { -struct erofs_inode *const vi =EROFS_I (m->inode); +struct inode *const inode = m->inode; +struct erofs_inode *const vi =EROFS_I (inode); +const erofs_off_t ebase =sizeof (struct z_erofs_map_header ) + +ALIGN (erofs_iloc (inode) + vi->inode_isize + vi->xattr_isize,8 );const unsigned int lclusterbits = vi->z_logical_clusterbits; +const unsigned int totalidx =erofs_iblks (inode); +unsigned int compacted_4b_initial, compacted_2b, amortizedshift;unsigned int vcnt, lo, lobits, encodebits, nblk, bytes; -bool big_pcluster; +bool big_pcluster = vi->z_advise &Z_EROFS_ADVISE_BIG_PCLUSTER_1 ; +erofs_off_t pos;u8 *in, type;int i; +if (lcn >= totalidx || lclusterbits >14 ) +return -EINVAL ; + + m->lcn = lcn; +/* used to align to 32-byte (compacted_2b) alignment */ + compacted_4b_initial = ((32 - ebase %32 ) /4 ) &7 ; + compacted_2b =0 ; +if ((vi->z_advise &Z_EROFS_ADVISE_COMPACTED_2B ) && + compacted_4b_initial < totalidx) + compacted_2b =rounddown (totalidx - compacted_4b_initial,16 ); + + pos = ebase; + amortizedshift =2 ;/* compact_4b */ +if (lcn >= compacted_4b_initial) { + pos += compacted_4b_initial *4 ; + lcn -= compacted_4b_initial; +if (lcn < compacted_2b) { + amortizedshift =1 ; + }else { + pos += compacted_2b *2 ; + lcn -= compacted_2b; + } + } + pos += lcn * (1 << amortizedshift); + +/* figure out the lcluster count in this pack */ if (1 << amortizedshift ==4 && lclusterbits <=14 ) vcnt =2 ;else if (1 << amortizedshift ==2 && lclusterbits <=12 )
@@ -122,7 +153,6 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,/* it doesn't equal to round_up(..) */ m->nextpackoff =round_down (pos, vcnt << amortizedshift) + (vcnt << amortizedshift); - big_pcluster = vi->z_advise &Z_EROFS_ADVISE_BIG_PCLUSTER_1 ; lobits =max (lclusterbits,ilog2 (Z_EROFS_LI_D0_CBLKCNT ) +1U ); encodebits = ((vcnt << amortizedshift) -sizeof (__le32)) *8 / vcnt; bytes = pos & ((vcnt << amortizedshift) -1 );
@@ -207,53 +237,6 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,return 0 ; } -static int z_erofs_load_compact_lcluster (struct z_erofs_maprecorder *m, -unsigned long lcn,bool lookahead) -{ -struct inode *const inode = m->inode; -struct erofs_inode *const vi =EROFS_I (inode); -const erofs_off_t ebase =sizeof (struct z_erofs_map_header ) + -ALIGN (erofs_iloc (inode) + vi->inode_isize + vi->xattr_isize,8 ); -unsigned int totalidx =erofs_iblks (inode); -unsigned int compacted_4b_initial, compacted_2b; -unsigned int amortizedshift; -erofs_off_t pos; - -if (lcn >= totalidx || vi->z_logical_clusterbits >14 ) -return -EINVAL ; - - m->lcn = lcn; -/* used to align to 32-byte (compacted_2b) alignment */ - compacted_4b_initial = (32 - ebase %32 ) /4 ; -if (compacted_4b_initial ==32 /4 ) - compacted_4b_initial =0 ; - -if ((vi->z_advise &Z_EROFS_ADVISE_COMPACTED_2B ) && - compacted_4b_initial < totalidx) - compacted_2b =rounddown (totalidx - compacted_4b_initial,16 ); -else - compacted_2b =0 ; - - pos = ebase; -if (lcn < compacted_4b_initial) { - amortizedshift =2 ; - goto out; - } - pos += compacted_4b_initial *4 ; - lcn -= compacted_4b_initial; - -if (lcn < compacted_2b) { - amortizedshift =1 ; - goto out; - } - pos += compacted_2b *2 ; - lcn -= compacted_2b; - amortizedshift =2 ; -out: - pos += lcn * (1 << amortizedshift); -return unpack_compacted_index (m, amortizedshift, pos, lookahead); -} -static int z_erofs_load_lcluster_from_disk (struct z_erofs_maprecorder *m,unsigned int lcn,bool lookahead) {
Signature · 1 line
2.39.5
Sasha Levin
maintainerPATCH 2/6 erofs: refine z_erofs_get_extent_compressedlen()
From: Gao Xiang <[email protected]>
[ Upstream commit 8f9530aeeb4f756bdfa70510b40e5d28ea3c742e ]
- Set compressedblks = 1 directly for non-bigpcluster cases. This simplifies the logic a bit since lcluster sizes larger than one block are unsupported and the details remain unclear.
- For Z_EROFS_LCLUSTER_TYPE_PLAIN pclusters, avoid assuming compressedblks = 1 by default. Instead, check if Z_EROFS_ADVISE_BIG_PCLUSTER_2 is set.
It basically has no impact to existing valid images, but it's useful to find the gap to prepare for large PLAIN pclusters.
Stable-dep-of: b44686c8391b ("erofs: fix large fragment handling")
--- fs/erofs/zmap.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-)
fs/erofs/zmap.c +16 -20
@@ -294,27 +294,23 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,static int z_erofs_get_extent_compressedlen (struct z_erofs_maprecorder *m,unsigned int initial_lcn) { -struct super_block *sb = m->inode->i_sb; -struct erofs_inode *const vi =EROFS_I (m->inode); -struct erofs_map_blocks *const map = m->map; -const unsigned int lclusterbits = vi->z_logical_clusterbits; -unsigned long lcn; +struct inode *inode = m->inode; +struct super_block *sb = inode->i_sb; +struct erofs_inode *vi =EROFS_I (inode); +bool bigpcl1 = vi->z_advise &Z_EROFS_ADVISE_BIG_PCLUSTER_1 ; +bool bigpcl2 = vi->z_advise &Z_EROFS_ADVISE_BIG_PCLUSTER_2 ; +unsigned long lcn = m->lcn +1 ;int err; -DBG_BUGON (m->type !=Z_EROFS_LCLUSTER_TYPE_PLAIN && - m->type !=Z_EROFS_LCLUSTER_TYPE_HEAD1 && - m->type !=Z_EROFS_LCLUSTER_TYPE_HEAD2 ); +DBG_BUGON (m->type ==Z_EROFS_LCLUSTER_TYPE_NONHEAD );DBG_BUGON (m->type != m->headtype); -if (m->headtype ==Z_EROFS_LCLUSTER_TYPE_PLAIN || - ((m->headtype ==Z_EROFS_LCLUSTER_TYPE_HEAD1 ) && - !(vi->z_advise &Z_EROFS_ADVISE_BIG_PCLUSTER_1 )) || - ((m->headtype ==Z_EROFS_LCLUSTER_TYPE_HEAD2 ) && - !(vi->z_advise &Z_EROFS_ADVISE_BIG_PCLUSTER_2 ))) { - map->m_plen =1ULL << lclusterbits; -return 0 ; - } - lcn = m->lcn +1 ; +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) >= inode->i_size) + m->compressedblks =1 ; +if (m->compressedblks) goto out;
@@ -339,9 +335,9 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,case Z_EROFS_LCLUSTER_TYPE_HEAD2 :/* * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type -* rather than CBLKCNT, it's a 1 lcluster-sized pcluster. +* rather than CBLKCNT, it's a 1 block-sized pcluster. */ - m->compressedblks =1 << (lclusterbits - sb->s_blocksize_bits); + m->compressedblks =1 ;break ;case Z_EROFS_LCLUSTER_TYPE_NONHEAD :if (m->delta[0 ] !=1 )
@@ -356,7 +352,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,return -EFSCORRUPTED ; } out: - map->m_plen =erofs_pos (sb, m->compressedblks); + m->map->m_plen =erofs_pos (sb, m->compressedblks);return 0 ; err_bonus_cblkcnt:erofs_err (sb,"bogus CBLKCNT @ lcn %lu of nid %llu" , lcn, vi->nid);
Signature · 1 line
2.39.5
Sasha Levin
maintainerPATCH 3/6 erofs: use Z_EROFS_LCLUSTER_TYPE_MAX to simplify switches
In reply to Sasha LevinFrom: Hongzhen Luo <[email protected]>
[ Upstream commit 3b7781aeaefb627d4e07c1af9be923f9e8047d8b ]
There's no need to enumerate each type. No logic changes.
Stable-dep-of: b44686c8391b ("erofs: fix large fragment handling")
--- fs/erofs/zmap.c | 63 +++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 39 deletions(-)
fs/erofs/zmap.c +24 -39
@@ -265,26 +265,22 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,if (err)return err; -switch (m->type) { -case Z_EROFS_LCLUSTER_TYPE_NONHEAD : +if (m->type >=Z_EROFS_LCLUSTER_TYPE_MAX ) { +erofs_err (sb,"unknown type %u @ lcn %lu of nid %llu" , + m->type, lcn, vi->nid); +DBG_BUGON (1 ); +return -EOPNOTSUPP ; + }else if (m->type ==Z_EROFS_LCLUSTER_TYPE_NONHEAD ) { lookback_distance = m->delta[0 ];if (!lookback_distance) - goto err_bogus; +break ;continue ; -case Z_EROFS_LCLUSTER_TYPE_PLAIN : -case Z_EROFS_LCLUSTER_TYPE_HEAD1 : -case Z_EROFS_LCLUSTER_TYPE_HEAD2 : + }else { m->headtype = m->type; m->map->m_la = (lcn << lclusterbits) | m->clusterofs;return 0 ; -default : -erofs_err (sb,"unknown type %u @ lcn %lu of nid %llu" , - m->type, lcn, vi->nid); -DBG_BUGON (1 ); -return -EOPNOTSUPP ; } } -err_bogus:erofs_err (sb,"bogus lookback distance %u @ lcn %lu of nid %llu" , lookback_distance, m->lcn, vi->nid);DBG_BUGON (1 );
@@ -329,35 +325,28 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,DBG_BUGON (lcn == initial_lcn && m->type ==Z_EROFS_LCLUSTER_TYPE_NONHEAD ); -switch (m->type) { -case Z_EROFS_LCLUSTER_TYPE_PLAIN : -case Z_EROFS_LCLUSTER_TYPE_HEAD1 : -case Z_EROFS_LCLUSTER_TYPE_HEAD2 : +if (m->type ==Z_EROFS_LCLUSTER_TYPE_NONHEAD ) { +if (m->delta[0 ] !=1 ) { +erofs_err (sb,"bogus CBLKCNT @ lcn %lu of nid %llu" , lcn, vi->nid); +DBG_BUGON (1 ); +return -EFSCORRUPTED ; + } +if (m->compressedblks) + goto out; + }else if (m->type <Z_EROFS_LCLUSTER_TYPE_MAX ) {/* * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type * rather than CBLKCNT, it's a 1 block-sized pcluster. */ m->compressedblks =1 ; -break ; -case Z_EROFS_LCLUSTER_TYPE_NONHEAD : -if (m->delta[0 ] !=1 ) - goto err_bonus_cblkcnt; -if (m->compressedblks) -break ; - fallthrough; -default : -erofs_err (sb,"cannot found CBLKCNT @ lcn %lu of nid %llu" , lcn, - vi->nid); -DBG_BUGON (1 ); -return -EFSCORRUPTED ; + goto out; } +erofs_err (sb,"cannot found CBLKCNT @ lcn %lu of nid %llu" , lcn, vi->nid); +DBG_BUGON (1 ); +return -EFSCORRUPTED ; out: m->map->m_plen =erofs_pos (sb, m->compressedblks);return 0 ; -err_bonus_cblkcnt: -erofs_err (sb,"bogus CBLKCNT @ lcn %lu of nid %llu" , lcn, vi->nid); -DBG_BUGON (1 ); -return -EFSCORRUPTED ; }static int z_erofs_get_extent_decompressedlen (struct z_erofs_maprecorder *m)
@@ -386,9 +375,7 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m) m->delta[1 ] =1 ;DBG_BUGON (1 ); } - }else if (m->type ==Z_EROFS_LCLUSTER_TYPE_PLAIN || - m->type ==Z_EROFS_LCLUSTER_TYPE_HEAD1 || - m->type ==Z_EROFS_LCLUSTER_TYPE_HEAD2 ) { + }else if (m->type <Z_EROFS_LCLUSTER_TYPE_MAX ) {if (lcn != headlcn)break ;/* ends at the next HEAD lcluster */ m->delta[1 ] =1 ;
@@ -452,8 +439,7 @@ static int z_erofs_do_map_blocks(struct inode *inode, }/* m.lcn should be >= 1 if endoff < m.clusterofs */ if (!m.lcn) { -erofs_err (inode->i_sb, -"invalid logical cluster 0 at nid %llu" , +erofs_err (inode->i_sb,"invalid logical cluster 0 at nid %llu" , vi->nid); err = -EFSCORRUPTED ; goto unmap_out;
@@ -469,8 +455,7 @@ static int z_erofs_do_map_blocks(struct inode *inode, goto unmap_out;break ;default : -erofs_err (inode->i_sb, -"unknown type %u @ offset %llu of nid %llu" , +erofs_err (inode->i_sb,"unknown type %u @ offset %llu of nid %llu" , m.type, ofs, vi->nid); err = -EOPNOTSUPP ; goto unmap_out;
Signature · 1 line
2.39.5
Sasha Levin
maintainerPATCH 4/6 erofs: simplify tail inline pcluster handling
In reply to Sasha LevinFrom: Gao Xiang <[email protected]>
[ Upstream commit b7710262d743aca112877d12abed61ce8a5d0d98 ]
Use z_idata_size != 0 to indicate that ztailpacking is enabled. Z_EROFS_ADVISE_INLINE_PCLUSTER cannot be ignored, as h_idata_size could be non-zero prior to erofs-utils 1.6 [1].
Additionally, merge z_idataoff and z_fragmentoff since these two features are mutually exclusive for a given inode.
[1] https://git.kernel.org/xiang/erofs-utils/c/547bea3cb71a
Stable-dep-of: b44686c8391b ("erofs: fix large fragment handling")
--- fs/erofs/internal.h | 9 ++------- fs/erofs/zmap.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 17 deletions(-)
fs/erofs/internal.h +2 -7
@@ -277,13 +277,8 @@ struct erofs_inode {unsigned char z_algorithmtype[2 ];unsigned char z_logical_clusterbits;unsigned long z_tailextent_headlcn; -union { -struct { -erofs_off_t z_idataoff; -unsigned short z_idata_size; - }; -erofs_off_t z_fragmentoff; - }; +erofs_off_t z_fragmentoff; + unsigned short z_idata_size; };#endif /* CONFIG_EROFS_FS_ZIP */ };
fs/erofs/zmap.c +10 -10
@@ -395,8 +395,8 @@ static int z_erofs_do_map_blocks(struct inode *inode, struct erofs_map_blocks *map, int flags) {struct erofs_inode *const vi =EROFS_I (inode); -bool ztailpacking = vi->z_advise &Z_EROFS_ADVISE_INLINE_PCLUSTER ;bool fragment = vi->z_advise &Z_EROFS_ADVISE_FRAGMENT_PCLUSTER ; +bool ztailpacking = vi->z_idata_size;struct z_erofs_maprecorder m = { .inode = inode, .map = map,
@@ -415,9 +415,8 @@ static int z_erofs_do_map_blocks(struct inode *inode,if (err) goto unmap_out; -if (ztailpacking && (flags &EROFS_GET_BLOCKS_FINDTAIL )) - vi->z_idataoff = m.nextpackoff; - +if ((flags &EROFS_GET_BLOCKS_FINDTAIL ) && ztailpacking) + vi->z_fragmentoff = m.nextpackoff; map->m_flags =EROFS_MAP_MAPPED |EROFS_MAP_ENCODED ; end = (m.lcn +1ULL ) << lclusterbits;
@@ -472,7 +471,7 @@ static int z_erofs_do_map_blocks(struct inode *inode, }if (ztailpacking && m.lcn == vi->z_tailextent_headlcn) { map->m_flags |=EROFS_MAP_META ; - map->m_pa = vi->z_idataoff; + map->m_pa = vi->z_fragmentoff; map->m_plen = vi->z_idata_size; }else if (fragment && m.lcn == vi->z_tailextent_headlcn) { map->m_flags |=EROFS_MAP_FRAGMENT ;
@@ -565,6 +564,10 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) vi->z_advise =le16_to_cpu (h->h_advise); 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 ) + vi->z_fragmentoff =le32_to_cpu (h->h_fragmentoff); +else if (vi->z_advise &Z_EROFS_ADVISE_INLINE_PCLUSTER ) + vi->z_idata_size =le16_to_cpu (h->h_idata_size); headnr =0 ; if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX ||
@@ -593,18 +596,16 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) goto out_put_metabuf; } -if (vi->z_advise &Z_EROFS_ADVISE_INLINE_PCLUSTER ) { +if (vi->z_idata_size) {struct erofs_map_blocks map = { .buf = __EROFS_BUF_INITIALIZER }; - vi->z_idata_size =le16_to_cpu (h->h_idata_size); err =z_erofs_do_map_blocks (inode, &map,EROFS_GET_BLOCKS_FINDTAIL );erofs_put_metabuf (&map.buf); -if (!map.m_plen || -erofs_blkoff (sb, map.m_pa) + map.m_plen > sb->s_blocksize) { +if (erofs_blkoff (sb, map.m_pa) + map.m_plen > sb->s_blocksize) {erofs_err (sb,"invalid tail-packing pclustersize %llu" , map.m_plen); err = -EFSCORRUPTED ;
@@ -619,7 +620,6 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) .buf = __EROFS_BUF_INITIALIZER }; - vi->z_fragmentoff =le32_to_cpu (h->h_fragmentoff); err =z_erofs_do_map_blocks (inode, &map,EROFS_GET_BLOCKS_FINDTAIL );erofs_put_metabuf (&map.buf);
Signature · 1 line
2.39.5
Sasha Levin
maintainerPATCH 5/6 erofs: clean up header parsing for ztailpacking and fragments
In reply to Sasha LevinFrom: Gao Xiang <[email protected]>
[ Upstream commit 540787d38b10dbc16a7d2bc2845752ab1605403a ]
Simplify the logic in z_erofs_fill_inode_lazy() by combining the handling of ztailpacking and fragments, as they are mutually exclusive.
Note that h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT is handled above, so no need to duplicate the check.
Stable-dep-of: b44686c8391b ("erofs: fix large fragment handling")
--- fs/erofs/zmap.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-)
fs/erofs/zmap.c +14 -25
@@ -394,7 +394,8 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)static int z_erofs_do_map_blocks (struct inode *inode,struct erofs_map_blocks *map,int flags) { -struct erofs_inode *const vi =EROFS_I (inode); +struct erofs_inode *vi =EROFS_I (inode); +struct super_block *sb = inode->i_sb;bool fragment = vi->z_advise &Z_EROFS_ADVISE_FRAGMENT_PCLUSTER ;bool ztailpacking = vi->z_idata_size;struct z_erofs_maprecorder m = {
@@ -438,7 +439,7 @@ static int z_erofs_do_map_blocks(struct inode *inode, }/* m.lcn should be >= 1 if endoff < m.clusterofs */ if (!m.lcn) { -erofs_err (inode->i_sb,"invalid logical cluster 0 at nid %llu" , +erofs_err (sb,"invalid logical cluster 0 at nid %llu" , vi->nid); err = -EFSCORRUPTED ; goto unmap_out;
@@ -454,7 +455,7 @@ static int z_erofs_do_map_blocks(struct inode *inode, goto unmap_out;break ;default : -erofs_err (inode->i_sb,"unknown type %u @ offset %llu of nid %llu" , +erofs_err (sb,"unknown type %u @ offset %llu of nid %llu" , m.type, ofs, vi->nid); err = -EOPNOTSUPP ; goto unmap_out;
@@ -473,10 +474,16 @@ static int z_erofs_do_map_blocks(struct inode *inode, map->m_flags |=EROFS_MAP_META ; map->m_pa = vi->z_fragmentoff; map->m_plen = vi->z_idata_size; +if (erofs_blkoff (sb, map->m_pa) + map->m_plen > sb->s_blocksize) { +erofs_err (sb,"invalid tail-packing pclustersize %llu" , + map->m_plen); + err = -EFSCORRUPTED ; + goto unmap_out; + } }else if (fragment && m.lcn == vi->z_tailextent_headlcn) { map->m_flags |=EROFS_MAP_FRAGMENT ; }else { - map->m_pa =erofs_pos (inode->i_sb, m.pblk); + map->m_pa =erofs_pos (sb, m.pblk); err =z_erofs_get_extent_compressedlen (&m, initial_lcn);if (err) goto unmap_out;
@@ -495,7 +502,7 @@ static int z_erofs_do_map_blocks(struct inode *inode, afmt = m.headtype ==Z_EROFS_LCLUSTER_TYPE_HEAD2 ? vi->z_algorithmtype[1 ] : vi->z_algorithmtype[0 ];if (!(EROFS_I_SB (inode)->available_compr_algs & (1 << afmt))) { -erofs_err (inode->i_sb,"inconsistent algorithmtype %u for nid %llu" , +erofs_err (sb,"inconsistent algorithmtype %u for nid %llu" , afmt, vi->nid); err = -EFSCORRUPTED ; goto unmap_out;
@@ -596,26 +603,8 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) goto out_put_metabuf; } -if (vi->z_idata_size) { -struct erofs_map_blocks map = { - .buf = __EROFS_BUF_INITIALIZER - }; - - err =z_erofs_do_map_blocks (inode, &map, -EROFS_GET_BLOCKS_FINDTAIL ); -erofs_put_metabuf (&map.buf); - -if (erofs_blkoff (sb, map.m_pa) + map.m_plen > sb->s_blocksize) { -erofs_err (sb,"invalid tail-packing pclustersize %llu" , - map.m_plen); - err = -EFSCORRUPTED ; - } -if (err <0 ) - goto out_put_metabuf; - } - -if (vi->z_advise &Z_EROFS_ADVISE_FRAGMENT_PCLUSTER && - !(h->h_clusterbits >>Z_EROFS_FRAGMENT_INODE_BIT )) { +if (vi->z_idata_size || + (vi->z_advise &Z_EROFS_ADVISE_FRAGMENT_PCLUSTER )) {struct erofs_map_blocks map = { .buf = __EROFS_BUF_INITIALIZER };
Signature · 1 line
2.39.5
Sasha Levin
maintainerPATCH 6/6 erofs: fix large fragment handling
In reply to Sasha LevinFrom: Gao Xiang <[email protected]>
[ Upstream commit b44686c8391b427fb1c85a31c35077e6947c6d90 ]
Fragments aren't limited by Z_EROFS_PCLUSTER_MAX_DSIZE. However, if a fragment's logical length is larger than Z_EROFS_PCLUSTER_MAX_DSIZE but the fragment is not the whole inode, it currently returns -EOPNOTSUPP because m_flags has the wrong EROFS_MAP_ENCODED flag set. It is not intended by design but should be rare, as it can only be reproduced by mkfs with -Eall-fragments in a specific case.
Let's normalize fragment m_flags using the new EROFS_MAP_FRAGMENT.
--- fs/erofs/internal.h | 4 +++- fs/erofs/zdata.c | 2 +- fs/erofs/zmap.c | 7 +++---- 3 files changed, 7 insertions(+), 6 deletions(-)
fs/erofs/internal.h +3 -1
@@ -324,10 +324,12 @@ static inline struct folio *erofs_grab_folio_nowait(struct address_space *as,/* The length of extent is full */ #define EROFS_MAP_FULL_MAPPED 0x0008/* Located in the special packed inode */ -#define EROFS_MAP_FRAGMENT 0x0010 +#define __EROFS_MAP_FRAGMENT 0x0010/* The extent refers to partial decompressed data */ #define EROFS_MAP_PARTIAL_REF 0x0020 +#define EROFS_MAP_FRAGMENT (EROFS_MAP_MAPPED | __EROFS_MAP_FRAGMENT) +struct erofs_map_blocks {struct erofs_buf buf;
fs/erofs/zdata.c +1 -1
@@ -1016,7 +1016,7 @@ static int z_erofs_scan_folio(struct z_erofs_frontend *f,if (!(map->m_flags &EROFS_MAP_MAPPED )) {folio_zero_segment (folio, cur, end); tight = false; - }else if (map->m_flags &EROFS_MAP_FRAGMENT ) { + }else if (map->m_flags & __EROFS_MAP_FRAGMENT) {erofs_off_t fpos = offset + cur - map->m_la; err = z_erofs_read_fragment(inode->i_sb, folio, cur,
fs/erofs/zmap.c +3 -4
@@ -481,7 +481,7 @@ static int z_erofs_do_map_blocks(struct inode *inode, goto unmap_out; } }else if (fragment && m.lcn == vi->z_tailextent_headlcn) { - map->m_flags |=EROFS_MAP_FRAGMENT ; + map->m_flags =EROFS_MAP_FRAGMENT ; }else { map->m_pa =erofs_pos (sb, m.pblk); err =z_erofs_get_extent_compressedlen (&m, initial_lcn);
@@ -644,8 +644,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, struct erofs_map_blocks *map, !vi->z_tailextent_headlcn) { map->m_la = 0; map->m_llen = inode->i_size; - map->m_flags = EROFS_MAP_MAPPED | - EROFS_MAP_FULL_MAPPED | EROFS_MAP_FRAGMENT; + map->m_flags = EROFS_MAP_FRAGMENT; } else { err =z_erofs_do_map_blocks (inode, map, flags); }
@@ -678,7 +677,7 @@ static int z_erofs_iomap_begin_report(struct inode *inode, loff_t offset, iomap->length = map.m_llen;if (map.m_flags &EROFS_MAP_MAPPED ) { iomap->type =IOMAP_MAPPED ; - iomap->addr = map.m_flags &EROFS_MAP_FRAGMENT ? + iomap->addr = map.m_flags & __EROFS_MAP_FRAGMENT ?IOMAP_NULL_ADDR : map.m_pa; }else { iomap->type =IOMAP_HOLE ;
Signature · 1 line
2.39.5