--- /dev/null
+From 8f89926290c4b3d31748d5089b27952243be0693 Mon Sep 17 00:00:00 2001
+From: Gao Xiang <hsiangkao@linux.alibaba.com>
+Date: Sat, 9 Oct 2021 04:08:37 +0800
+Subject: [PATCH 1003/1012] erofs: get compression algorithms directly on
+ mapping
+
+Currently, z_erofs_map_blocks_iter() returns whether extents are
+compressed or not, and the decompression frontend gets the specific
+algorithms then.
+
+It works but not quite well in many aspests, for example:
+ - The decompression frontend has to deal with whether extents are
+ compressed or not again and lookup the algorithms if compressed.
+ It's duplicated and too detailed about the on-disk mapping.
+
+ - A new secondary compression head will be introduced later so that
+ each file can have 2 compression algorithms at most for different
+ type of data. It could increase the complexity of the decompression
+ frontend if still handled in this way;
+
+ - A new readmore decompression strategy will be introduced to get
+ better performance for much bigger pcluster and lzma, which needs
+ the specific algorithm in advance as well.
+
+Let's look up compression algorithms in z_erofs_map_blocks_iter()
+directly instead.
+
+Link: https://lore.kernel.org/r/20211008200839.24541-2-xiang@kernel.org
+Reviewed-by: Chao Yu <chao@kernel.org>
+Reviewed-by: Yue Hu <huyue2@yulong.com>
+Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
+---
+ fs/erofs/compress.h | 5 -----
+ fs/erofs/internal.h | 12 +++++++++---
+ fs/erofs/zdata.c | 12 ++++++------
+ fs/erofs/zmap.c | 19 ++++++++++---------
+ include/trace/events/erofs.h | 2 +-
+ 5 files changed, 26 insertions(+), 24 deletions(-)
+
+diff --git a/fs/erofs/compress.h b/fs/erofs/compress.h
+index 3701c72ba..ad62d1b4d 100644
+--- a/fs/erofs/compress.h
++++ b/fs/erofs/compress.h
+@@ -8,11 +8,6 @@
+
+ #include "internal.h"
+
+-enum {
+- Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX,
+- Z_EROFS_COMPRESSION_RUNTIME_MAX
+-};
+-
+ struct z_erofs_decompress_req {
+ struct super_block *sb;
+ struct page **in, **out;
+diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
+index 0661d7d69..f8537ffde 100644
+--- a/fs/erofs/internal.h
++++ b/fs/erofs/internal.h
+@@ -363,7 +363,7 @@ extern const struct address_space_operations z_erofs_aops;
+ * of the corresponding uncompressed data in the file.
+ */
+ enum {
+- BH_Zipped = BH_PrivateStart,
++ BH_Encoded = BH_PrivateStart,
+ BH_FullMapped,
+ };
+
+@@ -371,8 +371,8 @@ enum {
+ #define EROFS_MAP_MAPPED (1 << BH_Mapped)
+ /* Located in metadata (could be copied from bd_inode) */
+ #define EROFS_MAP_META (1 << BH_Meta)
+-/* The extent has been compressed */
+-#define EROFS_MAP_ZIPPED (1 << BH_Zipped)
++/* The extent is encoded */
++#define EROFS_MAP_ENCODED (1 << BH_Encoded)
+ /* The length of extent is full */
+ #define EROFS_MAP_FULL_MAPPED (1 << BH_FullMapped)
+
+@@ -381,6 +381,7 @@ struct erofs_map_blocks {
+ u64 m_plen, m_llen;
+
+ unsigned short m_deviceid;
++ char m_algorithmformat;
+ unsigned int m_flags;
+
+ struct page *mpage;
+@@ -394,6 +395,11 @@ struct erofs_map_blocks {
+ */
+ #define EROFS_GET_BLOCKS_FIEMAP 0x0002
+
++enum {
++ Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX,
++ Z_EROFS_COMPRESSION_RUNTIME_MAX
++};
++
+ /* zmap.c */
+ extern const struct iomap_ops z_erofs_iomap_report_ops;
+
+diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
+index 8c947ed49..a9dced07c 100644
+--- a/fs/erofs/zdata.c
++++ b/fs/erofs/zdata.c
+@@ -476,6 +476,11 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt,
+ struct erofs_workgroup *grp;
+ int err;
+
++ if (!(map->m_flags & EROFS_MAP_ENCODED)) {
++ DBG_BUGON(1);
++ return -EFSCORRUPTED;
++ }
++
+ /* no available pcluster, let's allocate one */
+ pcl = z_erofs_alloc_pcluster(map->m_plen >> PAGE_SHIFT);
+ if (IS_ERR(pcl))
+@@ -483,16 +488,11 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt,
+
+ atomic_set(&pcl->obj.refcount, 1);
+ pcl->obj.index = map->m_pa >> PAGE_SHIFT;
+-
++ pcl->algorithmformat = map->m_algorithmformat;
+ pcl->length = (map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) |
+ (map->m_flags & EROFS_MAP_FULL_MAPPED ?
+ Z_EROFS_PCLUSTER_FULL_LENGTH : 0);
+
+- if (map->m_flags & EROFS_MAP_ZIPPED)
+- pcl->algorithmformat = Z_EROFS_COMPRESSION_LZ4;
+- else
+- pcl->algorithmformat = Z_EROFS_COMPRESSION_SHIFTED;
+-
+ /* new pclusters should be claimed as type 1, primary and followed */
+ pcl->next = clt->owned_head;
+ clt->mode = COLLECT_PRIMARY_FOLLOWED;
+diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
+index 7a6df35fd..1c3b068e5 100644
+--- a/fs/erofs/zmap.c
++++ b/fs/erofs/zmap.c
+@@ -111,7 +111,7 @@ struct z_erofs_maprecorder {
+
+ unsigned long lcn;
+ /* compression extent information gathered */
+- u8 type;
++ u8 type, headtype;
+ u16 clusterofs;
+ u16 delta[2];
+ erofs_blk_t pblk, compressedlcs;
+@@ -446,9 +446,8 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
+ }
+ return z_erofs_extent_lookback(m, m->delta[0]);
+ case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+- map->m_flags &= ~EROFS_MAP_ZIPPED;
+- fallthrough;
+ case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
++ m->headtype = m->type;
+ map->m_la = (lcn << lclusterbits) | m->clusterofs;
+ break;
+ default:
+@@ -472,7 +471,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
+
+ DBG_BUGON(m->type != Z_EROFS_VLE_CLUSTER_TYPE_PLAIN &&
+ m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD);
+- if (!(map->m_flags & EROFS_MAP_ZIPPED) ||
++ if (m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN ||
+ !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) {
+ map->m_plen = 1 << lclusterbits;
+ return 0;
+@@ -609,16 +608,14 @@ int z_erofs_map_blocks_iter(struct inode *inode,
+ if (err)
+ goto unmap_out;
+
+- map->m_flags = EROFS_MAP_ZIPPED; /* by default, compressed */
++ map->m_flags = EROFS_MAP_MAPPED | EROFS_MAP_ENCODED;
+ end = (m.lcn + 1ULL) << lclusterbits;
+
+ switch (m.type) {
+ case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+- if (endoff >= m.clusterofs)
+- map->m_flags &= ~EROFS_MAP_ZIPPED;
+- fallthrough;
+ case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+ if (endoff >= m.clusterofs) {
++ m.headtype = m.type;
+ map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
+ break;
+ }
+@@ -650,12 +647,16 @@ int z_erofs_map_blocks_iter(struct inode *inode,
+
+ map->m_llen = end - map->m_la;
+ map->m_pa = blknr_to_addr(m.pblk);
+- map->m_flags |= EROFS_MAP_MAPPED;
+
+ err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
+ if (err)
+ goto out;
+
++ if (m.headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN)
++ map->m_algorithmformat = Z_EROFS_COMPRESSION_SHIFTED;
++ else
++ map->m_algorithmformat = vi->z_algorithmtype[0];
++
+ if (flags & EROFS_GET_BLOCKS_FIEMAP) {
+ err = z_erofs_get_extent_decompressedlen(&m);
+ if (!err)
+diff --git a/include/trace/events/erofs.h b/include/trace/events/erofs.h
+index db4f2cec8..16ae7b666 100644
+--- a/include/trace/events/erofs.h
++++ b/include/trace/events/erofs.h
+@@ -24,7 +24,7 @@ struct erofs_map_blocks;
+ #define show_mflags(flags) __print_flags(flags, "", \
+ { EROFS_MAP_MAPPED, "M" }, \
+ { EROFS_MAP_META, "I" }, \
+- { EROFS_MAP_ZIPPED, "Z" })
++ { EROFS_MAP_ENCODED, "E" })
+
+ TRACE_EVENT(erofs_lookup,
+
+--
+2.32.0
+