erofs-utils: fuse: introduce partial-referenced pclusters
authorGao Xiang <hsiangkao@linux.alibaba.com>
Mon, 26 Sep 2022 15:25:10 +0000 (23:25 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Tue, 4 Oct 2022 17:32:09 +0000 (01:32 +0800)
Due to deduplication for compressed data, pclusters can be partially
referenced with their prefixes.

Decompression algorithms should know that in advance, otherwise they
will fail out unexpectedly.

Keep in sync with the latest kernel
commit 5c2a64252c5d ("erofs: introduce partial-referenced pclusters")

Signed-off-by: Ziyang Zhang <ZiyangZhang@linux.alibaba.com>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20220926152511.94832-8-hsiangkao@linux.alibaba.com
include/erofs/internal.h
include/erofs_fs.h
lib/data.c
lib/zmap.c

index c831700307dd49cfa62c87faa81c7fe9ebc00fd8..db7ac2d87b388f1042958b648dad6a3f086f2fb8 100644 (file)
@@ -136,6 +136,7 @@ EROFS_FEATURE_FUNCS(chunked_file, incompat, INCOMPAT_CHUNKED_FILE)
 EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE)
 EROFS_FEATURE_FUNCS(ztailpacking, incompat, INCOMPAT_ZTAILPACKING)
 EROFS_FEATURE_FUNCS(fragments, incompat, INCOMPAT_FRAGMENTS)
+EROFS_FEATURE_FUNCS(dedupe, incompat, INCOMPAT_DEDUPE)
 EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
 
 #define EROFS_I_EA_INITED      (1 << 0)
@@ -286,6 +287,7 @@ enum {
        BH_Encoded,
        BH_FullMapped,
        BH_Fragment,
+       BH_Partialref,
 };
 
 /* Has a disk mapping */
@@ -298,6 +300,8 @@ enum {
 #define EROFS_MAP_FULL_MAPPED  (1 << BH_FullMapped)
 /* Located in the special packed inode */
 #define EROFS_MAP_FRAGMENT     (1 << BH_Fragment)
+/* The extent refers to partial decompressed data */
+#define EROFS_MAP_PARTIAL_REF  (1 << BH_Partialref)
 
 struct erofs_map_blocks {
        char mpage[EROFS_BLKSIZ];
index 7fdc54a0caa7ecb8793a322b6fc31ac8ccbcc4fc..8835a76a9814a0ceb16a3f4df549cc6f90f8b98c 100644 (file)
@@ -26,6 +26,7 @@
 #define EROFS_FEATURE_INCOMPAT_DEVICE_TABLE    0x00000008
 #define EROFS_FEATURE_INCOMPAT_ZTAILPACKING    0x00000010
 #define EROFS_FEATURE_INCOMPAT_FRAGMENTS       0x00000020
+#define EROFS_FEATURE_INCOMPAT_DEDUPE          0x00000020
 #define EROFS_ALL_FEATURE_INCOMPAT             \
        (EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \
         EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \
@@ -33,7 +34,8 @@
         EROFS_FEATURE_INCOMPAT_CHUNKED_FILE | \
         EROFS_FEATURE_INCOMPAT_DEVICE_TABLE | \
         EROFS_FEATURE_INCOMPAT_ZTAILPACKING | \
-        EROFS_FEATURE_INCOMPAT_FRAGMENTS)
+        EROFS_FEATURE_INCOMPAT_FRAGMENTS | \
+        EROFS_FEATURE_INCOMPAT_DEDUPE)
 
 #define EROFS_SB_EXTSLOT_SIZE  16
 
@@ -371,6 +373,9 @@ enum {
 #define Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS        2
 #define Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT         0
 
+/* (noncompact only, HEAD) This pcluster refers to partial decompressed data */
+#define Z_EROFS_VLE_DI_PARTIAL_REF             (1 << 15)
+
 /*
  * D0_CBLKCNT will be marked _only_ at the 1st non-head lcluster to store the
  * compressed block count of a compressed extent (in logical clusters, aka.
index bcb0f7e6cc0ac4c60035a925e3346e469ee84dcb..76a6677e51144b169c75c3469d66f41975210e3a 100644 (file)
@@ -258,7 +258,8 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
                } else {
                        DBG_BUGON(end != map.m_la + map.m_llen);
                        length = map.m_llen;
-                       partial = !(map.m_flags & EROFS_MAP_FULL_MAPPED);
+                       partial = !(map.m_flags & EROFS_MAP_FULL_MAPPED) ||
+                               (map.m_flags & EROFS_MAP_PARTIAL_REF);
                }
 
                if (map.m_la < offset) {
index a234767dc803f697f860b7addd52324515e61be1..1c6706ae4c9015c85968dab1598d784974d4bb7d 100644 (file)
@@ -117,6 +117,7 @@ struct z_erofs_maprecorder {
        u16 delta[2];
        erofs_blk_t pblk, compressedlcs;
        erofs_off_t nextpackoff;
+       bool partialref;
 };
 
 static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
@@ -179,6 +180,8 @@ static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
                break;
        case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
        case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+               if (advise & Z_EROFS_VLE_DI_PARTIAL_REF)
+                       m->partialref = true;
                m->clusterofs = le16_to_cpu(di->di_clusterofs);
                m->pblk = le32_to_cpu(di->di_u.blkaddr);
                break;
@@ -620,7 +623,8 @@ static int z_erofs_do_map_blocks(struct erofs_inode *vi,
                err = -EOPNOTSUPP;
                goto out;
        }
-
+       if (m.partialref)
+               map->m_flags |= EROFS_MAP_PARTIAL_REF;
        map->m_llen = end - map->m_la;
        if (flags & EROFS_GET_BLOCKS_FINDTAIL) {
                vi->z_tailextent_headlcn = m.lcn;