[WIP] [PATCH v3 04/12] erofs-utils: fuse: refactor raw data logic

Gao Xiang hsiangkao at aol.com
Tue Nov 3 02:55:50 AEDT 2020


As a common logic and move into lib/
( will fold in to the original patch. )

Signed-off-by: Gao Xiang <hsiangkao at aol.com>
---
 fuse/init.c              |   2 +
 fuse/read.c              |  76 ++++++-------------------
 include/erofs/internal.h |  19 ++++++-
 lib/Makefile.am          |   2 +-
 lib/data.c               | 117 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 155 insertions(+), 61 deletions(-)
 create mode 100644 lib/data.c

diff --git a/fuse/init.c b/fuse/init.c
index c6a3af697532..09e7b1210006 100644
--- a/fuse/init.c
+++ b/fuse/init.c
@@ -71,7 +71,9 @@ int erofs_init_super(void)
 	sbk->build_time_nsec = le32_to_cpu(sb->build_time_nsec);
 	sbk->blocks = le32_to_cpu(sb->blocks);
 	sbk->meta_blkaddr = le32_to_cpu(sb->meta_blkaddr);
+	sbi.meta_blkaddr = sbk->meta_blkaddr;
 	sbk->xattr_blkaddr = le32_to_cpu(sb->xattr_blkaddr);
+	sbi.islotbits = EROFS_ISLOTBITS;
 	memcpy(sbk->uuid, sb->uuid, 16);
 	memcpy(sbk->volume_name, sb->volume_name, 16);
 	sbk->root_nid = le16_to_cpu(sb->root_nid);
diff --git a/fuse/read.c b/fuse/read.c
index 11f7e6161f8f..dc88b24eaae3 100644
--- a/fuse/read.c
+++ b/fuse/read.c
@@ -19,64 +19,26 @@
 #include "init.h"
 #include "erofs/decompress.h"
 
