[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