linux-erofs.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation
       [not found] <20201102155558.1995-1-hsiangkao.ref@aol.com>
@ 2020-11-02 15:55 ` Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 01/12] " Gao Xiang via Linux-erofs
                     ` (8 more replies)
  0 siblings, 9 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs

From: Gao Xiang <hsiangkao@redhat.com>

v2: https://lore.kernel.org/r/20201024130959.23720-1-hsiangkao@aol.com

background & v1:
https://lore.kernel.org/r/20201017051621.7810-1-hsiangkao@aol.com

kill a lot of insane logic, and hopefully it can get into shape
in the next iter.

Thanks,
Gao Xiang

Gao Xiang (9):
  erofs-utils: fuse: refactor raw data logic
  erofs-utils: fuse: kill sbk
  erofs-utils: fuse: kill nid2addr, addr2nid
  erofs-utils: fuse: kill erofs_get_root_nid()
  erofs-utils: fuse: move erofs_init() to main.c
  erofs-utils: fuse: move superblock logic into lib/
  erofs-utils: fuse: kill getattr.c
  erofs-utils: fuse: kill open.c
  erofs-utils: fuse: kill incomplate dcache

Huang Jianan (2):
  erofs-utils: fuse: add special file support
  erofs-utils: fuse: add compressed file support

Li Guifu (1):
  erofs-utils: introduce fuse implementation

 Makefile.am                |   2 +-
 README                     |  28 ++-
 configure.ac               |   3 +-
 fuse/Makefile.am           |  14 ++
 fuse/main.c                | 205 ++++++++++++++++++
 fuse/namei.c               | 237 +++++++++++++++++++++
 fuse/namei.h               |  17 ++
 fuse/read.c                | 173 +++++++++++++++
 fuse/read.h                |  17 ++
 fuse/readir.c              | 121 +++++++++++
 fuse/readir.h              |  17 ++
 fuse/zmap.c                | 417 +++++++++++++++++++++++++++++++++++++
 include/erofs/decompress.h |  35 ++++
 include/erofs/defs.h       |  16 ++
 include/erofs/internal.h   | 104 +++++++++
 include/erofs/io.h         |   1 +
 include/erofs_fs.h         |   4 +
 lib/Makefile.am            |   4 +-
 lib/data.c                 | 117 +++++++++++
 lib/decompress.c           |  87 ++++++++
 lib/io.c                   |  16 ++
 lib/super.c                |  79 +++++++
 22 files changed, 1709 insertions(+), 5 deletions(-)
 create mode 100644 fuse/Makefile.am
 create mode 100644 fuse/main.c
 create mode 100644 fuse/namei.c
 create mode 100644 fuse/namei.h
 create mode 100644 fuse/read.c
 create mode 100644 fuse/read.h
 create mode 100644 fuse/readir.c
 create mode 100644 fuse/readir.h
 create mode 100644 fuse/zmap.c
 create mode 100644 include/erofs/decompress.h
 create mode 100644 lib/data.c
 create mode 100644 lib/decompress.c
 create mode 100644 lib/super.c

-- 
2.24.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 01/12] erofs-utils: introduce fuse implementation
  2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
