[RFC PATCH v2 1/3] erofs-utils: lib: add support for fragments data decompression

Yue Hu zbestahu at gmail.com
Sat Jul 23 17:17:13 AEST 2022


Add compressed fragments support for erofsfuse.

Signed-off-by: Yue Hu <huyue2 at coolpad.com>
---
 include/erofs/internal.h | 13 +++++++++++
 include/erofs_fs.h       | 19 +++++++++++----
 lib/data.c               | 50 ++++++++++++++++++++++++++++++++++++++--
 lib/zmap.c               | 18 ++++++++++++---
 4 files changed, 90 insertions(+), 10 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 48498fe..ce235de 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -102,6 +102,7 @@ struct erofs_sb_info {
 		u16 devt_slotoff;		/* used for mkfs */
 		u16 device_id_mask;		/* used for others */
 	};
+	struct erofs_inode *fragments_inode;
 };
 
 /* global sbi */
@@ -132,6 +133,7 @@ EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER)
 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(sb_chksum, compat, COMPAT_SB_CHKSUM)
 
 #define EROFS_I_EA_INITED	(1 << 0)
@@ -190,6 +192,8 @@ struct erofs_inode {
 	void *eof_tailraw;
 	unsigned int eof_tailrawsize;
 
+	erofs_off_t fragmentoff;
+
 	union {
 		void *compressmeta;
 		void *chunkindexes;
@@ -201,6 +205,7 @@ struct erofs_inode {
 			uint64_t z_tailextent_headlcn;
 			unsigned int    z_idataoff;
 #define z_idata_size	idata_size
+#define z_fragmentoff	fragmentoff
 		};
 	};
 #ifdef WITH_ANDROID
@@ -208,6 +213,11 @@ struct erofs_inode {
 #endif
 };
 
+static inline erofs_off_t z_erofs_map_header_pos(struct erofs_inode *vi)
+{
+	return round_up(iloc(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
+}
+
 static inline bool is_inode_layout_compression(struct erofs_inode *inode)
 {
 	return erofs_inode_is_data_compressed(inode->datalayout);
@@ -276,6 +286,7 @@ enum {
 	BH_Mapped,
 	BH_Encoded,
 	BH_FullMapped,
+	BH_Fragments,
 };
 
 /* Has a disk mapping */
@@ -286,6 +297,8 @@ enum {
 #define EROFS_MAP_ENCODED	(1 << BH_Encoded)
 /* The length of extent is full */
 #define EROFS_MAP_FULL_MAPPED	(1 << BH_FullMapped)
+/* Located in fragments */
+#define EROFS_MAP_FRAGMENTS	(1 << BH_Fragments)
 
 struct erofs_map_blocks {
 	char mpage[EROFS_BLKSIZ];
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index 08f9761..d957ebb 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -25,13 +25,15 @@
 #define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE	0x00000004
 #define EROFS_FEATURE_INCOMPAT_DEVICE_TABLE	0x00000008
 #define EROFS_FEATURE_INCOMPAT_ZTAILPACKING	0x00000010
+#define EROFS_FEATURE_INCOMPAT_FRAGMENTS	0x00000020
 #define EROFS_ALL_FEATURE_INCOMPAT		\
 	(EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \
 	 EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \
 	 EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER | \
 	 EROFS_FEATURE_INCOMPAT_CHUNKED_FILE | \
 	 EROFS_FEATURE_INCOMPAT_DEVICE_TABLE | \
-	 EROFS_FEATURE_INCOMPAT_ZTAILPACKING)
+	 EROFS_FEATURE_INCOMPAT_ZTAILPACKING | \
+	 EROFS_FEATURE_INCOMPAT_FRAGMENTS)
 
 #define EROFS_SB_EXTSLOT_SIZE	16
 
@@ -294,16 +296,21 @@ struct z_erofs_lzma_cfgs {
  * bit 1 : HEAD1 big pcluster (0 - off; 1 - on)
  * bit 2 : HEAD2 big pcluster (0 - off; 1 - on)
  * bit 3 : tailpacking inline pcluster (0 - off; 1 - on)
+ * bit 4 : fragment pcluster (0 - off; 1 - on)
  */
 #define Z_EROFS_ADVISE_COMPACTED_2B		0x0001
 #define Z_EROFS_ADVISE_BIG_PCLUSTER_1		0x0002
 #define Z_EROFS_ADVISE_BIG_PCLUSTER_2		0x0004
 #define Z_EROFS_ADVISE_INLINE_PCLUSTER		0x0008
+#define Z_EROFS_ADVISE_FRAGMENT_PCLUSTER	0x0010
 
 struct z_erofs_map_header {
-	__le16	h_reserved1;
-	/* record the size of tailpacking data */
-	__le16  h_idata_size;
+	union {
+		/* direct addressing for fragment offset */
+		__le32	h_fragmentoff;
+		/* record the size of tailpacking data */
+		__le16	h_idata_size;
+	};
 	__le16	h_advise;
 	/*
 	 * bit 0-3 : algorithm type of head 1 (logical cluster type 01);
@@ -312,12 +319,14 @@ struct z_erofs_map_header {
 	__u8	h_algorithmtype;
 	/*
 	 * bit 0-2 : logical cluster bits - 12, e.g. 0 for 4096;
-	 * bit 3-7 : reserved.
+	 * bit 3-6 : reserved;
+	 * bit 7   : merge the whole file into fragments or not.
 	 */
 	__u8	h_clusterbits;
 };
 
 #define Z_EROFS_VLE_LEGACY_HEADER_PADDING       8
+#define Z_EROFS_FRAGMENT_INODE_BIT		7
 
 /*
  * Fixed-sized output compression ondisk Logical Extent cluster type:
diff --git a/lib/data.c b/lib/data.c
index 6bc554d..2f3ebb8 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -217,8 +217,8 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
 	return 0;
 }
 
-static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
-			     erofs_off_t size, erofs_off_t offset)
+static int z_erofs_do_read_data(struct erofs_inode *inode, char *buffer,
+				erofs_off_t size, erofs_off_t offset)
 {
 	erofs_off_t end, length, skip;
 	struct erofs_map_blocks map = {
@@ -275,6 +275,27 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
 			continue;
 		}
 
+		if (map.m_flags & EROFS_MAP_FRAGMENTS) {
+			char *out;
+
+			out = malloc(length);
+			if (!out) {
+				ret = -ENOMEM;
+				break;
+			}
+			ret = z_erofs_do_read_data(sbi.fragments_inode, out,
+						   length,
+						   inode->z_fragmentoff);
+			if (ret < 0) {
+				free(out);
+				break;
+			}
+			memcpy(buffer + end - offset, out + skip, length -
+			       skip);
+			free(out);
+			continue;
+		}
+
 		if (map.m_plen > bufsize) {
 			bufsize = map.m_plen;
 			raw = realloc(raw, bufsize);
@@ -304,6 +325,31 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
 	return ret < 0 ? ret : 0;
 }
 
+static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
+			     erofs_off_t size, erofs_off_t offset)
+{
+	struct erofs_inode *vi = inode;
+
+	if (erofs_sb_has_fragments()) {
+		int ret;
+		struct z_erofs_map_header *h;
+		char buf[sizeof(struct z_erofs_map_header)];
+
+		ret = dev_read(0, buf, z_erofs_map_header_pos(inode),
+			       sizeof(buf));
+		if (ret < 0)
+			return -EIO;
+
+		h = (struct z_erofs_map_header *)buf;
+
+		if (h->h_clusterbits >> Z_EROFS_FRAGMENT_INODE_BIT) {
+			vi = sbi.fragments_inode;
+			offset += le32_to_cpu(h->h_fragmentoff);
+		}
+	}
+	return z_erofs_do_read_data(vi, buffer, size, offset);
+}
+
 int erofs_pread(struct erofs_inode *inode, char *buf,
 		erofs_off_t count, erofs_off_t offset)
 {
diff --git a/lib/zmap.c b/lib/zmap.c
index 95745c5..812bf32 100644
--- a/lib/zmap.c
+++ b/lib/zmap.c
@@ -32,7 +32,6 @@ int z_erofs_fill_inode(struct erofs_inode *vi)
 static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
 {
 	int ret;
-	erofs_off_t pos;
 	struct z_erofs_map_header *h;
 	char buf[sizeof(struct z_erofs_map_header)];
 
@@ -42,9 +41,8 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
 	DBG_BUGON(!erofs_sb_has_big_pcluster() &&
 		  !erofs_sb_has_ztailpacking() &&
 		  vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
-	pos = round_up(iloc(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
 
-	ret = dev_read(0, buf, pos, sizeof(buf));
+	ret = dev_read(0, buf, z_erofs_map_header_pos(vi), sizeof(buf));
 	if (ret < 0)
 		return -EIO;
 
@@ -83,6 +81,17 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
 		if (ret < 0)
 			return ret;
 	}
+	if (vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER) {
+		struct erofs_map_blocks map = { .index = UINT_MAX };
+
+		ret = z_erofs_do_map_blocks(vi, &map,
+					    EROFS_GET_BLOCKS_FINDTAIL);
+		if (ret < 0) {
+			erofs_err("failed to find tail for fragment pcluster");
+			return ret;
+		}
+		vi->z_fragmentoff = le32_to_cpu(h->h_fragmentoff);
+	}
 	vi->flags |= EROFS_I_Z_INITED;
 	return 0;
 }
@@ -546,6 +555,7 @@ static int z_erofs_do_map_blocks(struct erofs_inode *vi,
 				 int flags)
 {
 	bool ztailpacking = vi->z_advise & Z_EROFS_ADVISE_INLINE_PCLUSTER;
+	bool in_fragments = vi->z_advise & Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
 	struct z_erofs_maprecorder m = {
 		.inode = vi,
 		.map = map,
@@ -609,6 +619,8 @@ static int z_erofs_do_map_blocks(struct erofs_inode *vi,
 		map->m_flags |= EROFS_MAP_META;
 		map->m_pa = vi->z_idataoff;
 		map->m_plen = vi->z_idata_size;
+	} else if (in_fragments && m.lcn == vi->z_tailextent_headlcn) {
+		map->m_flags |= EROFS_MAP_FRAGMENTS;
 	} else {
 		map->m_pa = blknr_to_addr(m.pblk);
 		err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
-- 
2.17.1



More information about the Linux-erofs mailing list