mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 01:53:29 +02:00
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.
Reported-by: Axel Fontaine <axel@axelfontaine.com>
Closes: https://github.com/erofs/erofs-utils/issues/23
Fixes: 7c3ca1838a ("erofs: restrict pcluster size limitations")
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20250711195826.3601157-1-hsiangkao@linux.alibaba.com
This commit is contained in:
parent
d31fbdc4c7
commit
b44686c839
|
|
@ -315,10 +315,12 @@ static inline struct folio *erofs_grab_folio_nowait(struct address_space *as,
|
||||||
/* The length of extent is full */
|
/* The length of extent is full */
|
||||||
#define EROFS_MAP_FULL_MAPPED 0x0008
|
#define EROFS_MAP_FULL_MAPPED 0x0008
|
||||||
/* Located in the special packed inode */
|
/* Located in the special packed inode */
|
||||||
#define EROFS_MAP_FRAGMENT 0x0010
|
#define __EROFS_MAP_FRAGMENT 0x0010
|
||||||
/* The extent refers to partial decompressed data */
|
/* The extent refers to partial decompressed data */
|
||||||
#define EROFS_MAP_PARTIAL_REF 0x0020
|
#define EROFS_MAP_PARTIAL_REF 0x0020
|
||||||
|
|
||||||
|
#define EROFS_MAP_FRAGMENT (EROFS_MAP_MAPPED | __EROFS_MAP_FRAGMENT)
|
||||||
|
|
||||||
struct erofs_map_blocks {
|
struct erofs_map_blocks {
|
||||||
struct erofs_buf buf;
|
struct erofs_buf buf;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1034,7 +1034,7 @@ static int z_erofs_scan_folio(struct z_erofs_frontend *f,
|
||||||
if (!(map->m_flags & EROFS_MAP_MAPPED)) {
|
if (!(map->m_flags & EROFS_MAP_MAPPED)) {
|
||||||
folio_zero_segment(folio, cur, end);
|
folio_zero_segment(folio, cur, end);
|
||||||
tight = false;
|
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;
|
erofs_off_t fpos = offset + cur - map->m_la;
|
||||||
|
|
||||||
err = z_erofs_read_fragment(inode->i_sb, folio, cur,
|
err = z_erofs_read_fragment(inode->i_sb, folio, cur,
|
||||||
|
|
|
||||||
|
|
@ -413,8 +413,7 @@ static int z_erofs_map_blocks_fo(struct inode *inode,
|
||||||
!vi->z_tailextent_headlcn) {
|
!vi->z_tailextent_headlcn) {
|
||||||
map->m_la = 0;
|
map->m_la = 0;
|
||||||
map->m_llen = inode->i_size;
|
map->m_llen = inode->i_size;
|
||||||
map->m_flags = EROFS_MAP_MAPPED |
|
map->m_flags = EROFS_MAP_FRAGMENT;
|
||||||
EROFS_MAP_FULL_MAPPED | EROFS_MAP_FRAGMENT;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
initial_lcn = ofs >> lclusterbits;
|
initial_lcn = ofs >> lclusterbits;
|
||||||
|
|
@ -489,7 +488,7 @@ static int z_erofs_map_blocks_fo(struct inode *inode,
|
||||||
goto unmap_out;
|
goto unmap_out;
|
||||||
}
|
}
|
||||||
} else if (fragment && m.lcn == vi->z_tailextent_headlcn) {
|
} else if (fragment && m.lcn == vi->z_tailextent_headlcn) {
|
||||||
map->m_flags |= EROFS_MAP_FRAGMENT;
|
map->m_flags = EROFS_MAP_FRAGMENT;
|
||||||
} else {
|
} else {
|
||||||
map->m_pa = erofs_pos(sb, m.pblk);
|
map->m_pa = erofs_pos(sb, m.pblk);
|
||||||
err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
|
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) {
|
if (lstart < lend) {
|
||||||
map->m_la = lstart;
|
map->m_la = lstart;
|
||||||
if (last && (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER)) {
|
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;
|
vi->z_fragmentoff = map->m_plen;
|
||||||
if (recsz > offsetof(struct z_erofs_extent, pstart_lo))
|
if (recsz > offsetof(struct z_erofs_extent, pstart_lo))
|
||||||
vi->z_fragmentoff |= map->m_pa << 32;
|
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;
|
iomap->length = map.m_llen;
|
||||||
if (map.m_flags & EROFS_MAP_MAPPED) {
|
if (map.m_flags & EROFS_MAP_MAPPED) {
|
||||||
iomap->type = IOMAP_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;
|
IOMAP_NULL_ADDR : map.m_pa;
|
||||||
} else {
|
} else {
|
||||||
iomap->type = IOMAP_HOLE;
|
iomap->type = IOMAP_HOLE;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user