@ 2020-11-02 15:55   ` Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 02/12] erofs-utils: fuse: add special file support Gao Xiang via Linux-erofs
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs; +Cc: Guo Weichao

From: Li Guifu <blucerlee@gmail.com>

Let's add erofsfuse approach, and benefits are:

 - images can be supported on various platforms;
 - new unpack tool can be developed based on this;
 - new on-disk features can be iterated, verified effectively.

This commit only aims at reading a regular file.
Other file (e.g. compressed file) support is out of scope for now.

Signed-off-by: Li Guifu <blucerlee@gmail.com>
Signed-off-by: Huang Jianan <huangjianan@oppo.com>
Signed-off-by: Guo Weichao <guoweichao@oppo.com>
Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 Makefile.am              |   2 +-
 README                   |  28 ++++-
 configure.ac             |   3 +-
 fuse/Makefile.am         |  14 +++
 fuse/dentry.c            | 130 ++++++++++++++++++++++
 fuse/dentry.h            |  42 ++++++++
 fuse/getattr.c           |  64 +++++++++++
 fuse/getattr.h           |  15 +++
 fuse/init.c              |  97 +++++++++++++++++
 fuse/init.h              |  22 ++++
 fuse/main.c              | 166 ++++++++++++++++++++++++++++
 fuse/namei.c             | 228 +++++++++++++++++++++++++++++++++++++++
 fuse/namei.h             |  22 ++++
 fuse/open.c              |  22 ++++
 fuse/open.h              |  15 +++
 fuse/read.c              | 113 +++++++++++++++++++
 fuse/read.h              |  16 +++
 fuse/readir.c            | 122 +++++++++++++++++++++
 fuse/readir.h            |  17 +++
 include/erofs/defs.h     |   3 +
 include/erofs/internal.h |  37 +++++++
 include/erofs/io.h       |   1 +
 lib/io.c                 |  16 +++
 23 files changed, 1192 insertions(+), 3 deletions(-)
 create mode 100644 fuse/Makefile.am
 create mode 100644 fuse/dentry.c
 create mode 100644 fuse/dentry.h
 create mode 100644 fuse/getattr.c
 create mode 100644 fuse/getattr.h
 create mode 100644 fuse/init.c
 create mode 100644 fuse/init.h
 create mode 100644 fuse/main.c
 create mode 100644 fuse/namei.c
 create mode 100644 fuse/namei.h
 create mode 100644 fuse/open.c
 create mode 100644 fuse/open.h
 create mode 100644 fuse/read.c
 create mode 100644 fuse/read.h
 create mode 100644 fuse/readir.c
 create mode 100644 fuse/readir.h

diff --git a/Makefile.am b/Makefile.am
index 1d20577068c5..24f4a7b3d5ad 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,4 +3,4 @@
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = man lib mkfs
+SUBDIRS = man lib mkfs fuse
diff --git a/README b/README
index 5addd6b80e04..870858c48b7d 100644
--- a/README
+++ b/README
@@ -2,7 +2,8 @@ erofs-utils
 ===========
 
 erofs-utils includes user-space tools for erofs filesystem images.
-Currently only mkfs.erofs is available.
+One is mkfs.erofs to create a image, the other is erofsfuse which
+is used to mount a image on a directory
 
 mkfs.erofs
 ----------
@@ -95,6 +96,31 @@ It may still be useful since new erofs-utils has not been widely used in
 commercial products. However, if that happens, please report bug to us
 as well.
 
+erofs-utils: erofsfuse
+----------------------
+erofsfuse mount a erofs filesystem image created by mkfs.erofs to a directory, and then
+It can be listed, read files and so on.
+
+Dependencies
+~~~~~~~~~~~~
+FUSE library version: 2.9.7
+fusermount version: 2.9.7
+using FUSE kernel interface version 7.19
+
+How to installed fuse
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+sudo apt-get update
+sudo apt-get install -y fuse libfuse-dev
+
+How to build erofsfuse
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	$ ./autogen.sh
+	$ ./configure
+	$ make
+
+erofsfuse binary will be generated under fuse folder.
+
 Contribution
 ------------
 
diff --git a/configure.ac b/configure.ac
index 0f40a840cf4f..4194a77f1e36 100644
--- a/configure.ac
+++ b/configure.ac
@@ -245,6 +245,7 @@ fi
 AC_CONFIG_FILES([Makefile
 		 man/Makefile
 		 lib/Makefile
-		 mkfs/Makefile])
+		 mkfs/Makefile
+		 fuse/Makefile])
 AC_OUTPUT
 
diff --git a/fuse/Makefile.am b/fuse/Makefile.am
new file mode 100644
index 000000000000..4921a4363cbb
--- /dev/null
+++ b/fuse/Makefile.am
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Makefile.am
+
+AUTOMAKE_OPTIONS = foreign
+bin_PROGRAMS     = erofsfuse
+erofsfuse_SOURCES = main.c dentry.c getattr.c namei.c read.c init.c open.c readir.c
+erofsfuse_CFLAGS = -Wall -Werror \
+                   -I$(top_srcdir)/include \
+                   $(shell pkg-config fuse --cflags) \
+                   -DFUSE_USE_VERSION=26 \
+                   -std=gnu99
+LDFLAGS += $(shell pkg-config fuse --libs)
+erofsfuse_LDADD = $(top_builddir)/lib/liberofs.la -ldl
+
diff --git a/fuse/dentry.c b/fuse/dentry.c
new file mode 100644
index 000000000000..0f722294d530
--- /dev/null
+++ b/fuse/dentry.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/fuse/dentry.c
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#include <stdlib.h>
+#include "dentry.h"
+#include "erofs/internal.h"
+#include "erofs/print.h"
+
+#define DCACHE_ENTRY_CALLOC()   calloc(1, sizeof(struct dcache_entry))
+#define DCACHE_ENTRY_LIFE       8
+
+struct dcache_entry root_entry;
+
+int dcache_init_root(uint32_t nid)
+{
+	if (root_entry.nid)
+		return -1;
+
+	/* Root entry doesn't need most of the fields. Namely, it only uses the
+	 * nid field and the subdirs pointer.
+	 */
+	erofs_info("Initializing root_entry dcache entry");
+	root_entry.nid = nid;
+	root_entry.subdirs = NULL;
+	root_entry.siblings = NULL;
+
+	return 0;
+}
+
+/* Inserts a node as a subdirs of a given parent. The parent is updated to
+ * point the newly inserted subdirs as the first subdirs. We return the new
+ * entry so that further entries can be inserted.
+ *
+ *      [0]                  [0]
+ *       /        ==>          \
+ *      /         ==>           \
+ * .->[1]->[2]-.       .->[1]->[3]->[2]-.
+ * `-----------麓       `----------------麓
+ */
+struct dcache_entry *dcache_insert(struct dcache_entry *parent,
+				   const char *name, int namelen, uint32_t nid)
+{
+	struct dcache_entry *new_entry;
+
+	erofs_dbg("Inserting %s,%d to dcache", name, namelen);
+
+	/* TODO: Deal with names that exceed the allocated size */
+	if (namelen + 1 > DCACHE_ENTRY_NAME_LEN)
+		return NULL;
+
+	if (parent == NULL)
+		parent = &root_entry;
+
+	new_entry = DCACHE_ENTRY_CALLOC();
+	if (!new_entry)
+		return NULL;
+
+	strncpy(new_entry->name, name, namelen);
+	new_entry->name[namelen] = 0;
+	new_entry->nid = nid;
+
+	if (!parent->subdirs) {
+		new_entry->siblings = new_entry;
+		parent->subdirs = new_entry;
+	} else {
+		new_entry->siblings = parent->subdirs->siblings;
+		parent->subdirs->siblings = new_entry;
+		parent->subdirs = new_entry;
+	}
+
+	return new_entry;
+}
+
+/* Lookup a cache entry for a given file name.  Return value is a struct pointer
+ * that can be used to both obtain the nid number and insert further child
+ * entries.
+ * TODO: Prune entries by using the LRU counter
+ */
+struct dcache_entry *dcache_lookup(struct dcache_entry *parent,
+				   const char *name, int namelen)
+{
+	struct dcache_entry *iter;
+
+	if (parent == NULL)
+		parent = &root_entry;
+
+	if (!parent->subdirs)
+		return NULL;
+
+	/* Iterate the list of siblings to see if there is any match */
+	iter = parent->subdirs;
+
+	do {
+		if (strncmp(iter->name, name, namelen) == 0 &&
+		    iter->name[namelen] == 0) {
+			parent->subdirs = iter;
+
+			return iter;
+		}
+
+		iter = iter->siblings;
+	} while (iter != parent->subdirs);
+
+	return NULL;
+}
+
+struct dcache_entry *dcache_try_insert(struct dcache_entry *parent,
+				   const char *name, int namelen, uint32_t nid)
+{
+	struct dcache_entry *d = dcache_lookup(parent, name, namelen);
+
+	if (d)
+		return d;
+
+	return dcache_insert(parent, name, namelen, nid);
+
+}
+erofs_nid_t dcache_get_nid(struct dcache_entry *entry)
+{
+	return entry ? entry->nid : root_entry.nid;
+}
+
+struct dcache_entry *dcache_root(void)
+{
+	return &root_entry;
+}
+
diff --git a/fuse/dentry.h b/fuse/dentry.h
new file mode 100644
index 000000000000..cb4d87972b2d
--- /dev/null
+++ b/fuse/dentry.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs-utils/fuse/dentry.h
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#ifndef _EROFS_DENTRY_H
+#define _EROFS_DENTRY_H
+
+#include <stdint.h>
+#include "erofs/internal.h"
+
+#ifdef __64BITS
+#define DCACHE_ENTRY_NAME_LEN       40
+#else
+#define DCACHE_ENTRY_NAME_LEN       48
+#endif
+
+/* This struct declares a node of a k-tree.  Every node has a pointer to one of
+ * the subdirs and a pointer (in a circular list fashion) to its siblings.
+ */
+
+struct dcache_entry {
+	struct dcache_entry *subdirs;
+	struct dcache_entry *siblings;
+	uint32_t nid;
+	uint16_t lru_count;
+	uint8_t user_count;
+	char name[DCACHE_ENTRY_NAME_LEN];
+};
+
+struct dcache_entry *dcache_insert(struct dcache_entry *parent,
+				   const char *name, int namelen, uint32_t n);
+struct dcache_entry *dcache_lookup(struct dcache_entry *parent,
+				   const char *name, int namelen);
+struct dcache_entry *dcache_try_insert(struct dcache_entry *parent,
+				       const char *name, int namelen,
+				       uint32_t nid);
+
+erofs_nid_t dcache_get_nid(struct dcache_entry *entry);
+int dcache_init_root(uint32_t n);
+#endif
diff --git a/fuse/getattr.c b/fuse/getattr.c
new file mode 100644
index 000000000000..8426145a9231
--- /dev/null
+++ b/fuse/getattr.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/fuse/getattr.c
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#include "getattr.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "erofs/defs.h"
+#include "erofs/internal.h"
+#include "erofs_fs.h"
+#include "erofs/print.h"
+
+#include "namei.h"
+
+extern struct erofs_super_block super;
+
+/* GNU's definitions of the attributes
+ * (http://www.gnu.org/software/libc/manual/html_node/Attribute-Meanings.html):
+ * st_uid: The user ID of the file鈥檚 owner.
+ * st_gid: The group ID of the file.
+ * st_atime: This is the last access time for the file.
+ * st_mtime: This is the time of the last modification to the contents of the
+ *           file.
+ * st_mode: Specifies the mode of the file. This includes file type information
+ *          (see Testing File Type) and the file permission bits (see Permission
+ *          Bits).
+ * st_nlink: The number of hard links to the file.This count keeps track of how
+ *           many directories have entries for this file. If the count is ever
+ *           decremented to zero, then the file itself is discarded as soon as
+ *           no process still holds it open. Symbolic links are not counted in
+ *           the total.
+ * st_size: This specifies the size of a regular file in bytes. For files that
+ *         are really devices this field isn鈥檛 usually meaningful.For symbolic
+ *         links this specifies the length of the file name the link refers to.
+ */
+int erofs_getattr(const char *path, struct stat *stbuf)
+{
+	struct erofs_vnode v;
+	int ret;
+
+	erofs_dbg("getattr(%s)", path);
+	memset(&v, 0, sizeof(v));
+	ret = erofs_iget_by_path(path, &v);
+	if (ret)
+		return -ENOENT;
+
+	stbuf->st_mode  = le16_to_cpu(v.i_mode);
+	stbuf->st_nlink = le16_to_cpu(v.i_nlink);
+	stbuf->st_size  = le32_to_cpu(v.i_size);
+	stbuf->st_blocks = stbuf->st_size / EROFS_BLKSIZ;
+	stbuf->st_uid = le16_to_cpu(v.i_uid);
+	stbuf->st_gid = le16_to_cpu(v.i_gid);
+	stbuf->st_atime = super.build_time;
+	stbuf->st_mtime = super.build_time;
+	stbuf->st_ctime = super.build_time;
+
+	return 0;
+}
diff --git a/fuse/getattr.h b/fuse/getattr.h
new file mode 100644
index 000000000000..735529a91d5b
--- /dev/null
+++ b/fuse/getattr.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs-utils/fuse/getattr.h
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#ifndef __EROFS_GETATTR_H
+#define __EROFS_GETATTR_H
+
+#include <fuse.h>
+#include <fuse_opt.h>
+
+int erofs_getattr(const char *path, struct stat *st);
+
+#endif
diff --git a/fuse/init.c b/fuse/init.c
new file mode 100644
index 000000000000..802771fc69a4
--- /dev/null
+++ b/fuse/init.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/fuse/init.c
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#include "init.h"
+#include <string.h>
+#include <stdlib.h>
+#include <asm-generic/errno-base.h>
+
+#include "namei.h"
+#include "erofs/io.h"
+#include "erofs/print.h"
+
+#define STR(_X) (#_X)
+#define SUPER_MEM(_X) (super._X)
+
+
+struct erofs_super_block super;
+static struct erofs_super_block *sbk = &super;
+
+int erofs_init_super(void)
+{
+	int ret;
+	char buf[EROFS_BLKSIZ];
+	struct erofs_super_block *sb;
+
+	memset(buf, 0, sizeof(buf));
+	ret = blk_read(buf, 0, 1);
+	if (ret < 0) {
+		erofs_err("Failed to read super block ret=%d", ret);
+		return -EINVAL;
+	}
+
+	sb = (struct erofs_super_block *) (buf + BOOT_SECTOR_SIZE);
+	sbk->magic = le32_to_cpu(sb->magic);
+	if (sbk->magic != EROFS_SUPER_MAGIC_V1) {
+		erofs_err("EROFS magic[0x%X] NOT matched to [0x%X] ",
+			  super.magic, EROFS_SUPER_MAGIC_V1);
+		return -EINVAL;
+	}
+
+	sbk->checksum = le32_to_cpu(sb->checksum);
+	sbk->feature_compat = le32_to_cpu(sb->feature_compat);
+	sbk->blkszbits = sb->blkszbits;
+
+	sbk->inos = le64_to_cpu(sb->inos);
+	sbk->build_time = le64_to_cpu(sb->build_time);
+	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);
+	sbk->xattr_blkaddr = le32_to_cpu(sb->xattr_blkaddr);
+	memcpy(sbk->uuid, sb->uuid, 16);
+	memcpy(sbk->volume_name, sb->volume_name, 16);
+	sbk->root_nid = le16_to_cpu(sb->root_nid);
+
+	erofs_dump("%-15s:0x%X\n", STR(magic), SUPER_MEM(magic));
+	erofs_dump("%-15s:0x%X\n", STR(feature_compat), SUPER_MEM(feature_compat));
+	erofs_dump("%-15s:%u\n",   STR(blkszbits), SUPER_MEM(blkszbits));
+	erofs_dump("%-15s:%u\n",   STR(root_nid), SUPER_MEM(root_nid));
+	erofs_dump("%-15s:%llu\n",  STR(inos), (unsigned long long)SUPER_MEM(inos));
+	erofs_dump("%-15s:%d\n",   STR(meta_blkaddr), SUPER_MEM(meta_blkaddr));
+	erofs_dump("%-15s:%d\n",   STR(xattr_blkaddr), SUPER_MEM(xattr_blkaddr));
+	return 0;
+}
+
+erofs_nid_t erofs_get_root_nid(void)
+{
+	return sbk->root_nid;
+}
+
+erofs_nid_t addr2nid(erofs_off_t addr)
+{
+	erofs_nid_t offset = (erofs_nid_t)sbk->meta_blkaddr * EROFS_BLKSIZ;
+
+	DBG_BUGON(!IS_SLOT_ALIGN(addr));
+	return (addr - offset) >> EROFS_ISLOTBITS;
+}
+
+erofs_off_t nid2addr(erofs_nid_t nid)
+{
+	erofs_off_t offset = (erofs_off_t)sbk->meta_blkaddr * EROFS_BLKSIZ;
+
+	return (nid <<  EROFS_ISLOTBITS) + offset;
+}
+
+void *erofs_init(struct fuse_conn_info *info)
+{
+	erofs_info("Using FUSE protocol %d.%d", info->proto_major, info->proto_minor);
+
+	if (inode_init(erofs_get_root_nid()) != 0) {
+		erofs_err("inode initialization failed");
+		abort();
+	}
+	return NULL;
+}
diff --git a/fuse/init.h b/fuse/init.h
new file mode 100644
index 000000000000..34085f2b548d
--- /dev/null
+++ b/fuse/init.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs-utils/fuse/init.h
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#ifndef __EROFS_INIT_H
+#define __EROFS_INIT_H
+
+#include <fuse.h>
+#include <fuse_opt.h>
+#include "erofs/internal.h"
+
+#define BOOT_SECTOR_SIZE	0x400
+
+int erofs_init_super(void);
+erofs_nid_t erofs_get_root_nid(void);
+erofs_off_t nid2addr(erofs_nid_t nid);
+erofs_nid_t addr2nid(erofs_off_t addr);
+void *erofs_init(struct fuse_conn_info *info);
+
+#endif
diff --git a/fuse/main.c b/fuse/main.c
new file mode 100644
index 000000000000..6fb3f3e42df3
--- /dev/null
+++ b/fuse/main.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/fuse/main.c
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <execinfo.h>
+#include <signal.h>
+#include <stddef.h>
+
+#include "erofs/print.h"
+#include "init.h"
+#include "read.h"
+#include "getattr.h"
+#include "open.h"
+#include "readir.h"
+#include "erofs/io.h"
+
+/* XXX: after liberofs is linked in, it should be removed */
+struct erofs_configure cfg;
+
+enum {
+	EROFS_OPT_HELP,
+	EROFS_OPT_VER,
+};
+
+struct options {
+	const char *disk;
+	const char *mount;
+	const char *logfile;
+	unsigned int debug_lvl;
+};
+static struct options fusecfg;
+
+#define OPTION(t, p)    { t, offsetof(struct options, p), 1 }
+
+static const struct fuse_opt option_spec[] = {
+	OPTION("--log=%s", logfile),
+	OPTION("--dbg=%u", debug_lvl),
+	FUSE_OPT_KEY("-h", EROFS_OPT_HELP),
+	FUSE_OPT_KEY("-v", EROFS_OPT_VER),
+	FUSE_OPT_END
+};
+
+static void usage(void)
+{
+	fprintf(stderr, "\terofsfuse [options] <image> <mountpoint>\n");
+	fprintf(stderr, "\t    --log=<file>    output log file\n");
+	fprintf(stderr, "\t    --dbg=<level>   log debug level 0 ~ 7\n");
+	fprintf(stderr, "\t    -h   show help\n");
+	fprintf(stderr, "\t    -v   show version\n");
+	exit(1);
+}
+
+static void dump_cfg(void)
+{
+	fprintf(stderr, "\tdisk :%s\n", fusecfg.disk);
+	fprintf(stderr, "\tmount:%s\n", fusecfg.mount);
+	fprintf(stderr, "\tdebug_lvl:%u\n", fusecfg.debug_lvl);
+	fprintf(stderr, "\tlogfile  :%s\n", fusecfg.logfile);
+}
+
+static int optional_opt_func(void *data, const char *arg, int key,
+			     struct fuse_args *outargs)
+{
+	UNUSED(data);
+	UNUSED(outargs);
+
+	switch (key) {
+	case FUSE_OPT_KEY_OPT:
+		return 1;
+
+	case FUSE_OPT_KEY_NONOPT:
+		if (!fusecfg.disk) {
+			fusecfg.disk = strdup(arg);
+			return 0;
+		} else if (!fusecfg.mount)
+			fusecfg.mount = strdup(arg);
+
+		return 1;
+	case EROFS_OPT_HELP:
+		usage();
+		break;
+
+	case EROFS_OPT_VER:
+		fprintf(stderr, "EROFS FUSE VERSION v 1.0.0\n");
+		exit(0);
+	}
+
+	return 1;
+}
+
+static void signal_handle_sigsegv(int signal)
+{
+	void *array[10];
+	size_t nptrs;
+	char **strings;
+	size_t i;
+
+	UNUSED(signal);
+	erofs_dbg("========================================");
+	erofs_dbg("Segmentation Fault.  Starting backtrace:");
+	nptrs = backtrace(array, 10);
+	strings = backtrace_symbols(array, nptrs);
+	if (strings) {
+		for (i = 0; i < nptrs; i++)
+			erofs_dbg("%s", strings[i]);
+		free(strings);
+	}
+	erofs_dbg("========================================");
+
+	abort();
+}
+
+static struct fuse_operations erofs_ops = {
+	.getattr = erofs_getattr,
+	.readdir = erofs_readdir,
+	.open = erofs_open,
+	.read = erofs_read,
+	.init = erofs_init,
+};
+
+int main(int argc, char *argv[])
+{
+	int ret = EXIT_FAILURE;
+	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+
+	if (signal(SIGSEGV, signal_handle_sigsegv) == SIG_ERR) {
+		fprintf(stderr, "Failed to initialize signals\n");
+		return EXIT_FAILURE;
+	}
+
+	/* Parse options */
+	if (fuse_opt_parse(&args, &fusecfg, option_spec, optional_opt_func) < 0)
+		return 1;
+
+	dump_cfg();
+
+	cfg.c_dbg_lvl = fusecfg.debug_lvl;
+
+	if (dev_open_ro(fusecfg.disk) < 0) {
+		fprintf(stderr, "Failed to open disk:%s\n", fusecfg.disk);
+		goto exit;
+	}
+
+	if (erofs_init_super()) {
+		fprintf(stderr, "Failed to read erofs super block\n");
+		goto exit_dev;
+	}
+
+	erofs_info("fuse start");
+
+	ret = fuse_main(args.argc, args.argv, &erofs_ops, NULL);
+
+	erofs_info("fuse done ret=%d", ret);
+
+exit_dev:
+	dev_close();
+exit:
+	fuse_opt_free_args(&args);
+	return ret;
+}
+
diff --git a/fuse/namei.c b/fuse/namei.c
new file mode 100644
index 000000000000..1564d5853fe6
--- /dev/null
+++ b/fuse/namei.c
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/fuse/namei.c
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#include "namei.h"
+#include <linux/kdev_t.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "erofs/defs.h"
+#include "erofs/print.h"
+#include "erofs/io.h"
+#include "dentry.h"
+#include "init.h"
+
+#define IS_PATH_SEPARATOR(__c)      ((__c) == '/')
+#define MINORBITS	20
+#define MINORMASK	((1U << MINORBITS) - 1)
+#define DT_UNKNOWN	0
+
+static const char *skip_trailing_backslash(const char *path)
+{
+	while (IS_PATH_SEPARATOR(*path))
+		path++;
+	return path;
+}
+
+static uint8_t get_path_token_len(const char *path)
+{
+	uint8_t len = 0;
+
+	while (path[len] != '/' && path[len])
+		len++;
+	return len;
+}
+
+int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *vi)
+{
+	int ret;
+	char buf[EROFS_BLKSIZ];
+	struct erofs_inode_compact *v1;
+	const erofs_off_t addr = nid2addr(nid);
+	const size_t size = EROFS_BLKSIZ - erofs_blkoff(addr);
+
+	ret = dev_read(buf, addr, size);
+	if (ret < 0)
+		return -EIO;
+
+	v1 = (struct erofs_inode_compact *)buf;
+	vi->datalayout = __inode_data_mapping(le16_to_cpu(v1->i_format));
+	vi->inode_isize = sizeof(struct erofs_inode_compact);
+	vi->xattr_isize = erofs_xattr_ibody_size(v1->i_xattr_icount);
+	vi->i_size = le32_to_cpu(v1->i_size);
+	vi->i_mode = le16_to_cpu(v1->i_mode);
+	vi->i_uid = le16_to_cpu(v1->i_uid);
+	vi->i_gid = le16_to_cpu(v1->i_gid);
+	vi->i_nlink = le16_to_cpu(v1->i_nlink);
+	vi->nid = nid;
+
+	switch (vi->i_mode & S_IFMT) {
+	case S_IFBLK:
+	case S_IFCHR:
+		/* fixme: add special devices support
+		 * vi->i_rdev = new_decode_dev(le32_to_cpu(v1->i_u.rdev));
+		 */
+		break;
+	case S_IFIFO:
+	case S_IFSOCK:
+		/*fixme: vi->i_rdev = 0; */
+		break;
+	case S_IFREG:
+	case S_IFLNK:
+	case S_IFDIR:
+		vi->raw_blkaddr = le32_to_cpu(v1->i_u.raw_blkaddr);
+		break;
+	default:
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/* dirent + name string */
+struct dcache_entry *list_name(const char *buf, struct dcache_entry *parent,
+				const char *name, unsigned int len,
+				uint32_t dirend)
+{
+	struct dcache_entry *entry = NULL;
+	struct erofs_dirent *ds, *de;
+
+	ds = (struct erofs_dirent *)buf;
+	de = (struct erofs_dirent *)(buf + le16_to_cpu(ds->nameoff));
+
+	while (ds < de) {
+		erofs_nid_t nid = le64_to_cpu(ds->nid);
+		uint16_t nameoff = le16_to_cpu(ds->nameoff);
+		char *d_name = (char *)(buf + nameoff);
+		uint16_t name_len = (ds + 1 >= de) ?
+			(uint16_t)strnlen(d_name, dirend - nameoff) :
+			le16_to_cpu(ds[1].nameoff) - nameoff;
+
+		#if defined(EROFS_DEBUG_ENTRY)
+		{
+			char debug[EROFS_BLKSIZ];
+
+			memcpy(debug, d_name, name_len);
+			debug[name_len] = '\0';
+			erofs_info("list entry: %s nid=%u", debug, nid);
+		}
+		#endif
+
+		entry = dcache_try_insert(parent, d_name, name_len, nid);
+		if (len == name_len && !memcmp(name, d_name, name_len))
+			return entry;
+
+		entry = NULL;
+		++ds;
+	}
+
+	return entry;
+}
+
+struct dcache_entry *disk_lookup(struct dcache_entry *parent, const char *name,
+		unsigned int name_len)
+{
+	int ret;
+	char buf[EROFS_BLKSIZ];
+	struct dcache_entry *entry = NULL;
+	struct erofs_vnode v;
+	uint32_t nr_cnt, dir_nr, dirsize, blkno;
+
+	ret = erofs_iget_by_nid(parent->nid, &v);
+	if (ret)
+		return NULL;
+
+	/* to check whether dirent is in the inline dirs */
+	blkno = v.raw_blkaddr;
+	dirsize = v.i_size;
+	dir_nr = erofs_blknr(dirsize);
+
+	nr_cnt = 0;
+	while (nr_cnt < dir_nr) {
+		ret = blk_read(buf, blkno + nr_cnt, 1);
+		if (ret < 0)
+			return NULL;
+
+		entry = list_name(buf, parent, name, name_len, EROFS_BLKSIZ);
+		if (entry)
+			goto next;
+
+		++nr_cnt;
+	}
+
+	if (v.datalayout == EROFS_INODE_FLAT_INLINE) {
+		uint32_t dir_off = erofs_blkoff(dirsize);
+		off_t dir_addr = nid2addr(dcache_get_nid(parent)) +
+			v.inode_isize + v.xattr_isize;
+
+		memset(buf, 0, sizeof(buf));
+		ret = dev_read(buf, dir_addr, dir_off);
+		if (ret < 0)
+			return NULL;
+
+		entry = list_name(buf, parent, name, name_len, dir_off);
+	}
+next:
+	return entry;
+}
+
+extern struct dcache_entry root_entry;
+int walk_path(const char *_path, erofs_nid_t *out_nid)
+{
+	struct dcache_entry *next, *ret;
+	const char *path = _path;
+
+	ret = next = &root_entry;
+	for (;;) {
+		uint8_t path_len;
+
+		path = skip_trailing_backslash(path);
+		path_len = get_path_token_len(path);
+		ret = next;
+		if (path_len == 0)
+			break;
+
+		next = dcache_lookup(ret, path, path_len);
+		if (!next) {
+			next = disk_lookup(ret, path, path_len);
+			if (!next)
+				return -ENOENT;
+		}
+
+		path += path_len;
+	}
+
+	if (!ret)
+		return -ENOENT;
+	erofs_dbg("find path = %s nid=%u", _path, ret->nid);
+
+	*out_nid = ret->nid;
+	return 0;
+
+}
+
+int erofs_iget_by_path(const char *path, struct erofs_vnode *v)
+{
+	int ret;
+	erofs_nid_t nid;
+
+	ret = walk_path(path, &nid);
+	if (ret)
+		return ret;
+
+	return erofs_iget_by_nid(nid, v);
+}
+
+int inode_init(erofs_nid_t root)
+{
+	dcache_init_root(root);
+
+	return 0;
+}
+
diff --git a/fuse/namei.h b/fuse/namei.h
new file mode 100644
index 000000000000..1803a673daaf
--- /dev/null
+++ b/fuse/namei.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs-utils/fuse/inode.h
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#ifndef __INODE_H
+#define __INODE_H
+
+#include "erofs/internal.h"
+#include "erofs_fs.h"
+
+int inode_init(erofs_nid_t root);
+struct dcache_entry *get_cached_dentry(struct dcache_entry **parent,
+				       const char **path);
+int erofs_iget_by_path(const char *path, struct erofs_vnode *v);
+int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *v);
+struct dcache_entry *disk_lookup(struct dcache_entry *parent, const char *name,
+		unsigned int name_len);
+int walk_path(const char *path, erofs_nid_t *out_nid);
+
+#endif
diff --git a/fuse/open.c b/fuse/open.c
new file mode 100644
index 000000000000..beb9a8615512
--- /dev/null
+++ b/fuse/open.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/fuse/open.c
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#include "open.h"
+#include <asm-generic/errno-base.h>
+#include <fuse.h>
+#include <fuse_opt.h>
+#include "erofs/print.h"
+
+int erofs_open(const char *path, struct fuse_file_info *fi)
+{
+	erofs_info("open path=%s", path);
+
+	if ((fi->flags & O_ACCMODE) != O_RDONLY)
+		return -EACCES;
+
+	return 0;
+}
+
diff --git a/fuse/open.h b/fuse/open.h
new file mode 100644
index 000000000000..dfc8b3cdd515
--- /dev/null
+++ b/fuse/open.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs-utils/fuse/open.h
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#ifndef __EROFS_OPEN_H
+#define __EROFS_OPEN_H
+
+#include <fuse.h>
+#include <fuse_opt.h>
+
+int erofs_open(const char *path, struct fuse_file_info *fi);
+
+#endif
diff --git a/fuse/read.c b/fuse/read.c
new file mode 100644
index 000000000000..58b23783d083
--- /dev/null
+++ b/fuse/read.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/fuse/read.c
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#include "read.h"
+#include <errno.h>
+#include <linux/fs.h>
+#include <sys/stat.h>
+#include <string.h>
+
+#include "erofs/defs.h"
+#include "erofs/internal.h"
+#include "erofs/print.h"
+#include "namei.h"
+#include "erofs/io.h"
+#include "init.h"
+
+size_t erofs_read_data(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;
+
+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 erofs_read(const char *path, char *buffer, size_t size, off_t offset,
+	       struct fuse_file_info *fi)
+{
+	int ret;
+	erofs_nid_t nid;
+	struct erofs_vnode v;
+
+	UNUSED(fi);
+	erofs_info("path:%s size=%zd offset=%llu", path, size, (long long)offset);
+
+	ret = walk_path(path, &nid);
+	if (ret)
+		return ret;
+
+	ret = erofs_iget_by_nid(nid, &v);
+	if (ret)
+		return ret;
+
+	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);
+
+	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
+	case EROFS_INODE_FLAT_COMPRESSION:
+		/* Fixme: */
+	default:
+		return -EINVAL;
+	}
+}
+
diff --git a/fuse/read.h b/fuse/read.h
new file mode 100644
index 000000000000..3f4af1495510
--- /dev/null
+++ b/fuse/read.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs-utils/fuse/read.h
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#ifndef __EROFS_READ_H
+#define __EROFS_READ_H
+
+#include <fuse.h>
+#include <fuse_opt.h>
+
+int erofs_read(const char *path, char *buffer, size_t size, off_t offset,
+	    struct fuse_file_info *fi);
+
+#endif
diff --git a/fuse/readir.c b/fuse/readir.c
new file mode 100644
index 000000000000..8111047803df
--- /dev/null
+++ b/fuse/readir.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/fuse/readir.c
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#include "readir.h"
+#include <errno.h>
+#include <linux/fs.h>
+#include <sys/stat.h>
+
+#include "erofs/defs.h"
+#include "erofs/internal.h"
+#include "erofs_fs.h"
+#include "namei.h"
+#include "erofs/io.h"
+#include "erofs/print.h"
+#include "init.h"
+
+erofs_nid_t split_entry(char *entry, off_t ofs, char *end, char *name,
+			uint32_t dirend)
+{
+	struct erofs_dirent *de = (struct erofs_dirent *)(entry + ofs);
+	uint16_t nameoff = le16_to_cpu(de->nameoff);
+	const char *de_name = entry + nameoff;
+	uint32_t de_namelen;
+
+	if ((void *)(de + 1) >= (void *)end)
+		de_namelen = strnlen(de_name, dirend - nameoff);
+	else
+		de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
+
+	memcpy(name, de_name, de_namelen);
+	name[de_namelen] = '\0';
+	return le64_to_cpu(de->nid);
+}
+
+int fill_dir(char *entrybuf, fuse_fill_dir_t filler, void *buf,
+	     uint32_t dirend)
+{
+	uint32_t ofs;
+	uint16_t nameoff;
+	char *end;
+	char name[EROFS_BLKSIZ];
+
+	nameoff = le16_to_cpu(((struct erofs_dirent *)entrybuf)->nameoff);
+	end = entrybuf + nameoff;
+	ofs = 0;
+	while (ofs < nameoff) {
+		(void)split_entry(entrybuf, ofs, end, name, dirend);
+		filler(buf, name, NULL, 0);
+		ofs += sizeof(struct erofs_dirent);
+	}
+
+	return 0;
+}
+
+/** Function to add an entry in a readdir() operation
+ *
+ * @param buf the buffer passed to the readdir() operation
+ * @param name the file name of the directory entry
+ * @param stat file attributes, can be NULL
+ * @param off offset of the next entry or zero
+ * @return 1 if buffer is full, zero otherwise
+ */
+int erofs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+		  off_t offset, struct fuse_file_info *fi)
+{
+	int ret;
+	erofs_nid_t nid;
+	struct erofs_vnode v;
+	char dirsbuf[EROFS_BLKSIZ];
+	uint32_t dir_nr, dir_off, nr_cnt;
+
+	erofs_dbg("readdir:%s offset=%llu", path, (long long)offset);
+	UNUSED(fi);
+
+	ret = walk_path(path, &nid);
+	if (ret)
+		return ret;
+
+	erofs_dbg("path=%s nid = %llu", path, (unsigned long long)nid);
+	ret = erofs_iget_by_nid(nid, &v);
+	if (ret)
+		return ret;
+
+	if (!S_ISDIR(v.i_mode))
+		return -ENOTDIR;
+
+	if (!v.i_size)
+		return 0;
+
+	dir_nr = erofs_blknr(v.i_size);
+	dir_off = erofs_blkoff(v.i_size);
+	nr_cnt = 0;
+
+	erofs_dbg("dir_size=%u dir_nr = %u dir_off=%u", v.i_size, dir_nr, dir_off);
+
+	while (nr_cnt < dir_nr) {
+		memset(dirsbuf, 0, sizeof(dirsbuf));
+		ret = blk_read(dirsbuf, v.raw_blkaddr + nr_cnt, 1);
+		if (ret < 0)
+			return -EIO;
+		fill_dir(dirsbuf, filler, buf, EROFS_BLKSIZ);
+		++nr_cnt;
+	}
+
+	if (v.datalayout == EROFS_INODE_FLAT_INLINE) {
+		off_t addr;
+
+		addr = nid2addr(nid) + v.inode_isize + v.xattr_isize;
+
+		memset(dirsbuf, 0, sizeof(dirsbuf));
+		ret = dev_read(dirsbuf, addr, dir_off);
+		if (ret < 0)
+			return -EIO;
+		fill_dir(dirsbuf, filler, buf, dir_off);
+	}
+
+	return 0;
+}
+
diff --git a/fuse/readir.h b/fuse/readir.h
new file mode 100644
index 000000000000..ee2ab8bdd0f0
--- /dev/null
+++ b/fuse/readir.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs-utils/fuse/readir.h
+ *
+ * Created by Li Guifu <blucerlee@gmail.com>
+ */
+#ifndef __EROFS_READDIR_H
+#define __EROFS_READDIR_H
+
+#include <fuse.h>
+#include <fuse_opt.h>
+
+int erofs_readdir(const char *path, void *buffer, fuse_fill_dir_t filler,
+	       off_t offset, struct fuse_file_info *fi);
+
+
+#endif
diff --git a/include/erofs/defs.h b/include/erofs/defs.h
index 8dee661ab9f0..e97de36aa04b 100644
--- a/include/erofs/defs.h
+++ b/include/erofs/defs.h
@@ -24,6 +24,9 @@
 #ifdef HAVE_LINUX_TYPES_H
 #include <linux/types.h>
 #endif
+#ifndef UNUSED
+#define UNUSED(_X)    ((void) _X)
+#endif
 
 /*
  * container_of - cast a member of a structure out to the containing structure
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index cabb2faa0072..1e3c23ae88b6 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -55,6 +55,8 @@ typedef u32 erofs_blk_t;
 #define blknr_to_addr(nr)       ((erofs_off_t)(nr) * EROFS_BLKSIZ)
 
 #define BLK_ROUND_UP(addr)	DIV_ROUND_UP(addr, EROFS_BLKSIZ)
+#define IS_SLOT_ALIGN(__ADDR)   (((__ADDR) % (EROFS_SLOTSIZE)) ? 0 : 1)
+#define IS_BLK_ALIGN(__ADDR)    (((__ADDR) % (EROFS_BLKSIZ)) ? 0 : 1)
 
 struct erofs_buffer_head;
 
@@ -132,11 +134,46 @@ struct erofs_inode {
 #endif
 };
 
+struct erofs_vnode {
+	uint8_t datalayout;
+
+	uint32_t i_size;
+	/* inline size in bytes */
+	uint16_t inode_isize;
+	uint16_t xattr_isize;
+
+	uint16_t xattr_shared_count;
+	char *xattr_shared_xattrs;
+
+	erofs_blk_t raw_blkaddr;
+	erofs_nid_t nid;
+	uint32_t i_ino;
+
+	uint16_t i_mode;
+	uint16_t i_uid;
+	uint16_t i_gid;
+	uint16_t i_nlink;
+
+	/* if file is inline read inline data witch inode */
+	char *idata;
+};
+
 static inline bool is_inode_layout_compression(struct erofs_inode *inode)
 {
 	return erofs_inode_is_data_compressed(inode->datalayout);
 }
 
+#define __inode_advise(x, bit, bits) \
+		(((x) >> (bit)) & ((1 << (bits)) - 1))
+
+#define __inode_version(advise)	\
+		__inode_advise(advise, EROFS_I_VERSION_BIT,	\
+			EROFS_I_VERSION_BITS)
+
+#define __inode_data_mapping(advise)	\
+	__inode_advise(advise, EROFS_I_DATALAYOUT_BIT,\
+		EROFS_I_DATALAYOUT_BITS)
+
 #define IS_ROOT(x)	((x) == (x)->i_parent)
 
 struct erofs_dentry {
diff --git a/include/erofs/io.h b/include/erofs/io.h
index a23de64541c6..557424578ece 100644
--- a/include/erofs/io.h
+++ b/include/erofs/io.h
@@ -17,6 +17,7 @@
 #endif
 
 int dev_open(const char *devname);
+int dev_open_ro(const char *dev);
 void dev_close(void);
 int dev_write(const void *buf, u64 offset, size_t len);
 int dev_read(void *buf, u64 offset, size_t len);
diff --git a/lib/io.c b/lib/io.c
index 4f5d9a6edaa4..d835f34da50f 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -108,6 +108,22 @@ int dev_open(const char *dev)
 	return 0;
 }
 
+/* XXX: temporary soluation. Disk I/O implementation needs to be refactored. */
+int dev_open_ro(const char *dev)
+{
+	int fd = open(dev, O_RDONLY | O_BINARY);
+
+	if (fd < 0) {
+		erofs_err("failed to open(%s).", dev);
+		return -errno;
+	}
+
+	erofs_devfd = fd;
+	erofs_devname = dev;
+	erofs_devsz = INT64_MAX;
+	return 0;
+}
+
 u64 dev_length(void)
 {
 	return erofs_devsz;
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 02/12] erofs-utils: fuse: add special file support
  2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 01/12] " Gao Xiang via Linux-erofs
@ 2020-11-02 15:55   ` Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 03/12] erofs-utils: fuse: add compressed " Gao Xiang via Linux-erofs
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs; +Cc: Guo Weichao