-size_t erofs_read_data(struct erofs_vnode *vnode, char *buffer,
-		       size_t size, off_t offset)
+size_t erofs_read_data_wrapper(struct erofs_vnode *vnode, char *buffer,
+			       size_t size, off_t offset)
 {
-	int ret;
-	size_t sum, rdsz = 0;
-	uint32_t addr = blknr_to_addr(vnode->raw_blkaddr) + offset;
-
-	sum = (offset + size) > vnode->i_size ?
-		(size_t)(vnode->i_size - offset) : size;
-	while (rdsz < sum) {
-		size_t count = min(EROFS_BLKSIZ, (uint32_t)(sum - rdsz));
-
-		ret = dev_read(buffer + rdsz, addr + rdsz, count);
-		if (ret < 0)
-			return -EIO;
-		rdsz += count;
-	}
-
-	erofs_info("nid:%llu size=%zd offset=%llu realsize=%zd done",
-	     (unsigned long long)vnode->nid, size, (long long)offset, rdsz);
-	return rdsz;
-
-}
-
-size_t erofs_read_data_inline(struct erofs_vnode *vnode, char *buffer,
-			      size_t size, off_t offset)
-{
-	int ret;
-	size_t sum, suminline, rdsz = 0;
-	uint32_t addr = blknr_to_addr(vnode->raw_blkaddr) + offset;
-	uint32_t szblk = vnode->i_size - erofs_blkoff(vnode->i_size);
-
-	sum = (offset + size) > szblk ? (size_t)(szblk - offset) : size;
-	suminline = size - sum;
-
-	while (rdsz < sum) {
-		size_t count = min(EROFS_BLKSIZ, (uint32_t)(sum - rdsz));
-
-		ret = dev_read(buffer + rdsz, addr + rdsz, count);
-		if (ret < 0)
-			return -EIO;
-		rdsz += count;
-	}
-
-	if (!suminline)
-		goto finished;
-
-	addr = nid2addr(vnode->nid) + vnode->inode_isize + vnode->xattr_isize;
-	ret = dev_read(buffer + rdsz, addr, suminline);
-	if (ret < 0)
-		return -EIO;
-	rdsz += suminline;
+	struct erofs_inode tmp = {
+		.u = {
+			.i_blkaddr = vnode->raw_blkaddr,
+		},
+		.nid = vnode->nid,
+		.i_size = vnode->i_size,
+		.datalayout = vnode->datalayout,
+		.inode_isize = vnode->inode_isize,
+		.xattr_isize = vnode->xattr_isize,
+	};
 
-finished:
-	erofs_info("nid:%llu size=%zd suminline=%u offset=%llu realsize=%zd done",
-	     (unsigned long long)vnode->nid, size, (unsigned)suminline, (long long)offset, rdsz);
-	return rdsz;
+	int ret = erofs_read_raw_data(&tmp, buffer, offset, size);
+	if (ret)
+		return ret;
 
+	erofs_info("nid:%llu size=%zd done", (unsigned long long)vnode->nid, size);
+	return size;
 }
 
 size_t erofs_read_data_compression(struct erofs_vnode *vnode, char *buffer,
@@ -172,10 +134,8 @@ int erofs_read(const char *path, char *buffer, size_t size, off_t offset,
 	erofs_info("path:%s nid=%llu mode=%u", path, (unsigned long long)nid, v.datalayout);
 	switch (v.datalayout) {
 	case EROFS_INODE_FLAT_PLAIN:
-		return erofs_read_data(&v, buffer, size, offset);
-
 	case EROFS_INODE_FLAT_INLINE:
-		return erofs_read_data_inline(&v, buffer, size, offset);
+		return erofs_read_data_wrapper(&v, buffer, size, offset);
 
 	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
 	case EROFS_INODE_FLAT_COMPRESSION:
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 6c5fbd3c5d3c..54038071bf84 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -70,12 +70,20 @@ struct erofs_sb_info {
 	u32 feature_incompat;
 	u64 build_time;
 	u32 build_time_nsec;
+
+	unsigned char islotbits;
+
 	u8 uuid[16];
 };
 
 /* global sbi */
 extern struct erofs_sb_info sbi;
 
+static inline erofs_off_t iloc(erofs_nid_t nid)
+{
+	return blknr_to_addr(sbi.meta_blkaddr) + (nid << sbi.islotbits);
+}
+
 #define EROFS_FEATURE_FUNCS(name, compat, feature) \
 static inline bool erofs_sb_has_##name(void) \
 { \
@@ -219,13 +227,16 @@ static inline const char *erofs_strerror(int err)
 }
 
 enum {
-	BH_Mapped ,
-	BH_Zipped ,
+	BH_Meta,
+	BH_Mapped,
+	BH_Zipped,
 	BH_FullMapped,
 };
 
 /* Has a disk mapping */
 #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 length of extent is full */
@@ -241,6 +252,10 @@ struct erofs_map_blocks {
 	erofs_blk_t index;
 };
 
+/* data.h */
+int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
+			erofs_off_t offset, erofs_off_t size);
+
 /* zmap.c */
 int z_erofs_fill_inode(struct erofs_vnode *vi);
 int z_erofs_map_blocks_iter(struct erofs_vnode *vi,
diff --git a/lib/Makefile.am b/lib/Makefile.am
index c921a62a8b23..54c43897aa49 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -3,7 +3,7 @@
 
 noinst_LTLIBRARIES = liberofs.la
 liberofs_la_SOURCES = config.c io.c cache.c inode.c xattr.c exclude.c \
-		      compress.c compressor.c decompress.c
+		      data.c compress.c compressor.c decompress.c
 liberofs_la_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
 if ENABLE_LZ4
 liberofs_la_CFLAGS += ${LZ4_CFLAGS}
diff --git a/lib/data.c b/lib/data.c
new file mode 100644
index 000000000000..56b208513980
--- /dev/null
+++ b/lib/data.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/lib/data.c
+ *
+ * Copyright (C) 2020 Gao Xiang <hsiangkao at aol.com>
+ */
+#include "erofs/print.h"
+#include "erofs/internal.h"
+#include "erofs/io.h"
+#include "erofs/trace.h"
+
+static int erofs_map_blocks_flatmode(struct erofs_inode *inode,
+				     struct erofs_map_blocks *map,
+				     int flags)
+{
+	int err = 0;
+	erofs_blk_t nblocks, lastblk;
+	u64 offset = map->m_la;
+	struct erofs_inode *vi = inode;
+	bool tailendpacking = (vi->datalayout == EROFS_INODE_FLAT_INLINE);
+
+	trace_erofs_map_blocks_flatmode_enter(inode, map, flags);
+
+	nblocks = DIV_ROUND_UP(inode->i_size, PAGE_SIZE);
+	lastblk = nblocks - tailendpacking;
+
+	if (offset >= inode->i_size) {
+		/* leave out-of-bound access unmapped */
+		map->m_flags = 0;
+		goto out;
+	}
+
+	/* there is no hole in flatmode */
+	map->m_flags = EROFS_MAP_MAPPED;
+
+	if (offset < blknr_to_addr(lastblk)) {
+		map->m_pa = blknr_to_addr(vi->u.i_blkaddr) + map->m_la;
+		map->m_plen = blknr_to_addr(lastblk) - offset;
+	} else if (tailendpacking) {
+		/* 2 - inode inline B: inode, [xattrs], inline last blk... */
+		map->m_pa = iloc(vi->nid) + vi->inode_isize +
+			vi->xattr_isize + erofs_blkoff(map->m_la);
+		map->m_plen = inode->i_size - offset;
+
+		/* inline data should be located in one meta block */
+		if (erofs_blkoff(map->m_pa) + map->m_plen > PAGE_SIZE) {
+			erofs_err("inline data cross block boundary @ nid %" PRIu64,
+				  vi->nid);
+			DBG_BUGON(1);
+			err = -EFSCORRUPTED;
+			goto err_out;
+		}
+
+		map->m_flags |= EROFS_MAP_META;
+	} else {
+		erofs_err("internal error @ nid: %" PRIu64 " (size %llu), m_la 0x%" PRIx64,
+			  vi->nid, (unsigned long long)inode->i_size, map->m_la);
+		DBG_BUGON(1);
+		err = -EIO;
+		goto err_out;
+	}
+
+out:
+	map->m_llen = map->m_plen;
+
+err_out:
+	trace_erofs_map_blocks_flatmode_exit(inode, map, flags, 0);
+	return err;
+}
+
+int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
+			erofs_off_t offset, erofs_off_t size)
+{
+	struct erofs_map_blocks map = {
+		.index = UINT_MAX,
+	};
+	int ret;
+	erofs_off_t ptr = offset;
+
+	while (ptr < offset + size) {
+		erofs_off_t eend;
+
+		map.m_la = ptr;
+		ret = erofs_map_blocks_flatmode(inode, &map, 0);
+		if (ret)
+			return ret;
+
+		DBG_BUGON(map.m_plen != map.m_llen);
+
+		if (!(map.m_flags & EROFS_MAP_MAPPED)) {
+			if (!map.m_llen) {
+				ptr = offset + size;
+				continue;
+			}
+			ptr = map.m_la + map.m_llen;
+			continue;
+		}
+
+		/* trim extent */
+		eend = min(offset + size, map.m_la + map.m_llen);
+		DBG_BUGON(ptr < map.m_la);
+
+		if (ptr > map.m_la) {
+			map.m_pa += ptr - map.m_la;
+			map.m_la = ptr;
+		}
+
+		ret = dev_read(buffer + ptr - offset,
+			       map.m_pa, eend - map.m_la);
+		if (ret < 0)
+			return -EIO;
+
+		ptr = eend;
+	}
+	return 0;
+}
+
-- 
2.24.0



More information about the Linux-erofs mailing list