]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
erofs: fix large fragment handling
authorGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 23 Jul 2025 13:50:09 +0000 (09:50 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 1 Aug 2025 08:48:45 +0000 (09:48 +0100)
[ 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.

Reported-by: Axel Fontaine <axel@axelfontaine.com>
Closes: https://github.com/erofs/erofs-utils/issues/23
Fixes: 7c3ca1838a78 ("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
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/erofs/internal.h
fs/erofs/zdata.c
fs/erofs/zmap.c

index 06895e9fec38f186506b58ad06636996f0bfd994..856463a702b2cbc1d3036f369eb8122461a69e40 100644 (file)
@@ -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;
 
index 94c1e2d64df9610a5bf8de18ed989eca2ba7e7b2..f35d2eb0ed11c5e29981cbf5b272f69475e6dd04 100644 (file)
@@ -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,
index f076cafb304f2d2dd9f4fa4816861a019af29ed2..25a4b82c183c0d492eb8956fb40208ec4d0a4c53 100644 (file)
@@ -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;