From: Huang Jianan <huangjianan@oppo.com>

Signed-off-by: Huang Jianan <huangjianan@oppo.com>
Signed-off-by: Guo Weichao <guoweichao@oppo.com>
Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/getattr.c           |  1 +
 fuse/main.c              |  1 +
 fuse/namei.c             | 14 ++++++++++----
 fuse/read.c              | 26 ++++++++++++++++++++++++++
 fuse/read.h              |  1 +
 include/erofs/internal.h |  1 +
 6 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/fuse/getattr.c b/fuse/getattr.c
index 8426145a9231..4c5991e7e487 100644
--- a/fuse/getattr.c
+++ b/fuse/getattr.c
@@ -56,6 +56,7 @@ int erofs_getattr(const char *path, struct stat *stbuf)
 	stbuf->st_blocks = stbuf->st_size / EROFS_BLKSIZ;
 	stbuf->st_uid = le16_to_cpu(v.i_uid);
 	stbuf->st_gid = le16_to_cpu(v.i_gid);
+	stbuf->st_rdev = le32_to_cpu(v.i_rdev);
 	stbuf->st_atime = super.build_time;
 	stbuf->st_mtime = super.build_time;
 	stbuf->st_ctime = super.build_time;
diff --git a/fuse/main.c b/fuse/main.c
index 6fb3f3e42df3..26f49f6fc299 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -116,6 +116,7 @@ static void signal_handle_sigsegv(int signal)
 }
 
 static struct fuse_operations erofs_ops = {
+	.readlink = erofs_readlink,
 	.getattr = erofs_getattr,
 	.readdir = erofs_readdir,
 	.open = erofs_open,
diff --git a/fuse/namei.c b/fuse/namei.c
index 1564d5853fe6..99e5ffa34858 100644
--- a/fuse/namei.c
+++ b/fuse/namei.c
@@ -11,6 +11,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <sys/stat.h>
+#include <sys/sysmacros.h>
 
 #include "erofs/defs.h"
 #include "erofs/print.h"
@@ -39,6 +40,13 @@ static uint8_t get_path_token_len(const char *path)
 	return len;
 }
 
+static inline dev_t new_decode_dev(u32 dev)
+{
+	unsigned major = (dev & 0xfff00) >> 8;
+	unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
+	return makedev(major, minor);
+}
+
 int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *vi)
 {
 	int ret;
@@ -65,13 +73,11 @@ int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *vi)
 	switch (vi->i_mode & S_IFMT) {
 	case S_IFBLK:
 	case S_IFCHR:
-		/* fixme: add special devices support
-		 * vi->i_rdev = new_decode_dev(le32_to_cpu(v1->i_u.rdev));
-		 */
+		vi->i_rdev = new_decode_dev(le32_to_cpu(v1->i_u.rdev));
 		break;
 	case S_IFIFO:
 	case S_IFSOCK:
-		/*fixme: vi->i_rdev = 0; */
+		vi->i_rdev = 0;
 		break;
 	case S_IFREG:
 	case S_IFLNK:
diff --git a/fuse/read.c b/fuse/read.c
index 58b23783d083..eb771c75baa7 100644
--- a/fuse/read.c
+++ b/fuse/read.c
@@ -111,3 +111,29 @@ int erofs_read(const char *path, char *buffer, size_t size, off_t offset,
 	}
 }
 
+int erofs_readlink(const char *path, char *buffer, size_t size)
+{
+	int ret;
+	erofs_nid_t nid;
+	size_t lnksz;
+	struct erofs_vnode v;
+
+	ret = walk_path(path, &nid);
+	if (ret)
+		return ret;
+
+	ret = erofs_iget_by_nid(nid, &v);
+	if (ret)
+		return ret;
+
+	lnksz = min((size_t)v.i_size, size - 1);
+
+	ret = erofs_read(path, buffer, lnksz, 0, NULL);
+	buffer[lnksz] = '\0';
+	if (ret != (int)lnksz)
+		return ret;
+
+	erofs_info("path:%s link=%s size=%llu", path, buffer, (unsigned long long)lnksz);
+	return 0;
+}
+
diff --git a/fuse/read.h b/fuse/read.h
index 3f4af1495510..e901c607dc91 100644
--- a/fuse/read.h
+++ b/fuse/read.h
@@ -12,5 +12,6 @@
 
 int erofs_read(const char *path, char *buffer, size_t size, off_t offset,
 	    struct fuse_file_info *fi);
+int erofs_readlink(const char *path, char *buffer, size_t size);
 
 #endif
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 1e3c23ae88b6..e2769a6be4c9 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -153,6 +153,7 @@ struct erofs_vnode {
 	uint16_t i_uid;
 	uint16_t i_gid;
 	uint16_t i_nlink;
+	uint32_t i_rdev;
 
 	/* if file is inline read inline data witch inode */
 	char *idata;
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 03/12] erofs-utils: fuse: add compressed file support
  2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 01/12] " Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 02/12] erofs-utils: fuse: add special file support Gao Xiang via Linux-erofs
@ 2020-11-02 15:55   ` Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 04/12] erofs-utils: fuse: refactor raw data logic Gao Xiang via Linux-erofs
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs; +Cc: Guo Weichao

From: Huang Jianan <huangjianan@oppo.com>

Signed-off-by: Huang Jianan <huangjianan@oppo.com>
Signed-off-by: Guo Weichao <guoweichao@oppo.com>
Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/Makefile.am           |   4 +-
 fuse/dentry.h              |   5 +-
 fuse/init.c                |  22 ++
 fuse/namei.c               |  11 +-
 fuse/read.c                |  77 ++++++-
 fuse/zmap.c                | 418 +++++++++++++++++++++++++++++++++++++
 include/erofs/decompress.h |  35 ++++
 include/erofs/defs.h       |  13 ++
 include/erofs/internal.h   |  43 +++-
 include/erofs_fs.h         |   4 +
 lib/Makefile.am            |   4 +-
 lib/decompress.c           |  87 ++++++++
 12 files changed, 714 insertions(+), 9 deletions(-)
 create mode 100644 fuse/zmap.c
 create mode 100644 include/erofs/decompress.h
 create mode 100644 lib/decompress.c

diff --git a/fuse/Makefile.am b/fuse/Makefile.am
index 4921a4363cbb..2b2608f57b03 100644
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -3,12 +3,12 @@
 
 AUTOMAKE_OPTIONS = foreign
 bin_PROGRAMS     = erofsfuse
-erofsfuse_SOURCES = main.c dentry.c getattr.c namei.c read.c init.c open.c readir.c
+erofsfuse_SOURCES = main.c dentry.c getattr.c namei.c read.c init.c open.c readir.c zmap.c
 erofsfuse_CFLAGS = -Wall -Werror \
                    -I$(top_srcdir)/include \
                    $(shell pkg-config fuse --cflags) \
                    -DFUSE_USE_VERSION=26 \
                    -std=gnu99
 LDFLAGS += $(shell pkg-config fuse --libs)
-erofsfuse_LDADD = $(top_builddir)/lib/liberofs.la -ldl
+erofsfuse_LDADD = $(top_builddir)/lib/liberofs.la -ldl ${LZ4_LIBS}
 
diff --git a/fuse/dentry.h b/fuse/dentry.h
index cb4d87972b2d..12f4cf6bafd9 100644
--- a/fuse/dentry.h
+++ b/fuse/dentry.h
@@ -10,10 +10,11 @@
 #include <stdint.h>
 #include "erofs/internal.h"
 
+/* fixme: Deal with names that exceed the allocated size */
 #ifdef __64BITS
-#define DCACHE_ENTRY_NAME_LEN       40
+#define DCACHE_ENTRY_NAME_LEN       EROFS_NAME_LEN
 #else
-#define DCACHE_ENTRY_NAME_LEN       48
+#define DCACHE_ENTRY_NAME_LEN       EROFS_NAME_LEN
 #endif
 
 /* This struct declares a node of a k-tree.  Every node has a pointer to one of
diff --git a/fuse/init.c b/fuse/init.c
index 802771fc69a4..c6a3af697532 100644
--- a/fuse/init.c
+++ b/fuse/init.c
@@ -18,7 +18,25 @@
 
 
 struct erofs_super_block super;
+/* XXX: sbk needs to be replaced with sbi */
 static struct erofs_super_block *sbk = &super;
+struct erofs_sb_info sbi;
+
+static bool check_layout_compatibility(struct erofs_sb_info *sbi,
+				       struct erofs_super_block *dsb)
+{
+	const unsigned int feature = le32_to_cpu(dsb->feature_incompat);
+
+	sbi->feature_incompat = feature;
+
+	/* check if current kernel meets all mandatory requirements */
+	if (feature & (~EROFS_ALL_FEATURE_INCOMPAT)) {
+		erofs_err("unidentified incompatible feature %x, please upgrade kernel version",
+			  feature & ~EROFS_ALL_FEATURE_INCOMPAT);
+		return false;
+	}
+	return true;
+}
 
 int erofs_init_super(void)
 {
@@ -41,6 +59,9 @@ int erofs_init_super(void)
 		return -EINVAL;
 	}
 
+	if (!check_layout_compatibility(&sbi, sb))
+		return -EINVAL;
+
 	sbk->checksum = le32_to_cpu(sb->checksum);
 	sbk->feature_compat = le32_to_cpu(sb->feature_compat);
 	sbk->blkszbits = sb->blkszbits;
@@ -56,6 +77,7 @@ int erofs_init_super(void)
 	sbk->root_nid = le16_to_cpu(sb->root_nid);
 
 	erofs_dump("%-15s:0x%X\n", STR(magic), SUPER_MEM(magic));
+	erofs_dump("%-15s:0x%X\n", STR(feature_incompat), sbi.feature_incompat);
 	erofs_dump("%-15s:0x%X\n", STR(feature_compat), SUPER_MEM(feature_compat));
 	erofs_dump("%-15s:%u\n",   STR(blkszbits), SUPER_MEM(blkszbits));
 	erofs_dump("%-15s:%u\n",   STR(root_nid), SUPER_MEM(root_nid));
diff --git a/fuse/namei.c b/fuse/namei.c
index 99e5ffa34858..79273f89be1b 100644
--- a/fuse/namei.c
+++ b/fuse/namei.c
@@ -49,7 +49,7 @@ static inline dev_t new_decode_dev(u32 dev)
 
 int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *vi)
 {
-	int ret;
+	int ret, ifmt;
 	char buf[EROFS_BLKSIZ];
 	struct erofs_inode_compact *v1;
 	const erofs_off_t addr = nid2addr(nid);
@@ -60,6 +60,11 @@ int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *vi)
 		return -EIO;
 
 	v1 = (struct erofs_inode_compact *)buf;
+	/* fixme: support extended inode */
+	ifmt = le16_to_cpu(v1->i_format);
+	if (__inode_version(ifmt) != EROFS_INODE_LAYOUT_COMPACT)
+		return -EOPNOTSUPP;
+
 	vi->datalayout = __inode_data_mapping(le16_to_cpu(v1->i_format));
 	vi->inode_isize = sizeof(struct erofs_inode_compact);
 	vi->xattr_isize = erofs_xattr_ibody_size(v1->i_xattr_icount);
@@ -88,6 +93,10 @@ int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *vi)
 		return -EIO;
 	}
 
+	vi->z_inited = false;
+	if (erofs_inode_is_data_compressed(vi->datalayout))
+		z_erofs_fill_inode(vi);
+
 	return 0;
 }
 
diff --git a/fuse/read.c b/fuse/read.c
index eb771c75baa7..11f7e6161f8f 100644
--- a/fuse/read.c
+++ b/fuse/read.c
@@ -3,6 +3,7 @@
  * erofs-utils/fuse/read.c
  *
  * Created by Li Guifu <blucerlee@gmail.com>
+ * Compression support by Huang Jianan <huangjianan@oppo.com>
  */
 #include "read.h"
 #include <errno.h>
@@ -16,6 +17,7 @@
 #include "namei.h"
 #include "erofs/io.h"
 #include "init.h"
+#include "erofs/decompress.h"
 
 size_t erofs_read_data(struct erofs_vnode *vnode, char *buffer,
 		       size_t size, off_t offset)
@@ -77,6 +79,78 @@ finished:
 
 }
 
+size_t erofs_read_data_compression(struct erofs_vnode *vnode, char *buffer,
+				   erofs_off_t size, erofs_off_t offset)
+{
+	int ret;
+	erofs_off_t end, length, skip;
+	struct erofs_map_blocks map = {
+		.index = UINT_MAX,
+	};
+	bool partial;
+	unsigned int algorithmformat;
+	char raw[EROFS_BLKSIZ];
+
+	end = offset + size;
+	while (end > offset) {
+		map.m_la = end - 1;
+
+		ret = z_erofs_map_blocks_iter(vnode, &map);
+		if (ret)
+			return ret;
+
+		if (!(map.m_flags & EROFS_MAP_MAPPED)) {
+			end = map.m_la;
+			continue;
+		}
+
+		ret = dev_read(raw, map.m_pa, EROFS_BLKSIZ);
+		if (ret < 0)
+			return -EIO;
+
+		algorithmformat = map.m_flags & EROFS_MAP_ZIPPED ?
+						Z_EROFS_COMPRESSION_LZ4 :
+						Z_EROFS_COMPRESSION_SHIFTED;
+
+		/*
+		 * trim to the needed size if the returned extent is quite
+		 * larger than requested, and set up partial flag as well.
+		 */
+		if (end < map.m_la + map.m_llen) {
+			length = end - map.m_la;
+			partial = true;
+		} else {
+			DBG_BUGON(end != map.m_la + map.m_llen);
+			length = map.m_llen;
+			partial = !(map.m_flags & EROFS_MAP_FULL_MAPPED);
+		}
+
+		if (map.m_la < offset) {
+			skip = offset - map.m_la;
+			end = offset;
+		} else {
+			skip = 0;
+			end = map.m_la;
+		}
+
+		ret = z_erofs_decompress(&(struct z_erofs_decompress_req) {
+					.in = raw,
+					.out = buffer + end - offset,
+					.decodedskip = skip,
+					.inputsize = map.m_plen,
+					.decodedlength = length,
+					.alg = algorithmformat,
+					.partial_decoding = partial
+					 });
+		if (ret < 0)
+			return ret;
+	}
+
+	erofs_info("nid:%llu size=%zd offset=%llu done",
+	     (unsigned long long)vnode->nid, size, (long long)offset);
+	return size;
+}
+
 int erofs_read(const char *path, char *buffer, size_t size, off_t offset,
 	       struct fuse_file_info *fi)
 {
@@ -105,7 +179,8 @@ int erofs_read(const char *path, char *buffer, size_t size, off_t offset,
 
 	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
 	case EROFS_INODE_FLAT_COMPRESSION:
-		/* Fixme: */
+		return erofs_read_data_compression(&v, buffer, size, offset);
+
 	default:
 		return -EINVAL;
 	}
diff --git a/fuse/zmap.c b/fuse/zmap.c
new file mode 100644
index 000000000000..9860b770362c
--- /dev/null
+++ b/fuse/zmap.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/fuse/zmap.c
+ *
+ * (a large amount of code was adapted from Linux kernel. )
+ *
+ * Copyright (C) 2018-2019 HUAWEI, Inc.
+ *             https://www.huawei.com/
+ * Created by Gao Xiang <gaoxiang25@huawei.com>
+ * Modified by Huang Jianan <huangjianan@oppo.com>
+ */
+#include "init.h"
+#include "erofs/io.h"
+#include "erofs/print.h"
+
+int z_erofs_fill_inode(struct erofs_vnode *vi)
+{
+	if (vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
+		vi->z_advise = 0;
+		vi->z_algorithmtype[0] = 0;
+		vi->z_algorithmtype[1] = 0;
+		vi->z_logical_clusterbits = LOG_BLOCK_SIZE;
+		vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits;
+		vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits;
+		vi->z_inited = true;
+	}
+
+	return 0;
+}
+
+static int z_erofs_fill_inode_lazy(struct erofs_vnode *vi)
+{
+	int ret;
+	erofs_off_t pos;
+	struct z_erofs_map_header *h;
+	char buf[8];
+
+	if (vi->z_inited)
+		return 0;
+
+	DBG_BUGON(vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
+
+	pos = round_up(nid2addr(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
+
+	ret = dev_read(buf, pos, 8);
+	if (ret < 0)
+		return -EIO;
+
+	h = (struct z_erofs_map_header *)buf;
+	vi->z_advise = le16_to_cpu(h->h_advise);
+	vi->z_algorithmtype[0] = h->h_algorithmtype & 15;
+	vi->z_algorithmtype[1] = h->h_algorithmtype >> 4;
+
+	if (vi->z_algorithmtype[0] >= Z_EROFS_COMPRESSION_MAX) {
+		erofs_err("unknown compression format %u for nid %llu",
+			  vi->z_algorithmtype[0], (unsigned long long)vi->nid);
+		return -EOPNOTSUPP;
+	}
+
+	vi->z_logical_clusterbits = LOG_BLOCK_SIZE + (h->h_clusterbits & 7);
+	vi->z_physical_clusterbits[0] = vi->z_logical_clusterbits +
+					((h->h_clusterbits >> 3) & 3);
+
+	if (vi->z_physical_clusterbits[0] != LOG_BLOCK_SIZE) {
+		erofs_err("unsupported physical clusterbits %u for nid %llu",
+			  vi->z_physical_clusterbits[0], (unsigned long long)vi->nid);
+		return -EOPNOTSUPP;
+	}
+
+	vi->z_physical_clusterbits[1] = vi->z_logical_clusterbits +
+					((h->h_clusterbits >> 5) & 7);
+	vi->z_inited = true;
+
+	return 0;
+}
+
+struct z_erofs_maprecorder {
+	struct erofs_vnode *vnode;
+	struct erofs_map_blocks *map;
+	void *kaddr;
+
+	unsigned long lcn;
+	/* compression extent information gathered */
+	u8  type;
+	u16 clusterofs;
+	u16 delta[2];
+	erofs_blk_t pblk;
+};
+
+static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
+				  erofs_blk_t eblk)
+{
+	int ret;
+	struct erofs_map_blocks *const map = m->map;
+	char *mpage = map->mpage;
+
+	if (map->index == eblk)
+		return 0;
+
+	ret = blk_read(mpage, eblk, 1);
+	if (ret < 0)
+		return -EIO;
+
+	map->index = eblk;
+
+	return 0;
+}
+
+static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+					 unsigned long lcn)
+{
+	struct erofs_vnode *const vi = m->vnode;
+	const erofs_off_t ibase = nid2addr(vi->nid);
+	const erofs_off_t pos =
+		Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize +
+					       vi->xattr_isize) +
+		lcn * sizeof(struct z_erofs_vle_decompressed_index);
+	struct z_erofs_vle_decompressed_index *di;
+	unsigned int advise, type;
+	int err;
+
+	err = z_erofs_reload_indexes(m, erofs_blknr(pos));
+	if (err)
+		return err;
+
+	m->lcn = lcn;
+	di = m->kaddr + erofs_blkoff(pos);
+
+	advise = le16_to_cpu(di->di_advise);
+	type = (advise >> Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT) &
+		((1 << Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS) - 1);
+	switch (type) {
+	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+		m->clusterofs = 1 << vi->z_logical_clusterbits;
+		m->delta[0] = le16_to_cpu(di->di_u.delta[0]);
+		m->delta[1] = le16_to_cpu(di->di_u.delta[1]);
+		break;
+	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+	case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+		m->clusterofs = le16_to_cpu(di->di_clusterofs);
+		m->pblk = le32_to_cpu(di->di_u.blkaddr);
+		break;
+	default:
+		DBG_BUGON(1);
+		return -EOPNOTSUPP;
+	}
+	m->type = type;
+	return 0;
+}
+
+static unsigned int decode_compactedbits(unsigned int lobits,
+					 unsigned int lomask,
+					 u8 *in, unsigned int pos, u8 *type)
+{
+	const unsigned int v = get_unaligned_le32(in + pos / 8) >> (pos & 7);
+	const unsigned int lo = v & lomask;
+
+	*type = (v >> lobits) & 3;
+	return lo;
+}
+
+static int unpack_compacted_index(struct z_erofs_maprecorder *m,
+				  unsigned int amortizedshift,
+				  unsigned int eofs)
+{
+	struct erofs_vnode *const vi = m->vnode;
+	const unsigned int lclusterbits = vi->z_logical_clusterbits;
+	const unsigned int lomask = (1 << lclusterbits) - 1;
+	unsigned int vcnt, base, lo, encodebits, nblk;
+	int i;
+	u8 *in, type;
+
+	if (1 << amortizedshift == 4)
+		vcnt = 2;
+	else if (1 << amortizedshift == 2 && lclusterbits == 12)
+		vcnt = 16;
+	else
+		return -EOPNOTSUPP;
+
+	encodebits = ((vcnt << amortizedshift) - sizeof(__le32)) * 8 / vcnt;
+	base = round_down(eofs, vcnt << amortizedshift);
+	in = m->kaddr + base;
+
+	i = (eofs - base) >> amortizedshift;
+
+	lo = decode_compactedbits(lclusterbits, lomask,
+				  in, encodebits * i, &type);
+	m->type = type;
+	if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
+		m->clusterofs = 1 << lclusterbits;
+		if (i + 1 != (int)vcnt) {
+			m->delta[0] = lo;
+			return 0;
+		}
+		/*
+		 * since the last lcluster in the pack is special,
+		 * of which lo saves delta[1] rather than delta[0].
+		 * Hence, get delta[0] by the previous lcluster indirectly.
+		 */
+		lo = decode_compactedbits(lclusterbits, lomask,
+					  in, encodebits * (i - 1), &type);
+		if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+			lo = 0;
+		m->delta[0] = lo + 1;
+		return 0;
+	}
+	m->clusterofs = lo;
+	m->delta[0] = 0;
+	/* figout out blkaddr (pblk) for HEAD lclusters */
+	nblk = 1;
+	while (i > 0) {
+		--i;
+		lo = decode_compactedbits(lclusterbits, lomask,
+					  in, encodebits * i, &type);
+		if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
+			i -= lo;
+
+		if (i >= 0)
+			++nblk;
+	}
+	in += (vcnt << amortizedshift) - sizeof(__le32);
+	m->pblk = le32_to_cpu(*(__le32 *)in) + nblk;
+	return 0;
+}
+
+static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+					    unsigned long lcn)
+{
+	struct erofs_vnode *const vi = m->vnode;
+	const unsigned int lclusterbits = vi->z_logical_clusterbits;
+	const erofs_off_t ebase = round_up(nid2addr(vi->nid) + vi->inode_isize +
+					   vi->xattr_isize, 8) +
+		sizeof(struct z_erofs_map_header);
+	const unsigned int totalidx = DIV_ROUND_UP(vi->i_size, EROFS_BLKSIZ);
+	unsigned int compacted_4b_initial, compacted_2b;
+	unsigned int amortizedshift;
+	erofs_off_t pos;
+	int err;
+
+	if (lclusterbits != 12)
+		return -EOPNOTSUPP;
+
+	if (lcn >= totalidx)
+		return -EINVAL;
+
+	m->lcn = lcn;
+	/* used to align to 32-byte (compacted_2b) alignment */
+	compacted_4b_initial = (32 - ebase % 32) / 4;
+	if (compacted_4b_initial == 32 / 4)
+		compacted_4b_initial = 0;
+
+	if (vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B)
+		compacted_2b = rounddown(totalidx - compacted_4b_initial, 16);
+	else
+		compacted_2b = 0;
+
+	pos = ebase;
+	if (lcn < compacted_4b_initial) {
+		amortizedshift = 2;
+		goto out;
+	}
+	pos += compacted_4b_initial * 4;
+	lcn -= compacted_4b_initial;
+
+	if (lcn < compacted_2b) {
+		amortizedshift = 1;
+		goto out;
+	}
+	pos += compacted_2b * 2;
+	lcn -= compacted_2b;
+	amortizedshift = 2;
+out:
+	pos += lcn * (1 << amortizedshift);
+	err = z_erofs_reload_indexes(m, erofs_blknr(pos));
+	if (err)
+		return err;
+	return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos));
+}
+
+static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+					  unsigned int lcn)
+{
+	const unsigned int datamode = m->vnode->datalayout;
+
+	if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY)
+		return legacy_load_cluster_from_disk(m, lcn);
+
+	if (datamode == EROFS_INODE_FLAT_COMPRESSION)
+		return compacted_load_cluster_from_disk(m, lcn);
+
+	return -EINVAL;
+}
+
+static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
+				   unsigned int lookback_distance)
+{
+	struct erofs_vnode *const vi = m->vnode;
+	struct erofs_map_blocks *const map = m->map;
+	const unsigned int lclusterbits = vi->z_logical_clusterbits;
+	unsigned long lcn = m->lcn;
+	int err;
+
+	if (lcn < lookback_distance) {
+		erofs_err("bogus lookback distance @ nid %llu",
+			  (unsigned long long)vi->nid);
+		DBG_BUGON(1);
+		return -EFSCORRUPTED;
+	}
+
+	/* load extent head logical cluster if needed */
+	lcn -= lookback_distance;
+	err = z_erofs_load_cluster_from_disk(m, lcn);
+	if (err)
+		return err;
+
+	switch (m->type) {
+	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+		if (!m->delta[0]) {
+			erofs_err("invalid lookback distance 0 @ nid %llu",
+				  (unsigned long long)vi->nid);
+			DBG_BUGON(1);
+			return -EFSCORRUPTED;
+		}
+		return z_erofs_extent_lookback(m, m->delta[0]);
+	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
+		map->m_flags &= ~EROFS_MAP_ZIPPED;
+	case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+		map->m_la = (lcn << lclusterbits) | m->clusterofs;
+		break;
+	default:
+		erofs_err("unknown type %u @ lcn %lu of nid %llu",
+			  m->type, lcn, (unsigned long long)vi->nid);
+		DBG_BUGON(1);
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+int z_erofs_map_blocks_iter(struct erofs_vnode *vi,
+			    struct erofs_map_blocks *map)
+{
+	struct z_erofs_maprecorder m = {
+		.vnode = vi,
+		.map = map,
+		.kaddr = map->mpage,
+	};
+	int err = 0;
+	unsigned int lclusterbits, endoff;
+	unsigned long long ofs, end;
+
+	/* when trying to read beyond EOF, leave it unmapped */
+	if (map->m_la >= vi->i_size) {
+		map->m_llen = map->m_la + 1 - vi->i_size;
+		map->m_la = vi->i_size;
+		map->m_flags = 0;
+		goto out;
+	}
+
+	err = z_erofs_fill_inode_lazy(vi);
+	if (err)
+		goto out;
+
+	lclusterbits = vi->z_logical_clusterbits;
+	ofs = map->m_la;
+	m.lcn = ofs >> lclusterbits;
+	endoff = ofs & ((1 << lclusterbits) - 1);
+
+	err = z_erofs_load_cluster_from_disk(&m, m.lcn);
+	if (err)
+		goto out;
+
+	map->m_flags = EROFS_MAP_ZIPPED;	/* by default, compressed */
+	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;
+	case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
+		if (endoff >= m.clusterofs) {
+			map->m_la = (m.lcn << lclusterbits) | m.clusterofs;
+			break;
+		}
+		/* m.lcn should be >= 1 if endoff < m.clusterofs */
+		if (!m.lcn) {
+			erofs_err("invalid logical cluster 0 at nid %llu",
+				  (unsigned long long)vi->nid);
+			err = -EFSCORRUPTED;
+			goto out;
+		}
+		end = (m.lcn << lclusterbits) | m.clusterofs;
+		map->m_flags |= EROFS_MAP_FULL_MAPPED;
+		m.delta[0] = 1;
+	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
+		/* get the correspoinding first chunk */
+		err = z_erofs_extent_lookback(&m, m.delta[0]);
+		if (err)
+			goto out;
+		break;
+	default:
+		erofs_err("unknown type %u @ offset %llu of nid %llu",
+			  m.type, ofs, (unsigned long long)vi->nid);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	map->m_llen = end - map->m_la;
+	map->m_plen = 1 << lclusterbits;
+	map->m_pa = blknr_to_addr(m.pblk);
+	map->m_flags |= EROFS_MAP_MAPPED;
+
+out:
+	erofs_dbg("m_la %" PRIu64 " m_pa %" PRIu64 " m_llen %" PRIu64 " m_plen %" PRIu64 " m_flags 0%o",
+		  map->m_la, map->m_pa,
+		  map->m_llen, map->m_plen, map->m_flags);
+
+	DBG_BUGON(err < 0 && err != -ENOMEM);
+	return err;
+}
diff --git a/include/erofs/decompress.h b/include/erofs/decompress.h
new file mode 100644
index 000000000000..beaac359b21f
--- /dev/null
+++ b/include/erofs/decompress.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * erofs-utils/include/erofs/decompress.h
+ *
+ * Copyright (C), 2008-2020, OPPO Mobile Comm Corp., Ltd.
+ * Created by Huang Jianan <huangjianan@oppo.com>
+ */
+#ifndef __EROFS_DECOMPRESS_H
+#define __EROFS_DECOMPRESS_H
+
+#include "internal.h"
+
+enum {
+	Z_EROFS_COMPRESSION_SHIFTED = Z_EROFS_COMPRESSION_MAX,
+	Z_EROFS_COMPRESSION_RUNTIME_MAX
+};
+
+struct z_erofs_decompress_req {
+	char *in, *out;
+
+	/*
+	 * initial decompressed bytes that need to be skipped
+	 * when finally copying to output buffer
+	 */
+	unsigned int decodedskip;
+	unsigned int inputsize, decodedlength;
+
+	/* indicate the algorithm will be used for decompression */
+	unsigned int alg;
+	bool partial_decoding;
+};
+
+int z_erofs_decompress(struct z_erofs_decompress_req *rq);
+
+#endif
diff --git a/include/erofs/defs.h b/include/erofs/defs.h
index e97de36aa04b..c42ca401a8ee 100644
--- a/include/erofs/defs.h
+++ b/include/erofs/defs.h
@@ -173,5 +173,18 @@ typedef int64_t         s64;
 #define __maybe_unused      __attribute__((__unused__))
 #endif
 
+struct __una_u32 { u32 x; } __packed;
+
+static inline u32 __get_unaligned_cpu32(const void *p)
+{
+	const struct __una_u32 *ptr = (const struct __una_u32 *)p;
+	return ptr->x;
+}
+
+static inline u32 get_unaligned_le32(const void *p)
+{
+	return __get_unaligned_cpu32((const u8 *)p);
+}
+
 #endif
 
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index e2769a6be4c9..6c5fbd3c5d3c 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -36,6 +36,8 @@ typedef unsigned short umode_t;
 #error incompatible PAGE_SIZE is already defined
 #endif
 
+#define PAGE_MASK		(~(PAGE_SIZE-1))
+
 #define LOG_BLOCK_SIZE          (12)
 #define EROFS_BLKSIZ            (1U << LOG_BLOCK_SIZE)
 
@@ -145,7 +147,15 @@ struct erofs_vnode {
 	uint16_t xattr_shared_count;
 	char *xattr_shared_xattrs;
 
-	erofs_blk_t raw_blkaddr;
+	union {
+		erofs_blk_t raw_blkaddr;
+		struct {
+			uint16_t z_advise;
+			uint8_t  z_algorithmtype[2];
+			uint8_t  z_logical_clusterbits;
+			uint8_t  z_physical_clusterbits[2];
+		};
+	};
 	erofs_nid_t nid;
 	uint32_t i_ino;
 
@@ -155,6 +165,7 @@ struct erofs_vnode {
 	uint16_t i_nlink;
 	uint32_t i_rdev;
 
+	bool z_inited;
 	/* if file is inline read inline data witch inode */
 	char *idata;
 };
@@ -207,5 +218,35 @@ static inline const char *erofs_strerror(int err)
 	return msg;
 }
 
+enum {
+	BH_Mapped ,
+	BH_Zipped ,
+	BH_FullMapped,
+};
+
+/* Has a disk mapping */
+#define EROFS_MAP_MAPPED	(1 << BH_Mapped)
+/* The extent has been compressed */
+#define EROFS_MAP_ZIPPED	(1 << BH_Zipped)
+/* The length of extent is full */
+#define EROFS_MAP_FULL_MAPPED	(1 << BH_FullMapped)
+
+struct erofs_map_blocks {
+	char mpage[EROFS_BLKSIZ];
+
+	erofs_off_t m_pa, m_la;
+	u64 m_plen, m_llen;
+
+	unsigned int m_flags;
+	erofs_blk_t index;
+};
+
+/* zmap.c */
+int z_erofs_fill_inode(struct erofs_vnode *vi);
+int z_erofs_map_blocks_iter(struct erofs_vnode *vi,
+			    struct erofs_map_blocks *map);
+
+#define EFSCORRUPTED    EUCLEAN         /* Filesystem is corrupted */
+
 #endif
 
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index 4cd79f01d820..a69f179a51a5 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -279,6 +279,10 @@ struct z_erofs_vle_decompressed_index {
 	} di_u;
 };
 
+#define Z_EROFS_VLE_LEGACY_INDEX_ALIGN(size) \
+	(round_up(size, sizeof(struct z_erofs_vle_decompressed_index)) + \
+	 sizeof(struct z_erofs_map_header) + Z_EROFS_VLE_LEGACY_HEADER_PADDING)
+
 #define Z_EROFS_VLE_EXTENT_ALIGN(size) round_up(size, \
 	sizeof(struct z_erofs_vle_decompressed_index))
 
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e4b51e65f053..c921a62a8b23 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -2,8 +2,8 @@
 # Makefile.am
 
 noinst_LTLIBRARIES = liberofs.la
-liberofs_la_SOURCES = config.c io.c cache.c inode.c xattr.c \
-		      compress.c compressor.c exclude.c
+liberofs_la_SOURCES = config.c io.c cache.c inode.c xattr.c exclude.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/decompress.c b/lib/decompress.c
new file mode 100644
index 000000000000..870b85430dd1
--- /dev/null
+++ b/lib/decompress.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * erofs-utils/lib/decompress.c
+ *
+ * Copyright (C), 2008-2020, OPPO Mobile Comm Corp., Ltd.
+ * Created by Huang Jianan <huangjianan@oppo.com>
+ */
+#include <stdlib.h>
+#include <lz4.h>
+
+#include "erofs/decompress.h"
+#include "erofs/err.h"
+
+#ifdef LZ4_ENABLED
+static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
+{
+	int ret = 0;
+	char *dest = rq->out;
+	char *src = rq->in;
+	char *buff = NULL;
+	bool support_0padding = false;
+	unsigned int inputmargin = 0;
+
+	if (erofs_sb_has_lz4_0padding()) {
+		support_0padding = true;
+
+		while (!src[inputmargin & ~PAGE_MASK])
+			if (!(++inputmargin & ~PAGE_MASK))
+				break;
+
+		if (inputmargin >= rq->inputsize)
+			return -EIO;
+	}
+
+	if (rq->decodedskip) {
+		buff = malloc(rq->decodedlength);
+		if (!buff)
+			return -ENOMEM;
+		dest = buff;
+	}
+
+	if (rq->partial_decoding || !support_0padding)
+		ret = LZ4_decompress_safe_partial(src + inputmargin, dest,
+				rq->inputsize - inputmargin,
+				rq->decodedlength, rq->decodedlength);
+	else
+		ret = LZ4_decompress_safe(src + inputmargin, dest,
+					  rq->inputsize - inputmargin,
+					  rq->decodedlength);
+
+	if (ret != (int)rq->decodedlength) {
+		ret = -EIO;
+		goto out;
+	}
+
+	if (rq->decodedskip)
+		memcpy(rq->out, dest + rq->decodedskip,
+		       rq->decodedlength - rq->decodedskip);
+
+out:
+	if (buff)
+		free(buff);
+
+	return ret;
+}
+#endif
+
+int z_erofs_decompress(struct z_erofs_decompress_req *rq)
+{
+	if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
+		if (rq->inputsize != EROFS_BLKSIZ)
+			return -EFSCORRUPTED;
+
+		DBG_BUGON(rq->decodedlength > EROFS_BLKSIZ);
+		DBG_BUGON(rq->decodedlength < rq->decodedskip);
+
+		memcpy(rq->out, rq->in + rq->decodedskip,
+		       rq->decodedlength - rq->decodedskip);
+		return 0;
+	}
+
+#ifdef LZ4_ENABLED
+	if (rq->alg == Z_EROFS_COMPRESSION_LZ4)
+		return z_erofs_decompress_lz4(rq);
+#endif
+	return -EOPNOTSUPP;
+}
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 04/12] erofs-utils: fuse: refactor raw data logic
  2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
                     ` (2 preceding siblings ...)
  2020-11-02 15:55   ` [WIP] [PATCH v3 03/12] erofs-utils: fuse: add compressed " Gao Xiang via Linux-erofs
@ 2020-11-02 15:55   ` Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 05/12] erofs-utils: fuse: kill sbk Gao Xiang via Linux-erofs
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs

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

Signed-off-by: Gao Xiang <hsiangkao@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@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


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 05/12] erofs-utils: fuse: kill sbk
  2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
                     ` (3 preceding siblings ...)
  2020-11-02 15:55   ` [WIP] [PATCH v3 04/12] erofs-utils: fuse: refactor raw data logic Gao Xiang via Linux-erofs
@ 2020-11-02 15:55   ` Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 06/12] erofs-utils: fuse: kill nid2addr, addr2nid Gao Xiang via Linux-erofs
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs

(will fold into the original patch.)

Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/init.c              | 78 +++++++++++++++++++---------------------
 fuse/init.h              |  2 +-
 fuse/main.c              |  2 +-
 include/erofs/internal.h |  7 ++++
 4 files changed, 45 insertions(+), 44 deletions(-)

diff --git a/fuse/init.c b/fuse/init.c
index 09e7b1210006..f3f7f9750468 100644
--- a/fuse/init.c
+++ b/fuse/init.c
@@ -18,8 +18,6 @@
 
 
 struct erofs_super_block super;
-/* XXX: sbk needs to be replaced with sbi */
-static struct erofs_super_block *sbk = &super;
 struct erofs_sb_info sbi;
 
 static bool check_layout_compatibility(struct erofs_sb_info *sbi,
@@ -38,65 +36,61 @@ static bool check_layout_compatibility(struct erofs_sb_info *sbi,
 	return true;
 }
 
-int erofs_init_super(void)
+int erofs_read_superblock(void)
 {
+	char data[EROFS_BLKSIZ];
+	struct erofs_super_block *dsb;
+	unsigned int blkszbits;
 	int ret;
-	char buf[EROFS_BLKSIZ];
-	struct erofs_super_block *sb;
 
-	memset(buf, 0, sizeof(buf));
-	ret = blk_read(buf, 0, 1);
+	ret = blk_read(data, 0, 1);
 	if (ret < 0) {
-		erofs_err("Failed to read super block ret=%d", ret);
-		return -EINVAL;
+		erofs_err("cannot read erofs superblock: %d", ret);
+		return -EIO;
 	}
+	dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
 
-	sb = (struct erofs_super_block *) (buf + BOOT_SECTOR_SIZE);
-	sbk->magic = le32_to_cpu(sb->magic);
-	if (sbk->magic != EROFS_SUPER_MAGIC_V1) {
-		erofs_err("EROFS magic[0x%X] NOT matched to [0x%X] ",
-			  super.magic, EROFS_SUPER_MAGIC_V1);
-		return -EINVAL;
+	ret = -EINVAL;
+	if (le32_to_cpu(dsb->magic) != EROFS_SUPER_MAGIC_V1) {
+		erofs_err("cannot find valid erofs superblock");
+		return ret;
 	}
 
-	if (!check_layout_compatibility(&sbi, sb))
-		return -EINVAL;
+	sbi.feature_compat = le32_to_cpu(dsb->feature_compat);
 
-	sbk->checksum = le32_to_cpu(sb->checksum);
-	sbk->feature_compat = le32_to_cpu(sb->feature_compat);
-	sbk->blkszbits = sb->blkszbits;
+	blkszbits = dsb->blkszbits;
+	/* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */
+	if (blkszbits != LOG_BLOCK_SIZE) {
+		erofs_err("blksize %u isn't supported on this platform",
+			  1 << blkszbits);
+		return ret;
+	}
+
+	if (!check_layout_compatibility(&sbi, dsb))
+		return ret;
 
-	sbk->inos = le64_to_cpu(sb->inos);
-	sbk->build_time = le64_to_cpu(sb->build_time);
-	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.blocks = le32_to_cpu(dsb->blocks);
+	sbi.meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
+	sbi.xattr_blkaddr = le32_to_cpu(dsb->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);
-
-	erofs_dump("%-15s:0x%X\n", STR(magic), SUPER_MEM(magic));
-	erofs_dump("%-15s:0x%X\n", STR(feature_incompat), sbi.feature_incompat);
-	erofs_dump("%-15s:0x%X\n", STR(feature_compat), SUPER_MEM(feature_compat));
-	erofs_dump("%-15s:%u\n",   STR(blkszbits), SUPER_MEM(blkszbits));
-	erofs_dump("%-15s:%u\n",   STR(root_nid), SUPER_MEM(root_nid));
-	erofs_dump("%-15s:%llu\n",  STR(inos), (unsigned long long)SUPER_MEM(inos));
-	erofs_dump("%-15s:%d\n",   STR(meta_blkaddr), SUPER_MEM(meta_blkaddr));
-	erofs_dump("%-15s:%d\n",   STR(xattr_blkaddr), SUPER_MEM(xattr_blkaddr));
+	sbi.root_nid = le16_to_cpu(dsb->root_nid);
+	sbi.inos = le64_to_cpu(dsb->inos);
+
+	sbi.build_time = le64_to_cpu(dsb->build_time);
+	sbi.build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
+
+	memcpy(&sbi.uuid, dsb->uuid, sizeof(dsb->uuid));
 	return 0;
 }
 
 erofs_nid_t erofs_get_root_nid(void)
 {
-	return sbk->root_nid;
+	return sbi.root_nid;
 }
 
 erofs_nid_t addr2nid(erofs_off_t addr)
 {
-	erofs_nid_t offset = (erofs_nid_t)sbk->meta_blkaddr * EROFS_BLKSIZ;
+	erofs_nid_t offset = (erofs_nid_t)sbi.meta_blkaddr * EROFS_BLKSIZ;
 
 	DBG_BUGON(!IS_SLOT_ALIGN(addr));
 	return (addr - offset) >> EROFS_ISLOTBITS;
@@ -104,7 +98,7 @@ erofs_nid_t addr2nid(erofs_off_t addr)
 
 erofs_off_t nid2addr(erofs_nid_t nid)
 {
-	erofs_off_t offset = (erofs_off_t)sbk->meta_blkaddr * EROFS_BLKSIZ;
+	erofs_off_t offset = (erofs_off_t)sbi.meta_blkaddr * EROFS_BLKSIZ;
 
 	return (nid <<  EROFS_ISLOTBITS) + offset;
 }
diff --git a/fuse/init.h b/fuse/init.h
index 34085f2b548d..062cd69f6e4d 100644
--- a/fuse/init.h
+++ b/fuse/init.h
@@ -13,7 +13,7 @@
 
 #define BOOT_SECTOR_SIZE	0x400
 
-int erofs_init_super(void);
+int erofs_read_superblock(void);
 erofs_nid_t erofs_get_root_nid(void);
 erofs_off_t nid2addr(erofs_nid_t nid);
 erofs_nid_t addr2nid(erofs_off_t addr);
diff --git a/fuse/main.c b/fuse/main.c
index 26f49f6fc299..fed4488081d8 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -147,7 +147,7 @@ int main(int argc, char *argv[])
 		goto exit;
 	}
 
-	if (erofs_init_super()) {
+	if (erofs_read_superblock()) {
 		fprintf(stderr, "Failed to read erofs super block\n");
 		goto exit_dev;
 	}
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 54038071bf84..306005dea2a7 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -63,6 +63,8 @@ typedef u32 erofs_blk_t;
 struct erofs_buffer_head;
 
 struct erofs_sb_info {
+	u64 blocks;
+
 	erofs_blk_t meta_blkaddr;
 	erofs_blk_t xattr_blkaddr;
 
@@ -73,6 +75,11 @@ struct erofs_sb_info {
 
 	unsigned char islotbits;
 
+	/* what we really care is nid, rather than ino.. */
+	erofs_nid_t root_nid;
+	/* used for statfs, f_files - f_favail */
+	u64 inos;
+
 	u8 uuid[16];
 };
 
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 06/12] erofs-utils: fuse: kill nid2addr, addr2nid
  2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
                     ` (4 preceding siblings ...)
  2020-11-02 15:55   ` [WIP] [PATCH v3 05/12] erofs-utils: fuse: kill sbk Gao Xiang via Linux-erofs
@ 2020-11-02 15:55   ` Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 07/12] erofs-utils: fuse: kill erofs_get_root_nid() Gao Xiang via Linux-erofs
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs

(will fold into the original patch.)

Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/init.c   | 15 ---------------
 fuse/init.h   |  2 --
 fuse/namei.c  |  4 ++--
 fuse/readir.c |  2 +-
 fuse/zmap.c   |  6 +++---
 5 files changed, 6 insertions(+), 23 deletions(-)

diff --git a/fuse/init.c b/fuse/init.c
index f3f7f9750468..b4089a204409 100644
--- a/fuse/init.c
+++ b/fuse/init.c
@@ -88,21 +88,6 @@ erofs_nid_t erofs_get_root_nid(void)
 	return sbi.root_nid;
 }
 
-erofs_nid_t addr2nid(erofs_off_t addr)
-{
-	erofs_nid_t offset = (erofs_nid_t)sbi.meta_blkaddr * EROFS_BLKSIZ;
-
-	DBG_BUGON(!IS_SLOT_ALIGN(addr));
-	return (addr - offset) >> EROFS_ISLOTBITS;
-}
-
-erofs_off_t nid2addr(erofs_nid_t nid)
-{
-	erofs_off_t offset = (erofs_off_t)sbi.meta_blkaddr * EROFS_BLKSIZ;
-
-	return (nid <<  EROFS_ISLOTBITS) + offset;
-}
-
 void *erofs_init(struct fuse_conn_info *info)
 {
 	erofs_info("Using FUSE protocol %d.%d", info->proto_major, info->proto_minor);
diff --git a/fuse/init.h b/fuse/init.h
index 062cd69f6e4d..4bd48d18b003 100644
--- a/fuse/init.h
+++ b/fuse/init.h
@@ -15,8 +15,6 @@
 
 int erofs_read_superblock(void);
 erofs_nid_t erofs_get_root_nid(void);
-erofs_off_t nid2addr(erofs_nid_t nid);
-erofs_nid_t addr2nid(erofs_off_t addr);
 void *erofs_init(struct fuse_conn_info *info);
 
 #endif
diff --git a/fuse/namei.c b/fuse/namei.c
index 79273f89be1b..c3766f9a9f02 100644
--- a/fuse/namei.c
+++ b/fuse/namei.c
@@ -52,7 +52,7 @@ int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *vi)
 	int ret, ifmt;
 	char buf[EROFS_BLKSIZ];
 	struct erofs_inode_compact *v1;
-	const erofs_off_t addr = nid2addr(nid);
+	const erofs_off_t addr = iloc(nid);
 	const size_t size = EROFS_BLKSIZ - erofs_blkoff(addr);
 
 	ret = dev_read(buf, addr, size);
@@ -173,7 +173,7 @@ struct dcache_entry *disk_lookup(struct dcache_entry *parent, const char *name,
 
 	if (v.datalayout == EROFS_INODE_FLAT_INLINE) {
 		uint32_t dir_off = erofs_blkoff(dirsize);
-		off_t dir_addr = nid2addr(dcache_get_nid(parent)) +
+		off_t dir_addr = iloc(dcache_get_nid(parent)) +
 			v.inode_isize + v.xattr_isize;
 
 		memset(buf, 0, sizeof(buf));
diff --git a/fuse/readir.c b/fuse/readir.c
index 8111047803df..496f4e73a9c2 100644
--- a/fuse/readir.c
+++ b/fuse/readir.c
@@ -108,7 +108,7 @@ int erofs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 	if (v.datalayout == EROFS_INODE_FLAT_INLINE) {
 		off_t addr;
 
-		addr = nid2addr(nid) + v.inode_isize + v.xattr_isize;
+		addr = iloc(nid) + v.inode_isize + v.xattr_isize;
 
 		memset(dirsbuf, 0, sizeof(dirsbuf));
 		ret = dev_read(dirsbuf, addr, dir_off);
diff --git a/fuse/zmap.c b/fuse/zmap.c
index 9860b770362c..cb667da4e0c8 100644
--- a/fuse/zmap.c
+++ b/fuse/zmap.c
@@ -40,7 +40,7 @@ static int z_erofs_fill_inode_lazy(struct erofs_vnode *vi)
 
 	DBG_BUGON(vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
 
-	pos = round_up(nid2addr(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
+	pos = round_up(iloc(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
 
 	ret = dev_read(buf, pos, 8);
 	if (ret < 0)
@@ -110,7 +110,7 @@ static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
 					 unsigned long lcn)
 {
 	struct erofs_vnode *const vi = m->vnode;
-	const erofs_off_t ibase = nid2addr(vi->nid);
+	const erofs_off_t ibase = iloc(vi->nid);
 	const erofs_off_t pos =
 		Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize +
 					       vi->xattr_isize) +
@@ -228,7 +228,7 @@ static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
 {
 	struct erofs_vnode *const vi = m->vnode;
 	const unsigned int lclusterbits = vi->z_logical_clusterbits;
-	const erofs_off_t ebase = round_up(nid2addr(vi->nid) + vi->inode_isize +
+	const erofs_off_t ebase = round_up(iloc(vi->nid) + vi->inode_isize +
 					   vi->xattr_isize, 8) +
 		sizeof(struct z_erofs_map_header);
 	const unsigned int totalidx = DIV_ROUND_UP(vi->i_size, EROFS_BLKSIZ);
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 07/12] erofs-utils: fuse: kill erofs_get_root_nid()
  2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
                     ` (5 preceding siblings ...)
  2020-11-02 15:55   ` [WIP] [PATCH v3 06/12] erofs-utils: fuse: kill nid2addr, addr2nid Gao Xiang via Linux-erofs
@ 2020-11-02 15:55   ` Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 08/12] erofs-utils: fuse: move erofs_init() to main.c Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 09/12] erofs-utils: fuse: move superblock logic into lib/ Gao Xiang via Linux-erofs
  8 siblings, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs

(will fold into the original patch.)

Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/init.c | 7 +------
 fuse/init.h | 1 -
 2 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/fuse/init.c b/fuse/init.c
index b4089a204409..d67c7f0dd298 100644
--- a/fuse/init.c
+++ b/fuse/init.c
@@ -83,16 +83,11 @@ int erofs_read_superblock(void)
 	return 0;
 }
 
-erofs_nid_t erofs_get_root_nid(void)
-{
-	return sbi.root_nid;
-}
-
 void *erofs_init(struct fuse_conn_info *info)
 {
 	erofs_info("Using FUSE protocol %d.%d", info->proto_major, info->proto_minor);
 
-	if (inode_init(erofs_get_root_nid()) != 0) {
+	if (inode_init(sbi.root_nid) != 0) {
 		erofs_err("inode initialization failed");
 		abort();
 	}
diff --git a/fuse/init.h b/fuse/init.h
index 4bd48d18b003..f0211707b5ff 100644
--- a/fuse/init.h
+++ b/fuse/init.h
@@ -14,7 +14,6 @@
 #define BOOT_SECTOR_SIZE	0x400
 
 int erofs_read_superblock(void);
-erofs_nid_t erofs_get_root_nid(void);
 void *erofs_init(struct fuse_conn_info *info);
 
 #endif
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 08/12] erofs-utils: fuse: move erofs_init() to main.c
  2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
                     ` (6 preceding siblings ...)
  2020-11-02 15:55   ` [WIP] [PATCH v3 07/12] erofs-utils: fuse: kill erofs_get_root_nid() Gao Xiang via Linux-erofs
@ 2020-11-02 15:55   ` Gao Xiang via Linux-erofs
  2020-11-02 15:55   ` [WIP] [PATCH v3 09/12] erofs-utils: fuse: move superblock logic into lib/ Gao Xiang via Linux-erofs
  8 siblings, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs

(will fold into the original patch.)

Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/init.c | 10 ----------
 fuse/main.c | 12 ++++++++++++
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/fuse/init.c b/fuse/init.c
index d67c7f0dd298..a5694beaf519 100644
--- a/fuse/init.c
+++ b/fuse/init.c
@@ -83,13 +83,3 @@ int erofs_read_superblock(void)
 	return 0;
 }
 
-void *erofs_init(struct fuse_conn_info *info)
-{
-	erofs_info("Using FUSE protocol %d.%d", info->proto_major, info->proto_minor);
-
-	if (inode_init(sbi.root_nid) != 0) {
-		erofs_err("inode initialization failed");
-		abort();
-	}
-	return NULL;
-}
diff --git a/fuse/main.c b/fuse/main.c
index fed4488081d8..30e4839bdcb4 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -13,6 +13,7 @@
 
 #include "erofs/print.h"
 #include "init.h"
+#include "namei.h"
 #include "read.h"
 #include "getattr.h"
 #include "open.h"
@@ -115,6 +116,17 @@ static void signal_handle_sigsegv(int signal)
 	abort();
 }
 
+void *erofs_init(struct fuse_conn_info *info)
+{
+	erofs_info("Using FUSE protocol %d.%d", info->proto_major, info->proto_minor);
+
+	if (inode_init(sbi.root_nid) != 0) {
+		erofs_err("inode initialization failed");
+		abort();
+	}
+	return NULL;
+}
+
 static struct fuse_operations erofs_ops = {
 	.readlink = erofs_readlink,
 	.getattr = erofs_getattr,
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 09/12] erofs-utils: fuse: move superblock logic into lib/
  2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
                     ` (7 preceding siblings ...)
  2020-11-02 15:55   ` [WIP] [PATCH v3 08/12] erofs-utils: fuse: move erofs_init() to main.c Gao Xiang via Linux-erofs
@ 2020-11-02 15:55   ` Gao Xiang via Linux-erofs
  2020-11-02 15:59     ` [WIP] [PATCH v3 10/12] erofs-utils: fuse: kill getattr.c Gao Xiang via Linux-erofs
  8 siblings, 1 reply; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:55 UTC (permalink / raw)
  To: linux-erofs

(will fold into the original patch.)

Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/Makefile.am           |  2 +-
 fuse/init.h                | 19 -------------------
 fuse/main.c                |  1 -
 fuse/namei.c               |  1 -
 fuse/read.c                |  1 -
 fuse/readir.c              |  1 -
 fuse/zmap.c                |  1 -
 include/erofs/internal.h   |  3 +++
 lib/Makefile.am            |  2 +-
 fuse/init.c => lib/super.c |  8 +-------
 10 files changed, 6 insertions(+), 33 deletions(-)
 delete mode 100644 fuse/init.h
 rename fuse/init.c => lib/super.c (94%)

diff --git a/fuse/Makefile.am b/fuse/Makefile.am
index 2b2608f57b03..f54def7a1526 100644
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -3,7 +3,7 @@
 
 AUTOMAKE_OPTIONS = foreign
 bin_PROGRAMS     = erofsfuse
-erofsfuse_SOURCES = main.c dentry.c getattr.c namei.c read.c init.c open.c readir.c zmap.c
+erofsfuse_SOURCES = main.c dentry.c getattr.c namei.c read.c open.c readir.c zmap.c
 erofsfuse_CFLAGS = -Wall -Werror \
                    -I$(top_srcdir)/include \
                    $(shell pkg-config fuse --cflags) \
diff --git a/fuse/init.h b/fuse/init.h
deleted file mode 100644
index f0211707b5ff..000000000000
--- a/fuse/init.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * erofs-utils/fuse/init.h
- *
- * Created by Li Guifu <blucerlee@gmail.com>
- */
-#ifndef __EROFS_INIT_H
-#define __EROFS_INIT_H
-
-#include <fuse.h>
-#include <fuse_opt.h>
-#include "erofs/internal.h"
-
-#define BOOT_SECTOR_SIZE	0x400
-
-int erofs_read_superblock(void);
-void *erofs_init(struct fuse_conn_info *info);
-
-#endif
diff --git a/fuse/main.c b/fuse/main.c
index 30e4839bdcb4..21f8b0451732 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -12,7 +12,6 @@
 #include <stddef.h>
 
 #include "erofs/print.h"
-#include "init.h"
 #include "namei.h"
 #include "read.h"
 #include "getattr.h"
diff --git a/fuse/namei.c b/fuse/namei.c
index c3766f9a9f02..4c428dbc59f6 100644
--- a/fuse/namei.c
+++ b/fuse/namei.c
@@ -17,7 +17,6 @@
 #include "erofs/print.h"
 #include "erofs/io.h"
 #include "dentry.h"
-#include "init.h"
 
 #define IS_PATH_SEPARATOR(__c)      ((__c) == '/')
 #define MINORBITS	20
diff --git a/fuse/read.c b/fuse/read.c
index dc88b24eaae3..10a26d84c37c 100644
--- a/fuse/read.c
+++ b/fuse/read.c
@@ -16,7 +16,6 @@
 #include "erofs/print.h"
 #include "namei.h"
 #include "erofs/io.h"
-#include "init.h"
 #include "erofs/decompress.h"
 
 size_t erofs_read_data_wrapper(struct erofs_vnode *vnode, char *buffer,
diff --git a/fuse/readir.c b/fuse/readir.c
index 496f4e73a9c2..5281c8b80e59 100644
--- a/fuse/readir.c
+++ b/fuse/readir.c
@@ -15,7 +15,6 @@
 #include "namei.h"
 #include "erofs/io.h"
 #include "erofs/print.h"
-#include "init.h"
 
 erofs_nid_t split_entry(char *entry, off_t ofs, char *end, char *name,
 			uint32_t dirend)
diff --git a/fuse/zmap.c b/fuse/zmap.c
index cb667da4e0c8..ba5c457278a8 100644
--- a/fuse/zmap.c
+++ b/fuse/zmap.c
@@ -9,7 +9,6 @@
  * Created by Gao Xiang <gaoxiang25@huawei.com>
  * Modified by Huang Jianan <huangjianan@oppo.com>
  */
-#include "init.h"
 #include "erofs/io.h"
 #include "erofs/print.h"
 
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 306005dea2a7..e56fd1898f3e 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -259,6 +259,9 @@ struct erofs_map_blocks {
 	erofs_blk_t index;
 };
 
+/* super.c */
+int erofs_read_superblock(void);
+
 /* data.h */
 int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
 			erofs_off_t offset, erofs_off_t size);
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 54c43897aa49..487c4944479d 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -2,7 +2,7 @@
 # Makefile.am
 
 noinst_LTLIBRARIES = liberofs.la
-liberofs_la_SOURCES = config.c io.c cache.c inode.c xattr.c exclude.c \
+liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c exclude.c \
 		      data.c compress.c compressor.c decompress.c
 liberofs_la_CFLAGS = -Wall -Werror -I$(top_srcdir)/include
 if ENABLE_LZ4
diff --git a/fuse/init.c b/lib/super.c
similarity index 94%
rename from fuse/init.c
rename to lib/super.c
index a5694beaf519..6213585c085d 100644
--- a/fuse/init.c
+++ b/lib/super.c
@@ -1,22 +1,16 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * erofs-utils/fuse/init.c
+ * erofs-utils/lib/super.c
  *
  * Created by Li Guifu <blucerlee@gmail.com>
  */
-#include "init.h"
 #include <string.h>
 #include <stdlib.h>
 #include <asm-generic/errno-base.h>
 
-#include "namei.h"
 #include "erofs/io.h"
 #include "erofs/print.h"
 
-#define STR(_X) (#_X)
-#define SUPER_MEM(_X) (super._X)
-
-
 struct erofs_super_block super;
 struct erofs_sb_info sbi;
 
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 10/12] erofs-utils: fuse: kill getattr.c
  2020-11-02 15:55   ` [WIP] [PATCH v3 09/12] erofs-utils: fuse: move superblock logic into lib/ Gao Xiang via Linux-erofs
@ 2020-11-02 15:59     ` Gao Xiang via Linux-erofs
  2020-11-02 15:59       ` [WIP] [PATCH v3 11/12] erofs-utils: fuse: kill open.c Gao Xiang via Linux-erofs
  2020-11-02 15:59       ` [WIP] [PATCH v3 12/12] erofs-utils: fuse: kill incomplate dcache Gao Xiang via Linux-erofs
  0 siblings, 2 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:59 UTC (permalink / raw)
  To: linux-erofs

(will fold into the original patch.)

Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/Makefile.am |  2 +-
 fuse/getattr.c   | 65 ------------------------------------------------
 fuse/getattr.h   | 15 -----------
 fuse/main.c      | 25 ++++++++++++++++++-
 4 files changed, 25 insertions(+), 82 deletions(-)
 delete mode 100644 fuse/getattr.c
 delete mode 100644 fuse/getattr.h

diff --git a/fuse/Makefile.am b/fuse/Makefile.am
index f54def7a1526..6e639f33f664 100644
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -3,7 +3,7 @@
 
 AUTOMAKE_OPTIONS = foreign
 bin_PROGRAMS     = erofsfuse
-erofsfuse_SOURCES = main.c dentry.c getattr.c namei.c read.c open.c readir.c zmap.c
+erofsfuse_SOURCES = main.c dentry.c namei.c read.c open.c readir.c zmap.c
 erofsfuse_CFLAGS = -Wall -Werror \
                    -I$(top_srcdir)/include \
                    $(shell pkg-config fuse --cflags) \
diff --git a/fuse/getattr.c b/fuse/getattr.c
deleted file mode 100644
index 4c5991e7e487..000000000000
--- a/fuse/getattr.c
+++ /dev/null
@@ -1,65 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * erofs-utils/fuse/getattr.c
- *
- * Created by Li Guifu <blucerlee@gmail.com>
- */
-#include "getattr.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "erofs/defs.h"
-#include "erofs/internal.h"
-#include "erofs_fs.h"
-#include "erofs/print.h"
-
-#include "namei.h"
-
-extern struct erofs_super_block super;
-
-/* GNU's definitions of the attributes
- * (http://www.gnu.org/software/libc/manual/html_node/Attribute-Meanings.html):
- * st_uid: The user ID of the file鈥檚 owner.
- * st_gid: The group ID of the file.
- * st_atime: This is the last access time for the file.
- * st_mtime: This is the time of the last modification to the contents of the
- *           file.
- * st_mode: Specifies the mode of the file. This includes file type information
- *          (see Testing File Type) and the file permission bits (see Permission
- *          Bits).
- * st_nlink: The number of hard links to the file.This count keeps track of how
- *           many directories have entries for this file. If the count is ever
- *           decremented to zero, then the file itself is discarded as soon as
- *           no process still holds it open. Symbolic links are not counted in
- *           the total.
- * st_size: This specifies the size of a regular file in bytes. For files that
- *         are really devices this field isn鈥檛 usually meaningful.For symbolic
- *         links this specifies the length of the file name the link refers to.
- */
-int erofs_getattr(const char *path, struct stat *stbuf)
-{
-	struct erofs_vnode v;
-	int ret;
-
-	erofs_dbg("getattr(%s)", path);
-	memset(&v, 0, sizeof(v));
-	ret = erofs_iget_by_path(path, &v);
-	if (ret)
-		return -ENOENT;
-
-	stbuf->st_mode  = le16_to_cpu(v.i_mode);
-	stbuf->st_nlink = le16_to_cpu(v.i_nlink);
-	stbuf->st_size  = le32_to_cpu(v.i_size);
-	stbuf->st_blocks = stbuf->st_size / EROFS_BLKSIZ;
-	stbuf->st_uid = le16_to_cpu(v.i_uid);
-	stbuf->st_gid = le16_to_cpu(v.i_gid);
-	stbuf->st_rdev = le32_to_cpu(v.i_rdev);
-	stbuf->st_atime = super.build_time;
-	stbuf->st_mtime = super.build_time;
-	stbuf->st_ctime = super.build_time;
-
-	return 0;
-}
diff --git a/fuse/getattr.h b/fuse/getattr.h
deleted file mode 100644
index 735529a91d5b..000000000000
--- a/fuse/getattr.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * erofs-utils/fuse/getattr.h
- *
- * Created by Li Guifu <blucerlee@gmail.com>
- */
-#ifndef __EROFS_GETATTR_H
-#define __EROFS_GETATTR_H
-
-#include <fuse.h>
-#include <fuse_opt.h>
-
-int erofs_getattr(const char *path, struct stat *st);
-
-#endif
diff --git a/fuse/main.c b/fuse/main.c
index 21f8b0451732..3842fedce8c1 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -14,7 +14,6 @@
 #include "erofs/print.h"
 #include "namei.h"
 #include "read.h"
-#include "getattr.h"
 #include "open.h"
 #include "readir.h"
 #include "erofs/io.h"
@@ -126,6 +125,30 @@ void *erofs_init(struct fuse_conn_info *info)
 	return NULL;
 }
 
+int erofs_getattr(const char *path, struct stat *stbuf)
+{
+	struct erofs_vnode v;
+	int ret;
+
+	erofs_dbg("getattr(%s)", path);
+	memset(&v, 0, sizeof(v));
+	ret = erofs_iget_by_path(path, &v);
+	if (ret)
+		return -ENOENT;
+
+	stbuf->st_mode  = v.i_mode;
+	stbuf->st_nlink = v.i_nlink;
+	stbuf->st_size  = v.i_size;
+	stbuf->st_blocks = stbuf->st_size / EROFS_BLKSIZ;
+	stbuf->st_uid = v.i_uid;
+	stbuf->st_gid = v.i_gid;
+	stbuf->st_rdev = v.i_rdev;
+	stbuf->st_atime = sbi.build_time;
+	stbuf->st_mtime = sbi.build_time;
+	stbuf->st_ctime = sbi.build_time;
+	return 0;
+}
+
 static struct fuse_operations erofs_ops = {
 	.readlink = erofs_readlink,
 	.getattr = erofs_getattr,
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 11/12] erofs-utils: fuse: kill open.c
  2020-11-02 15:59     ` [WIP] [PATCH v3 10/12] erofs-utils: fuse: kill getattr.c Gao Xiang via Linux-erofs
@ 2020-11-02 15:59       ` Gao Xiang via Linux-erofs
  2020-11-02 15:59       ` [WIP] [PATCH v3 12/12] erofs-utils: fuse: kill incomplate dcache Gao Xiang via Linux-erofs
  1 sibling, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:59 UTC (permalink / raw)
  To: linux-erofs

(will fold into the original patch.)

Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/Makefile.am |  2 +-
 fuse/main.c      | 11 ++++++++++-
 fuse/open.c      | 22 ----------------------
 fuse/open.h      | 15 ---------------
 4 files changed, 11 insertions(+), 39 deletions(-)
 delete mode 100644 fuse/open.c
 delete mode 100644 fuse/open.h

diff --git a/fuse/Makefile.am b/fuse/Makefile.am
index 6e639f33f664..5ff0b4d0e6ab 100644
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -3,7 +3,7 @@
 
 AUTOMAKE_OPTIONS = foreign
 bin_PROGRAMS     = erofsfuse
-erofsfuse_SOURCES = main.c dentry.c namei.c read.c open.c readir.c zmap.c
+erofsfuse_SOURCES = main.c dentry.c namei.c read.c readir.c zmap.c
 erofsfuse_CFLAGS = -Wall -Werror \
                    -I$(top_srcdir)/include \
                    $(shell pkg-config fuse --cflags) \
diff --git a/fuse/main.c b/fuse/main.c
index 3842fedce8c1..e423312d9e1a 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -14,7 +14,6 @@
 #include "erofs/print.h"
 #include "namei.h"
 #include "read.h"
-#include "open.h"
 #include "readir.h"
 #include "erofs/io.h"
 
@@ -125,6 +124,16 @@ void *erofs_init(struct fuse_conn_info *info)
 	return NULL;
 }
 
+int erofs_open(const char *path, struct fuse_file_info *fi)
+{
+	erofs_info("open path=%s", path);
+
+	if ((fi->flags & O_ACCMODE) != O_RDONLY)
+		return -EACCES;
+
+	return 0;
+}
+
 int erofs_getattr(const char *path, struct stat *stbuf)
 {
 	struct erofs_vnode v;
diff --git a/fuse/open.c b/fuse/open.c
deleted file mode 100644
index beb9a8615512..000000000000
--- a/fuse/open.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * erofs-utils/fuse/open.c
- *
- * Created by Li Guifu <blucerlee@gmail.com>
- */
-#include "open.h"
-#include <asm-generic/errno-base.h>
-#include <fuse.h>
-#include <fuse_opt.h>
-#include "erofs/print.h"
-
-int erofs_open(const char *path, struct fuse_file_info *fi)
-{
-	erofs_info("open path=%s", path);
-
-	if ((fi->flags & O_ACCMODE) != O_RDONLY)
-		return -EACCES;
-
-	return 0;
-}
-
diff --git a/fuse/open.h b/fuse/open.h
deleted file mode 100644
index dfc8b3cdd515..000000000000
--- a/fuse/open.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * erofs-utils/fuse/open.h
- *
- * Created by Li Guifu <blucerlee@gmail.com>
- */
-#ifndef __EROFS_OPEN_H
-#define __EROFS_OPEN_H
-
-#include <fuse.h>
-#include <fuse_opt.h>
-
-int erofs_open(const char *path, struct fuse_file_info *fi);
-
-#endif
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [WIP] [PATCH v3 12/12] erofs-utils: fuse: kill incomplate dcache
  2020-11-02 15:59     ` [WIP] [PATCH v3 10/12] erofs-utils: fuse: kill getattr.c Gao Xiang via Linux-erofs
  2020-11-02 15:59       ` [WIP] [PATCH v3 11/12] erofs-utils: fuse: kill open.c Gao Xiang via Linux-erofs
@ 2020-11-02 15:59       ` Gao Xiang via Linux-erofs
  1 sibling, 0 replies; 13+ messages in thread
From: Gao Xiang via Linux-erofs @ 2020-11-02 15:59 UTC (permalink / raw)
  To: linux-erofs

useless at all, use simplist bare disk lookup way for now
(also libfuse has an internal dcache, we can use it as well.
 plus no need to introduce dcache for unpack tool.)

(will fold into the original patch.)

Signed-off-by: Gao Xiang <hsiangkao@aol.com>
---
 fuse/Makefile.am |   2 +-
 fuse/dentry.c    | 130 ----------------------------------
 fuse/dentry.h    |  43 ------------
 fuse/main.c      |   5 --
 fuse/namei.c     | 179 +++++++++++++++++++++++------------------------
 fuse/namei.h     |   5 --
 6 files changed, 88 insertions(+), 276 deletions(-)
 delete mode 100644 fuse/dentry.c
 delete mode 100644 fuse/dentry.h

diff --git a/fuse/Makefile.am b/fuse/Makefile.am
index 5ff0b4d0e6ab..84e5f834d6a4 100644
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -3,7 +3,7 @@
 
 AUTOMAKE_OPTIONS = foreign
 bin_PROGRAMS     = erofsfuse
-erofsfuse_SOURCES = main.c dentry.c namei.c read.c readir.c zmap.c
+erofsfuse_SOURCES = main.c namei.c read.c readir.c zmap.c
 erofsfuse_CFLAGS = -Wall -Werror \
                    -I$(top_srcdir)/include \
                    $(shell pkg-config fuse --cflags) \
diff --git a/fuse/dentry.c b/fuse/dentry.c
deleted file mode 100644
index 0f722294d530..000000000000
--- a/fuse/dentry.c
+++ /dev/null
@@ -1,130 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * erofs-utils/fuse/dentry.c
- *
- * Created by Li Guifu <blucerlee@gmail.com>
- */
-#include <stdlib.h>
-#include "dentry.h"
-#include "erofs/internal.h"
-#include "erofs/print.h"
-
-#define DCACHE_ENTRY_CALLOC()   calloc(1, sizeof(struct dcache_entry))
-#define DCACHE_ENTRY_LIFE       8
-
-struct dcache_entry root_entry;
-
-int dcache_init_root(uint32_t nid)
-{
-	if (root_entry.nid)
-		return -1;
-
-	/* Root entry doesn't need most of the fields. Namely, it only uses the
-	 * nid field and the subdirs pointer.
-	 */
-	erofs_info("Initializing root_entry dcache entry");
-	root_entry.nid = nid;
-	root_entry.subdirs = NULL;
-	root_entry.siblings = NULL;
-
-	return 0;
-}
-
-/* Inserts a node as a subdirs of a given parent. The parent is updated to
- * point the newly inserted subdirs as the first subdirs. We return the new
- * entry so that further entries can be inserted.
- *
- *      [0]                  [0]
- *       /        ==>          \
- *      /         ==>           \
- * .->[1]->[2]-.       .->[1]->[3]->[2]-.
- * `-----------麓       `----------------麓
- */
-struct dcache_entry *dcache_insert(struct dcache_entry *parent,
-				   const char *name, int namelen, uint32_t nid)
-{
-	struct dcache_entry *new_entry;
-
-	erofs_dbg("Inserting %s,%d to dcache", name, namelen);
-
-	/* TODO: Deal with names that exceed the allocated size */
-	if (namelen + 1 > DCACHE_ENTRY_NAME_LEN)
-		return NULL;
-
-	if (parent == NULL)
-		parent = &root_entry;
-
-	new_entry = DCACHE_ENTRY_CALLOC();
-	if (!new_entry)
-		return NULL;
-
-	strncpy(new_entry->name, name, namelen);
-	new_entry->name[namelen] = 0;
-	new_entry->nid = nid;
-
-	if (!parent->subdirs) {
-		new_entry->siblings = new_entry;
-		parent->subdirs = new_entry;
-	} else {
-		new_entry->siblings = parent->subdirs->siblings;
-		parent->subdirs->siblings = new_entry;
-		parent->subdirs = new_entry;
-	}
-
-	return new_entry;
-}
-
-/* Lookup a cache entry for a given file name.  Return value is a struct pointer
- * that can be used to both obtain the nid number and insert further child
- * entries.
- * TODO: Prune entries by using the LRU counter
- */
-struct dcache_entry *dcache_lookup(struct dcache_entry *parent,
-				   const char *name, int namelen)
-{
-	struct dcache_entry *iter;
-
-	if (parent == NULL)
-		parent = &root_entry;
-
-	if (!parent->subdirs)
-		return NULL;
-
-	/* Iterate the list of siblings to see if there is any match */
-	iter = parent->subdirs;
-
-	do {
-		if (strncmp(iter->name, name, namelen) == 0 &&
-		    iter->name[namelen] == 0) {
-			parent->subdirs = iter;
-
-			return iter;
-		}
-
-		iter = iter->siblings;
-	} while (iter != parent->subdirs);
-
-	return NULL;
-}
-
-struct dcache_entry *dcache_try_insert(struct dcache_entry *parent,
-				   const char *name, int namelen, uint32_t nid)
-{
-	struct dcache_entry *d = dcache_lookup(parent, name, namelen);
-
-	if (d)
-		return d;
-
-	return dcache_insert(parent, name, namelen, nid);
-
-}
-erofs_nid_t dcache_get_nid(struct dcache_entry *entry)
-{
-	return entry ? entry->nid : root_entry.nid;
-}
-
-struct dcache_entry *dcache_root(void)
-{
-	return &root_entry;
-}
-
diff --git a/fuse/dentry.h b/fuse/dentry.h
deleted file mode 100644
index 12f4cf6bafd9..000000000000
--- a/fuse/dentry.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * erofs-utils/fuse/dentry.h
- *
- * Created by Li Guifu <blucerlee@gmail.com>
- */
-#ifndef _EROFS_DENTRY_H
-#define _EROFS_DENTRY_H
-
-#include <stdint.h>
-#include "erofs/internal.h"
-
-/* fixme: Deal with names that exceed the allocated size */
-#ifdef __64BITS
-#define DCACHE_ENTRY_NAME_LEN       EROFS_NAME_LEN
-#else
-#define DCACHE_ENTRY_NAME_LEN       EROFS_NAME_LEN
-#endif
-
-/* This struct declares a node of a k-tree.  Every node has a pointer to one of
- * the subdirs and a pointer (in a circular list fashion) to its siblings.
- */
-
-struct dcache_entry {
-	struct dcache_entry *subdirs;
-	struct dcache_entry *siblings;
-	uint32_t nid;
-	uint16_t lru_count;
-	uint8_t user_count;
-	char name[DCACHE_ENTRY_NAME_LEN];
-};
-
-struct dcache_entry *dcache_insert(struct dcache_entry *parent,
-				   const char *name, int namelen, uint32_t n);
-struct dcache_entry *dcache_lookup(struct dcache_entry *parent,
-				   const char *name, int namelen);
-struct dcache_entry *dcache_try_insert(struct dcache_entry *parent,
-				       const char *name, int namelen,
-				       uint32_t nid);
-
-erofs_nid_t dcache_get_nid(struct dcache_entry *entry);
-int dcache_init_root(uint32_t n);
-#endif
diff --git a/fuse/main.c b/fuse/main.c
index e423312d9e1a..563b2c378952 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -116,11 +116,6 @@ static void signal_handle_sigsegv(int signal)
 void *erofs_init(struct fuse_conn_info *info)
 {
 	erofs_info("Using FUSE protocol %d.%d", info->proto_major, info->proto_minor);
-
-	if (inode_init(sbi.root_nid) != 0) {
-		erofs_err("inode initialization failed");
-		abort();
-	}
 	return NULL;
 }
 
diff --git a/fuse/namei.c b/fuse/namei.c
index 4c428dbc59f6..5ee3f8d2a4b6 100644
--- a/fuse/namei.c
+++ b/fuse/namei.c
@@ -16,7 +16,6 @@
 #include "erofs/defs.h"
 #include "erofs/print.h"
 #include "erofs/io.h"
-#include "dentry.h"
 
 #define IS_PATH_SEPARATOR(__c)      ((__c) == '/')
 #define MINORBITS	20
@@ -99,124 +98,127 @@ int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *vi)
 	return 0;
 }
 
-/* dirent + name string */
-struct dcache_entry *list_name(const char *buf, struct dcache_entry *parent,
-				const char *name, unsigned int len,
-				uint32_t dirend)
+
+struct erofs_dirent *find_target_dirent(erofs_nid_t pnid,
+					void *dentry_blk,
+					const char *name, unsigned int len,
+					unsigned int nameoff,
+					unsigned int maxsize)
 {
-	struct dcache_entry *entry = NULL;
-	struct erofs_dirent *ds, *de;
-
-	ds = (struct erofs_dirent *)buf;
-	de = (struct erofs_dirent *)(buf + le16_to_cpu(ds->nameoff));
-
-	while (ds < de) {
-		erofs_nid_t nid = le64_to_cpu(ds->nid);
-		uint16_t nameoff = le16_to_cpu(ds->nameoff);
-		char *d_name = (char *)(buf + nameoff);
-		uint16_t name_len = (ds + 1 >= de) ?
-			(uint16_t)strnlen(d_name, dirend - nameoff) :
-			le16_to_cpu(ds[1].nameoff) - nameoff;
-
-		#if defined(EROFS_DEBUG_ENTRY)
-		{
-			char debug[EROFS_BLKSIZ];
-
-			memcpy(debug, d_name, name_len);
-			debug[name_len] = '\0';
-			erofs_info("list entry: %s nid=%u", debug, nid);
+	struct erofs_dirent *de = dentry_blk;
+	const struct erofs_dirent *end = dentry_blk + nameoff;
+
+	while (de < end) {
+		const char *de_name;
+		unsigned int de_namelen;
+
+		nameoff = le16_to_cpu(de->nameoff);
+		de_name = (char *)dentry_blk + nameoff;
+
+		/* the last dirent in the block? */
+		if (de + 1 >= end)
+			de_namelen = strnlen(de_name, maxsize - nameoff);
+		else
+			de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;
+
+		/* a corrupted entry is found */
+		if (nameoff + de_namelen > maxsize ||
+		    de_namelen > EROFS_NAME_LEN) {
+			erofs_err("bogus dirent @ nid %llu", pnid | 0ULL);
+			DBG_BUGON(1);
+			return ERR_PTR(-EFSCORRUPTED);
 		}
-		#endif
-
-		entry = dcache_try_insert(parent, d_name, name_len, nid);
-		if (len == name_len && !memcmp(name, d_name, name_len))
-			return entry;
 
-		entry = NULL;
-		++ds;
+		if (len == de_namelen && !memcmp(de_name, name, de_namelen))
+			return de;
+		++de;
 	}
-
-	return entry;
+	return NULL;
 }
 
-struct dcache_entry *disk_lookup(struct dcache_entry *parent, const char *name,
-		unsigned int name_len)
+int erofs_namei(erofs_nid_t *nid,
+		const char *name, unsigned int len)
 {
 	int ret;
 	char buf[EROFS_BLKSIZ];
-	struct dcache_entry *entry = NULL;
 	struct erofs_vnode v;
-	uint32_t nr_cnt, dir_nr, dirsize, blkno;
 
-	ret = erofs_iget_by_nid(parent->nid, &v);
+	ret = erofs_iget_by_nid(*nid, &v);
 	if (ret)
-		return NULL;
-
-	/* to check whether dirent is in the inline dirs */
-	blkno = v.raw_blkaddr;
-	dirsize = v.i_size;
-	dir_nr = erofs_blknr(dirsize);
-
-	nr_cnt = 0;
-	while (nr_cnt < dir_nr) {
-		ret = blk_read(buf, blkno + nr_cnt, 1);
-		if (ret < 0)
-			return NULL;
-
-		entry = list_name(buf, parent, name, name_len, EROFS_BLKSIZ);
-		if (entry)
-			goto next;
-
-		++nr_cnt;
-	}
-
-	if (v.datalayout == EROFS_INODE_FLAT_INLINE) {
-		uint32_t dir_off = erofs_blkoff(dirsize);
-		off_t dir_addr = iloc(dcache_get_nid(parent)) +
-			v.inode_isize + v.xattr_isize;
-
-		memset(buf, 0, sizeof(buf));
-		ret = dev_read(buf, dir_addr, dir_off);
-		if (ret < 0)
-			return NULL;
+		return ret;
 
-		entry = list_name(buf, parent, name, name_len, dir_off);
+	{
+		unsigned int offset = 0;
+
+		struct erofs_inode tmp = {
+			.u = {
+				.i_blkaddr = v.raw_blkaddr,
+			},
+			.nid = v.nid,
+			.i_size = v.i_size,
+			.datalayout = v.datalayout,
+			.inode_isize = v.inode_isize,
+			.xattr_isize = v.xattr_isize,
+		};
+
+		while (offset < v.i_size) {
+			int maxsize = min(v.i_size - offset, EROFS_BLKSIZ);
+			struct erofs_dirent *de = (void *)buf;
+			unsigned int nameoff;
+
+			ret = erofs_read_raw_data(&tmp, buf, offset, maxsize);
+			if (ret)
+				return ret;
+
+			nameoff = le16_to_cpu(de->nameoff);
+
+			if (nameoff < sizeof(struct erofs_dirent) ||
+			    nameoff >= PAGE_SIZE) {
+				erofs_err("invalid de[0].nameoff %u @ nid %llu",
+					  nameoff, *nid | 0ULL);
+				return -EFSCORRUPTED;
+			}
+
+			de = find_target_dirent(*nid, buf, name, len,
+						nameoff, maxsize);
+			if (IS_ERR(de))
+				return PTR_ERR(de);
+
+			if (de) {
+				*nid = le64_to_cpu(de->nid);
+				return 0;
+			}
+			offset += maxsize;
+		}
 	}
-next:
-	return entry;
+	return -ENOENT;
 }
 
 extern struct dcache_entry root_entry;
 int walk_path(const char *_path, erofs_nid_t *out_nid)
 {
-	struct dcache_entry *next, *ret;
+	int ret;
+	erofs_nid_t nid = sbi.root_nid;
 	const char *path = _path;
 
-	ret = next = &root_entry;
 	for (;;) {
 		uint8_t path_len;
 
 		path = skip_trailing_backslash(path);
 		path_len = get_path_token_len(path);
-		ret = next;
 		if (path_len == 0)
 			break;
 
-		next = dcache_lookup(ret, path, path_len);
-		if (!next) {
-			next = disk_lookup(ret, path, path_len);
-			if (!next)
-				return -ENOENT;
-		}
+		ret = erofs_namei(&nid, path, path_len);
+		if (ret)
+			return ret;
 
 		path += path_len;
 	}
 
-	if (!ret)
-		return -ENOENT;
-	erofs_dbg("find path = %s nid=%u", _path, ret->nid);
+	erofs_dbg("find path = %s nid=%llu", _path, nid | 0ULL);
 
-	*out_nid = ret->nid;
+	*out_nid = nid;
 	return 0;
 
 }
@@ -233,10 +235,3 @@ int erofs_iget_by_path(const char *path, struct erofs_vnode *v)
 	return erofs_iget_by_nid(nid, v);
 }
 
-int inode_init(erofs_nid_t root)
-{
-	dcache_init_root(root);
-
-	return 0;
-}
-
diff --git a/fuse/namei.h b/fuse/namei.h
index 1803a673daaf..2625ec58d434 100644
--- a/fuse/namei.h
+++ b/fuse/namei.h
@@ -10,13 +10,8 @@
 #include "erofs/internal.h"
 #include "erofs_fs.h"
 
-int inode_init(erofs_nid_t root);
-struct dcache_entry *get_cached_dentry(struct dcache_entry **parent,
-				       const char **path);
 int erofs_iget_by_path(const char *path, struct erofs_vnode *v);
 int erofs_iget_by_nid(erofs_nid_t nid, struct erofs_vnode *v);
-struct dcache_entry *disk_lookup(struct dcache_entry *parent, const char *name,
-		unsigned int name_len);
 int walk_path(const char *path, erofs_nid_t *out_nid);
 
 #endif
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-11-02 16:00 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20201102155558.1995-1-hsiangkao.ref@aol.com>
2020-11-02 15:55 ` [WIP] [PATCH v3 00/12] erofs-utils: introduce fuse implementation Gao Xiang via Linux-erofs
2020-11-02 15:55   ` [WIP] [PATCH v3 01/12] " Gao Xiang via Linux-erofs
2020-11-02 15:55   ` [WIP] [PATCH v3 02/12] erofs-utils: fuse: add special file support Gao Xiang via Linux-erofs
2020-11-02 15:55   ` [WIP] [PATCH v3 03/12] erofs-utils: fuse: add compressed " Gao Xiang via Linux-erofs
2020-11-02 15:55   ` [WIP] [PATCH v3 04/12] erofs-utils: fuse: refactor raw data logic Gao Xiang via Linux-erofs
2020-11-02 15:55   ` [WIP] [PATCH v3 05/12] erofs-utils: fuse: kill sbk Gao Xiang via Linux-erofs
2020-11-02 15:55   ` [WIP] [PATCH v3 06/12] erofs-utils: fuse: kill nid2addr, addr2nid Gao Xiang via Linux-erofs
2020-11-02 15:55   ` [WIP] [PATCH v3 07/12] erofs-utils: fuse: kill erofs_get_root_nid() Gao Xiang via Linux-erofs
2020-11-02 15:55   ` [WIP] [PATCH v3 08/12] erofs-utils: fuse: move erofs_init() to main.c Gao Xiang via Linux-erofs
2020-11-02 15:55   ` [WIP] [PATCH v3 09/12] erofs-utils: fuse: move superblock logic into lib/ Gao Xiang via Linux-erofs
2020-11-02 15:59     ` [WIP] [PATCH v3 10/12] erofs-utils: fuse: kill getattr.c Gao Xiang via Linux-erofs
2020-11-02 15:59       ` [WIP] [PATCH v3 11/12] erofs-utils: fuse: kill open.c Gao Xiang via Linux-erofs
2020-11-02 15:59       ` [WIP] [PATCH v3 12/12] erofs-utils: fuse: kill incomplate dcache Gao Xiang via Linux-erofs

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).