Linux-EROFS Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 01/16] erofs-utils: fix tar.h
@ 2023-08-02  9:17 Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 02/16] erofs-utils: lib: add list_splice_tail() helper Jingbo Xu
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Include "internal.h" to fix the dependency on prototypes of `struct
erofs_inode` and `struct erofs_sb_info`.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/tar.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/include/erofs/tar.h b/include/erofs/tar.h
index 8d3f8de..b7c2ef8 100644
--- a/include/erofs/tar.h
+++ b/include/erofs/tar.h
@@ -2,8 +2,15 @@
 #ifndef __EROFS_TAR_H
 #define __EROFS_TAR_H
 
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
 #include <sys/stat.h>
 
+#include "internal.h"
+
 struct erofs_pax_header {
 	struct stat st;
 	bool use_mtime;
@@ -27,4 +34,8 @@ int tarerofs_parse_tar(struct erofs_inode *root, struct erofs_tarfile *tar);
 int tarerofs_reserve_devtable(struct erofs_sb_info *sbi, unsigned int devices);
 int tarerofs_write_devtable(struct erofs_sb_info *sbi, struct erofs_tarfile *tar);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 02/16] erofs-utils: lib: add list_splice_tail() helper
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 03/16] erofs-utils: lib: add bitops library Jingbo Xu
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Add list_splice_tail() helper.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/list.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/include/erofs/list.h b/include/erofs/list.h
index 3f5da1a..d7a9fee 100644
--- a/include/erofs/list.h
+++ b/include/erofs/list.h
@@ -70,6 +70,26 @@ static inline int list_empty(struct list_head *head)
 	return head->next == head;
 }
 
+static inline void __list_splice(struct list_head *list,
+		struct list_head *prev, struct list_head *next)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+
+	first->prev = prev;
+	prev->next = first;
+
+	last->next = next;
+	next->prev = last;
+}
+
+static inline void list_splice_tail(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head->prev, head);
+}
+
 #define list_entry(ptr, type, member) container_of(ptr, type, member)
 
 #define list_first_entry(ptr, type, member)                                    \
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 03/16] erofs-utils: lib: add bitops library
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 02/16] erofs-utils: lib: add list_splice_tail() helper Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 04/16] erofs-utils: read i_ino in erofs_read_inode_from_disk() Jingbo Xu
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Introduce following bitmap helpers:

	DECLARE_BITMAP
	test_bit
	__set_bit
	__clear_bit
	find_next_bit
	find_next_zero_bit

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/bitops.h | 43 ++++++++++++++++++++++++
 include/erofs/defs.h   | 75 ++++++++++++++++++++++++++++++++++++++++++
 lib/Makefile.am        |  3 +-
 lib/bitops.c           | 58 ++++++++++++++++++++++++++++++++
 4 files changed, 178 insertions(+), 1 deletion(-)
 create mode 100644 include/erofs/bitops.h
 create mode 100644 lib/bitops.c

diff --git a/include/erofs/bitops.h b/include/erofs/bitops.h
new file mode 100644
index 0000000..985195d
--- /dev/null
+++ b/include/erofs/bitops.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 */
+#ifndef __EROFS_BITOPS_H
+#define __EROFS_BITOPS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "defs.h"
+
+static inline void __set_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+	*p  |= mask;
+}
+
+static inline void __clear_bit(int nr, volatile unsigned long *addr)
+{
+	unsigned long mask = BIT_MASK(nr);
+	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+
+	*p &= ~mask;
+}
+
+static inline int test_bit(int nr, const volatile unsigned long *addr)
+{
+	return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
+}
+
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+			    unsigned long offset);
+
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+				 unsigned long offset);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/erofs/defs.h b/include/erofs/defs.h
index 20f9741..c6bbbb5 100644
--- a/include/erofs/defs.h
+++ b/include/erofs/defs.h
@@ -343,6 +343,81 @@ unsigned long __roundup_pow_of_two(unsigned long n)
 #define lstat64		lstat
 #endif
 
+#define DECLARE_BITMAP(name,bits) \
+	unsigned long name[BITS_TO_LONGS(bits)]
+
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
+
+/**
+ * __swab32 - return a byteswapped 32-bit value
+ * @x: value to byteswap
+ */
+#define __swab32(x) ((__u32)(					\
+	(((__u32)(x) & (__u32)0x000000ffUL) << 24) |		\
+	(((__u32)(x) & (__u32)0x0000ff00UL) <<  8) |		\
+	(((__u32)(x) & (__u32)0x00ff0000UL) >>  8) |		\
+	(((__u32)(x) & (__u32)0xff000000UL) >> 24)))
+
+/**
+ * __swab64 - return a byteswapped 64-bit value
+ * @x: value to byteswap
+ */
+#define __swab64(x) ((__u64)(					\
+	(((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) |	\
+	(((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) |	\
+	(((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) |	\
+	(((__u64)(x) & (__u64)0x00000000ff000000ULL) <<  8) |	\
+	(((__u64)(x) & (__u64)0x000000ff00000000ULL) >>  8) |	\
+	(((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) |	\
+	(((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) |	\
+	(((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56)))
+
+static __always_inline unsigned long __swab(const unsigned long y)
+{
+#if BITS_PER_LONG == 64
+	return __swab64(y);
+#else /* BITS_PER_LONG == 32 */
+	return __swab32(y);
+#endif
+}
+
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __always_inline unsigned long __ffs(unsigned long word)
+{
+	int num = 0;
+
+#if BITS_PER_LONG == 64
+	if ((word & 0xffffffff) == 0) {
+		num += 32;
+		word >>= 32;
+	}
+#endif
+	if ((word & 0xffff) == 0) {
+		num += 16;
+		word >>= 16;
+	}
+	if ((word & 0xff) == 0) {
+		num += 8;
+		word >>= 8;
+	}
+	if ((word & 0xf) == 0) {
+		num += 4;
+		word >>= 4;
+	}
+	if ((word & 0x3) == 0) {
+		num += 2;
+		word >>= 2;
+	}
+	if ((word & 0x1) == 0)
+		num += 1;
+	return num;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 7a5dc03..08e986e 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -19,6 +19,7 @@ noinst_HEADERS = $(top_srcdir)/include/erofs_fs.h \
       $(top_srcdir)/include/erofs/io.h \
       $(top_srcdir)/include/erofs/list.h \
       $(top_srcdir)/include/erofs/print.h \
+      $(top_srcdir)/include/erofs/bitops.h \
       $(top_srcdir)/include/erofs/tar.h \
       $(top_srcdir)/include/erofs/trace.h \
       $(top_srcdir)/include/erofs/xattr.h \
@@ -31,7 +32,7 @@ liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c exclude.c \
 		      namei.c data.c compress.c compressor.c zmap.c decompress.c \
 		      compress_hints.c hashmap.c sha256.c blobchunk.c dir.c \
 		      fragments.c rb_tree.c dedupe.c uuid_unparse.c uuid.c tar.c \
-		      block_list.c
+		      block_list.c bitops.c
 
 liberofs_la_CFLAGS = -Wall ${libuuid_CFLAGS} -I$(top_srcdir)/include
 if ENABLE_LZ4
diff --git a/lib/bitops.c b/lib/bitops.c
new file mode 100644
index 0000000..6ce521a
--- /dev/null
+++ b/lib/bitops.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
+#include <stdlib.h>
+#include <erofs/bitops.h>
+#include "erofs/internal.h"
+
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
+
+static unsigned long _find_next_bit(const unsigned long *addr1,
+		const unsigned long *addr2, unsigned long nbits,
+		unsigned long start, unsigned long invert, unsigned long le)
+{
+	unsigned long tmp, mask;
+
+	if (start >= nbits)
+		return nbits;
+
+	tmp = addr1[start / BITS_PER_LONG];
+	if (addr2)
+		tmp &= addr2[start / BITS_PER_LONG];
+	tmp ^= invert;
+
+	/* Handle 1st word. */
+	mask = BITMAP_FIRST_WORD_MASK(start);
+	if (le)
+		mask = __swab(mask);
+
+	tmp &= mask;
+
+	start = round_down(start, BITS_PER_LONG);
+
+	while (!tmp) {
+		start += BITS_PER_LONG;
+		if (start >= nbits)
+			return nbits;
+
+		tmp = addr1[start / BITS_PER_LONG];
+		if (addr2)
+			tmp &= addr2[start / BITS_PER_LONG];
+		tmp ^= invert;
+	}
+
+	if (le)
+		tmp = __swab(tmp);
+
+	return min(start + __ffs(tmp), nbits);
+}
+
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+			    unsigned long offset)
+{
+	return _find_next_bit(addr, NULL, size, offset, 0UL, 0);
+}
+
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+				 unsigned long offset)
+{
+	return _find_next_bit(addr, NULL, size, offset, ~0UL, 0);
+}
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 04/16] erofs-utils: read i_ino in erofs_read_inode_from_disk()
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 02/16] erofs-utils: lib: add list_splice_tail() helper Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 03/16] erofs-utils: lib: add bitops library Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 05/16] erofs-utils: read dis->blocks in erofs_init_devices() Jingbo Xu
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Read on-disk ino and store it in i_ino[0].

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 lib/namei.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lib/namei.c b/lib/namei.c
index 1023a9a..2bb1d4c 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -60,6 +60,7 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
 		die = (struct erofs_inode_extended *)buf;
 		vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount);
 		vi->i_mode = le16_to_cpu(die->i_mode);
+		vi->i_ino[0] = le32_to_cpu(die->i_ino);
 
 		switch (vi->i_mode & S_IFMT) {
 		case S_IFREG:
@@ -95,6 +96,7 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
 		vi->inode_isize = sizeof(struct erofs_inode_compact);
 		vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount);
 		vi->i_mode = le16_to_cpu(dic->i_mode);
+		vi->i_ino[0] = le32_to_cpu(dic->i_ino);
 
 		switch (vi->i_mode & S_IFMT) {
 		case S_IFREG:
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 05/16] erofs-utils: read dis->blocks in erofs_init_devices()
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (2 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 04/16] erofs-utils: read i_ino in erofs_read_inode_from_disk() Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 06/16] erofs-utils: add erofs_read_xattrs_from_disk() helper Jingbo Xu
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Read dis->blocks in erofs_init_devices().  Also fix the missing
le32_to_cpu() when reading mapped_blkaddr.

Initialize sbi->extra_devices from on-disk extra_devices.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 lib/super.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/lib/super.c b/lib/super.c
index 16a1d62..1e4f9f4 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -36,11 +36,7 @@ static int erofs_init_devices(struct erofs_sb_info *sbi,
 	else
 		ondisk_extradevs = le16_to_cpu(dsb->extra_devices);
 
-	if (ondisk_extradevs != sbi->extra_devices) {
-		erofs_err("extra devices don't match (ondisk %u, given %u)",
-			  ondisk_extradevs, sbi->extra_devices);
-		return -EINVAL;
-	}
+	sbi->extra_devices = ondisk_extradevs;
 	if (!ondisk_extradevs)
 		return 0;
 
@@ -59,8 +55,9 @@ static int erofs_init_devices(struct erofs_sb_info *sbi,
 			return ret;
 		}
 
-		sbi->devs[i].mapped_blkaddr = dis.mapped_blkaddr;
-		sbi->total_blocks += dis.blocks;
+		sbi->devs[i].mapped_blkaddr = le32_to_cpu(dis.mapped_blkaddr);
+		sbi->devs[i].blocks = le32_to_cpu(dis.blocks);
+		sbi->total_blocks += sbi->devs[i].blocks;
 		pos += EROFS_DEVT_SLOT_SIZE;
 	}
 	return 0;
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 06/16] erofs-utils: add erofs_read_xattrs_from_disk() helper
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (3 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 05/16] erofs-utils: read dis->blocks in erofs_init_devices() Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 07/16] erofs-utils: add erofs_inode_tag_opaque() helper Jingbo Xu
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Add erofs_read_xattrs_from_disk() helper to read extended attributes
from disk.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/xattr.h |  1 +
 lib/xattr.c           | 76 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index dc27cf6..634daf9 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -85,6 +85,7 @@ int erofs_xattr_write_name_prefixes(struct erofs_sb_info *sbi, FILE *f);
 
 int erofs_setxattr(struct erofs_inode *inode, char *key,
 		   const void *value, size_t size);
+int erofs_read_xattrs_from_disk(struct erofs_inode *inode);
 
 #ifdef __cplusplus
 }
diff --git a/lib/xattr.c b/lib/xattr.c
index 12f580e..8d8f9f0 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -493,6 +493,82 @@ int erofs_scan_file_xattrs(struct erofs_inode *inode)
 	return erofs_droid_xattr_set_caps(inode);
 }
 
+static struct xattr_item *erofs_read_xattr_from_disk(struct erofs_inode *inode,
+						     char *key)
+{
+	ssize_t ret;
+	u8 prefix;
+	u16 prefixlen;
+	unsigned int len[2];
+	char *kvbuf;
+
+	if (!match_prefix(key, &prefix, &prefixlen))
+		return ERR_PTR(-ENODATA);
+
+	ret = erofs_getxattr(inode, key, NULL, 0);
+	if (ret < 0)
+		return ERR_PTR(-errno);
+
+	/* allocate key-value buffer */
+	len[0] = strlen(key) - prefixlen;
+	len[1] = ret;
+	kvbuf = malloc(len[0] + len[1]);
+	if (!kvbuf)
+		return ERR_PTR(-ENOMEM);
+	memcpy(kvbuf, key + prefixlen, len[0]);
+	if (len[1]) {
+		ret = erofs_getxattr(inode, key, kvbuf + len[0], len[1]);
+		if (ret < 0) {
+			free(kvbuf);
+			return ERR_PTR(-errno);
+		}
+		if (ret != len[1]) {
+			erofs_err("size of xattr value got changed just now (%u-> %ld)",
+				  len[1], (long)ret);
+			len[1] = ret;
+		}
+	}
+	return get_xattritem(prefix, kvbuf, len);
+}
+
+int erofs_read_xattrs_from_disk(struct erofs_inode *inode)
+{
+	ssize_t kllen;
+	char *keylst, *key;
+	struct xattr_item *item;
+	int ret;
+
+	init_list_head(&inode->i_xattrs);
+	kllen = erofs_listxattr(inode, NULL, 0);
+	if (kllen < 0)
+		return kllen;
+	if (kllen <= 1)
+		return 0;
+
+	keylst = malloc(kllen);
+	if (!keylst)
+		return -ENOMEM;
+
+	ret = erofs_listxattr(inode, keylst, kllen);
+	if (ret < 0)
+		goto err;
+
+	for (key = keylst; key < keylst + kllen; key += strlen(key) + 1) {
+		item = erofs_read_xattr_from_disk(inode, key);
+		if (IS_ERR(item)) {
+			ret = PTR_ERR(item);
+			goto err;
+		}
+
+		ret = erofs_xattr_add(&inode->i_xattrs, item);
+		if (ret < 0)
+			goto err;
+	}
+err:
+	free(keylst);
+	return ret;
+}
+
 int erofs_prepare_xattr_ibody(struct erofs_inode *inode)
 {
 	int ret;
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 07/16] erofs-utils: add erofs_inode_tag_opaque() helper
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (4 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 06/16] erofs-utils: add erofs_read_xattrs_from_disk() helper Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 08/16] erofs-utils: add erofs_insert_ihash() helper Jingbo Xu
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Add erofs_inode_tag_opaque() helper checking if it's an opaque directory.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/internal.h |  2 ++
 include/erofs/xattr.h    | 22 ++++++++++++++++++++
 lib/tar.c                |  5 -----
 lib/xattr.c              | 44 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 68 insertions(+), 5 deletions(-)

diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 04a9a69..83a2e22 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -218,6 +218,8 @@ struct erofs_inode {
 #endif
 	erofs_off_t fragmentoff;
 	unsigned int fragment_size;
+
+	bool opaque;
 };
 
 static inline erofs_off_t erofs_iloc(struct erofs_inode *inode)
diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index 634daf9..21d669b 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -73,6 +73,27 @@ static inline unsigned int xattrblock_offset(struct erofs_inode *vi,
 #ifndef XATTR_NAME_POSIX_ACL_DEFAULT
 #define XATTR_NAME_POSIX_ACL_DEFAULT "system.posix_acl_default"
 #endif
+#ifndef OVL_XATTR_NAMESPACE
+#define OVL_XATTR_NAMESPACE "overlay."
+#endif
+#ifndef OVL_XATTR_OPAQUE_POSTFIX
+#define OVL_XATTR_OPAQUE_POSTFIX "opaque"
+#endif
+#ifndef OVL_XATTR_TRUSTED_PREFIX
+#define OVL_XATTR_TRUSTED_PREFIX XATTR_TRUSTED_PREFIX OVL_XATTR_NAMESPACE
+#endif
+#ifndef OVL_XATTR_OPAQUE_SUFFIX
+#define OVL_XATTR_OPAQUE_SUFFIX OVL_XATTR_NAMESPACE OVL_XATTR_OPAQUE_POSTFIX
+#endif
+#ifndef OVL_XATTR_OPAQUE_SUFFIX_LEN
+#define OVL_XATTR_OPAQUE_SUFFIX_LEN (sizeof(OVL_XATTR_OPAQUE_SUFFIX) - 1)
+#endif
+#ifndef OVL_XATTR_OPAQUE
+#define OVL_XATTR_OPAQUE OVL_XATTR_TRUSTED_PREFIX OVL_XATTR_OPAQUE_POSTFIX
+#endif
+#ifndef OVL_XATTR_OPAQUE_LEN
+#define OVL_XATTR_OPAQUE_LEN (sizeof(OVL_XATTR_OPAQUE) - 1)
+#endif
 
 int erofs_scan_file_xattrs(struct erofs_inode *inode);
 int erofs_prepare_xattr_ibody(struct erofs_inode *inode);
@@ -86,6 +107,7 @@ int erofs_xattr_write_name_prefixes(struct erofs_sb_info *sbi, FILE *f);
 int erofs_setxattr(struct erofs_inode *inode, char *key,
 		   const void *value, size_t size);
 int erofs_read_xattrs_from_disk(struct erofs_inode *inode);
+void erofs_inode_tag_opaque(struct erofs_inode *inode);
 
 #ifdef __cplusplus
 }
diff --git a/lib/tar.c b/lib/tar.c
index 54ee33f..3180ee4 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -19,11 +19,6 @@
 #include "erofs/xattr.h"
 #include "erofs/blobchunk.h"
 
-#define OVL_XATTR_NAMESPACE "overlay."
-#define OVL_XATTR_TRUSTED_PREFIX XATTR_TRUSTED_PREFIX OVL_XATTR_NAMESPACE
-#define OVL_XATTR_OPAQUE_POSTFIX "opaque"
-#define OVL_XATTR_OPAQUE OVL_XATTR_TRUSTED_PREFIX OVL_XATTR_OPAQUE_POSTFIX
-
 #define EROFS_WHITEOUT_DEV	0
 
 static char erofs_libbuf[16384];
diff --git a/lib/xattr.c b/lib/xattr.c
index 8d8f9f0..e9aff53 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -1421,6 +1421,50 @@ int erofs_listxattr(struct erofs_inode *vi, char *buffer, size_t buffer_size)
 	return shared_listxattr(vi, &it);
 }
 
+static bool erofs_xattr_is_opaque(struct xattr_item *item)
+{
+	struct ea_type_node *tnode;
+	unsigned int plen;
+	const char *prefix;
+
+	if (item->prefix == EROFS_XATTR_INDEX_TRUSTED &&
+	    !strncmp(item->kvbuf, OVL_XATTR_OPAQUE_SUFFIX,
+		     OVL_XATTR_OPAQUE_SUFFIX_LEN))
+		return true;
+
+	if (item->prefix & EROFS_XATTR_LONG_PREFIX) {
+		list_for_each_entry(tnode, &ea_name_prefixes, list) {
+			prefix = tnode->type.prefix;
+			plen = tnode->type.prefix_len;
+			if (tnode->index == item->prefix &&
+			    plen + item->len[0] == OVL_XATTR_OPAQUE_LEN &&
+			    !strncmp(prefix, OVL_XATTR_OPAQUE, plen) &&
+			    !strncmp(item->kvbuf, OVL_XATTR_OPAQUE + plen,
+				     item->len[0]))
+				return true;
+		}
+	}
+	return false;
+}
+
+void erofs_inode_tag_opaque(struct erofs_inode *inode)
+{
+	struct inode_xattr_node *node, *n;
+
+	list_for_each_entry_safe(node, n, &inode->i_xattrs, list) {
+		if (erofs_xattr_is_opaque(node->item)) {
+			if (S_ISDIR(inode->i_mode))
+				inode->opaque = true;
+			else
+				erofs_dbg("file %s: opaque xattr on non-dir",
+					  inode->i_srcpath);
+			/* strip overlayfs xattrs */
+			list_del(&node->list);
+			free(node);
+		}
+	}
+}
+
 int erofs_xattr_insert_name_prefix(const char *prefix)
 {
 	struct ea_type_node *tnode;
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 08/16] erofs-utils: add erofs_insert_ihash() helper
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (5 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 07/16] erofs-utils: add erofs_inode_tag_opaque() helper Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 09/16] erofs-utils: add erofs_rebuild_dump_tree() helper Jingbo Xu
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Add erofs_insert_ihash() helper inserting inode into inode hash table.

Also add prototypes of erofs_iget() and erofs_iget_by_nid() in the
header file.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/inode.h |  3 +++
 lib/inode.c           | 10 +++++++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/include/erofs/inode.h b/include/erofs/inode.h
index e8a5670..1c602a8 100644
--- a/include/erofs/inode.h
+++ b/include/erofs/inode.h
@@ -25,6 +25,9 @@ u32 erofs_new_encode_dev(dev_t dev);
 unsigned char erofs_mode_to_ftype(umode_t mode);
 unsigned char erofs_ftype_to_dtype(unsigned int filetype);
 void erofs_inode_manager_init(void);
+void erofs_insert_ihash(struct erofs_inode *inode, dev_t dev, ino_t ino);
+struct erofs_inode *erofs_iget(dev_t dev, ino_t ino);
+struct erofs_inode *erofs_iget_by_nid(erofs_nid_t nid);
 unsigned int erofs_iput(struct erofs_inode *inode);
 erofs_nid_t erofs_lookupnid(struct erofs_inode *inode);
 struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent,
diff --git a/lib/inode.c b/lib/inode.c
index d54f84f..b967aab 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -75,6 +75,12 @@ void erofs_inode_manager_init(void)
 		init_list_head(&inode_hashtable[i]);
 }
 
+void erofs_insert_ihash(struct erofs_inode *inode, dev_t dev, ino_t ino)
+{
+	list_add(&inode->i_hash,
+		 &inode_hashtable[(ino ^ dev) % NR_INODE_HASHTABLE]);
+}
+
 /* get the inode from the (source) inode # */
 struct erofs_inode *erofs_iget(dev_t dev, ino_t ino)
 {
@@ -976,9 +982,7 @@ static int erofs_fill_inode(struct erofs_inode *inode, struct stat *st,
 		inode->inode_isize = sizeof(struct erofs_inode_compact);
 	}
 
-	list_add(&inode->i_hash,
-		 &inode_hashtable[(st->st_ino ^ st->st_dev) %
-				  NR_INODE_HASHTABLE]);
+	erofs_insert_ihash(inode, st->st_dev, st->st_ino);
 	return 0;
 }
 
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 09/16] erofs-utils: add erofs_rebuild_dump_tree() helper
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (6 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 08/16] erofs-utils: add erofs_insert_ihash() helper Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 10/16] erofs-utils: add erofs_rebuild_get_dentry() helper Jingbo Xu
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Enhance tarerofs_dump_tree() so that it could optionally skip whiteout
files.  Rename it to erofs_rebuild_dump_tree().

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/inode.h    |  2 +-
 include/erofs/internal.h |  2 ++
 lib/inode.c              | 23 ++++++++++++++++++++---
 lib/tar.c                |  2 --
 mkfs/main.c              |  2 +-
 5 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/include/erofs/inode.h b/include/erofs/inode.h
index 1c602a8..a43cb8f 100644
--- a/include/erofs/inode.h
+++ b/include/erofs/inode.h
@@ -32,7 +32,7 @@ unsigned int erofs_iput(struct erofs_inode *inode);
 erofs_nid_t erofs_lookupnid(struct erofs_inode *inode);
 struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent,
 				   const char *name);
-int tarerofs_dump_tree(struct erofs_inode *dir);
+int erofs_rebuild_dump_tree(struct erofs_inode *dir, bool skip_whout);
 int erofs_init_empty_dir(struct erofs_inode *dir);
 struct erofs_inode *erofs_new_inode(void);
 struct erofs_inode *erofs_mkfs_build_tree_from_path(const char *path);
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 83a2e22..be84dc1 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -415,6 +415,8 @@ static inline u32 erofs_crc32c(u32 crc, const u8 *in, size_t len)
 	return crc;
 }
 
+#define EROFS_WHITEOUT_DEV	0
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/inode.c b/lib/inode.c
index b967aab..dae6c11 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -1323,9 +1323,14 @@ struct erofs_inode *erofs_mkfs_build_special_from_fd(int fd, const char *name)
 	return inode;
 }
 
-int tarerofs_dump_tree(struct erofs_inode *dir)
+static bool erofs_inode_is_whiteout(struct erofs_inode *inode)
 {
-	struct erofs_dentry *d;
+	return S_ISCHR(inode->i_mode) && inode->u.i_rdev == EROFS_WHITEOUT_DEV;
+}
+
+int erofs_rebuild_dump_tree(struct erofs_inode *dir, bool skip_whout)
+{
+	struct erofs_dentry *d, *n;
 	unsigned int nr_subdirs;
 	int ret;
 
@@ -1368,6 +1373,18 @@ int tarerofs_dump_tree(struct erofs_inode *dir)
 		return 0;
 	}
 
+	if (skip_whout) {
+		list_for_each_entry_safe(d, n, &dir->i_subdirs, d_child) {
+			if (erofs_inode_is_whiteout(d->inode)) {
+				erofs_dbg("skip whiteout %s", d->inode->i_srcpath);
+				erofs_d_invalidate(d);
+				list_del(&d->d_child);
+				free(d);
+				continue;
+			}
+		}
+	}
+
 	nr_subdirs = 0;
 	list_for_each_entry(d, &dir->i_subdirs, d_child)
 		++nr_subdirs;
@@ -1391,7 +1408,7 @@ int tarerofs_dump_tree(struct erofs_inode *dir)
 			continue;
 
 		inode = erofs_igrab(d->inode);
-		ret = tarerofs_dump_tree(inode);
+		ret = erofs_rebuild_dump_tree(inode, skip_whout);
 		dir->i_nlink += (erofs_mode_to_ftype(inode->i_mode) == EROFS_FT_DIR);
 		erofs_iput(inode);
 		if (ret)
diff --git a/lib/tar.c b/lib/tar.c
index 3180ee4..5382c54 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -19,8 +19,6 @@
 #include "erofs/xattr.h"
 #include "erofs/blobchunk.h"
 
-#define EROFS_WHITEOUT_DEV	0
-
 static char erofs_libbuf[16384];
 
 struct tar_header {
diff --git a/mkfs/main.c b/mkfs/main.c
index 3809c71..b495a54 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -947,7 +947,7 @@ int main(int argc, char **argv)
 		if (err < 0)
 			goto exit;
 
-		err = tarerofs_dump_tree(root_inode);
+		err = erofs_rebuild_dump_tree(root_inode, false);
 		if (err < 0)
 			goto exit;
 	}
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 10/16] erofs-utils: add erofs_rebuild_get_dentry() helper
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (7 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 09/16] erofs-utils: add erofs_rebuild_dump_tree() helper Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 11/16] erofs-utils: make erofs_get_unhashed_chunk() global Jingbo Xu
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Rename tarerofs_get_dentry() to erofs_rebuild_get_dentry().

Also make `whout` and 'opq' parameter optional when `aufs` is false.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/rebuild.h |  19 +++++++
 lib/Makefile.am         |   3 +-
 lib/rebuild.c           | 117 ++++++++++++++++++++++++++++++++++++++++
 lib/tar.c               | 109 ++-----------------------------------
 4 files changed, 141 insertions(+), 107 deletions(-)
 create mode 100644 include/erofs/rebuild.h
 create mode 100644 lib/rebuild.c

diff --git a/include/erofs/rebuild.h b/include/erofs/rebuild.h
new file mode 100644
index 0000000..92873c9
--- /dev/null
+++ b/include/erofs/rebuild.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0 */
+#ifndef __EROFS_REBUILD_H
+#define __EROFS_REBUILD_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "internal.h"
+
+struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
+		char *path, bool aufs, bool *whout, bool *opq);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 08e986e..0dae4b3 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -25,6 +25,7 @@ noinst_HEADERS = $(top_srcdir)/include/erofs_fs.h \
       $(top_srcdir)/include/erofs/xattr.h \
       $(top_srcdir)/include/erofs/compress_hints.h \
       $(top_srcdir)/include/erofs/fragments.h \
+      $(top_srcdir)/include/erofs/rebuild.h \
       $(top_srcdir)/lib/liberofs_private.h
 
 noinst_HEADERS += compressor.h
@@ -32,7 +33,7 @@ liberofs_la_SOURCES = config.c io.c cache.c super.c inode.c xattr.c exclude.c \
 		      namei.c data.c compress.c compressor.c zmap.c decompress.c \
 		      compress_hints.c hashmap.c sha256.c blobchunk.c dir.c \
 		      fragments.c rb_tree.c dedupe.c uuid_unparse.c uuid.c tar.c \
-		      block_list.c bitops.c
+		      block_list.c bitops.c rebuild.c
 
 liberofs_la_CFLAGS = -Wall ${libuuid_CFLAGS} -I$(top_srcdir)/include
 if ENABLE_LZ4
diff --git a/lib/rebuild.c b/lib/rebuild.c
new file mode 100644
index 0000000..7aaa071
--- /dev/null
+++ b/lib/rebuild.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "erofs/print.h"
+#include "erofs/inode.h"
+#include "erofs/rebuild.h"
+#include "erofs/internal.h"
+
+#ifdef HAVE_LINUX_AUFS_TYPE_H
+#include <linux/aufs_type.h>
+#else
+#define AUFS_WH_PFX		".wh."
+#define AUFS_DIROPQ_NAME	AUFS_WH_PFX ".opq"
+#define AUFS_WH_DIROPQ		AUFS_WH_PFX AUFS_DIROPQ_NAME
+#endif
+
+static struct erofs_dentry *erofs_rebuild_mkdir(struct erofs_inode *dir,
+						const char *s)
+{
+	struct erofs_inode *inode;
+	struct erofs_dentry *d;
+
+	inode = erofs_new_inode();
+	if (IS_ERR(inode))
+		return ERR_CAST(inode);
+
+	inode->i_mode = S_IFDIR | 0755;
+	inode->i_parent = dir;
+	inode->i_uid = getuid();
+	inode->i_gid = getgid();
+	inode->i_mtime = inode->sbi->build_time;
+	inode->i_mtime_nsec = inode->sbi->build_time_nsec;
+	erofs_init_empty_dir(inode);
+
+	d = erofs_d_alloc(dir, s);
+	if (!IS_ERR(d)) {
+		d->type = EROFS_FT_DIR;
+		d->inode = inode;
+	}
+	return d;
+}
+
+struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
+		char *path, bool aufs, bool *whout, bool *opq)
+{
+	struct erofs_dentry *d = NULL;
+	unsigned int len = strlen(path);
+	char *s = path;
+
+	if (aufs) {
+		*whout = false;
+		*opq = false;
+	}
+
+	while (s < path + len) {
+		char *slash = memchr(s, '/', path + len - s);
+		if (slash) {
+			if (s == slash) {
+				while (*++s == '/');	/* skip '//...' */
+				continue;
+			}
+			*slash = '\0';
+		}
+
+		if (!memcmp(s, ".", 2)) {
+			/* null */
+		} else if (!memcmp(s, "..", 3)) {
+			pwd = pwd->i_parent;
+		} else {
+			struct erofs_inode *inode = NULL;
+
+			if (aufs && !slash) {
+				if (!memcmp(s, AUFS_WH_DIROPQ, sizeof(AUFS_WH_DIROPQ))) {
+					*opq = true;
+					break;
+				}
+				if (!memcmp(s, AUFS_WH_PFX, sizeof(AUFS_WH_PFX) - 1)) {
+					s += sizeof(AUFS_WH_PFX) - 1;
+					*whout = true;
+				}
+			}
+
+			list_for_each_entry(d, &pwd->i_subdirs, d_child) {
+				if (!strcmp(d->name, s)) {
+					if (d->type != EROFS_FT_DIR && slash)
+						return ERR_PTR(-EIO);
+					inode = d->inode;
+					break;
+				}
+			}
+
+			if (inode) {
+				pwd = inode;
+			} else if (!slash) {
+				d = erofs_d_alloc(pwd, s);
+				if (IS_ERR(d))
+					return d;
+				d->type = EROFS_FT_UNKNOWN;
+				d->inode = pwd;
+			} else {
+				d = erofs_rebuild_mkdir(pwd, s);
+				if (IS_ERR(d))
+					return d;
+				pwd = d->inode;
+			}
+		}
+		if (slash) {
+			*slash = '/';
+			s = slash + 1;
+		} else {
+			break;
+		}
+	}
+	return d;
+}
diff --git a/lib/tar.c b/lib/tar.c
index 5382c54..c3e864b 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -3,13 +3,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
-#ifdef HAVE_LINUX_AUFS_TYPE_H
-#include <linux/aufs_type.h>
-#else
-#define AUFS_WH_PFX		".wh."
-#define AUFS_DIROPQ_NAME	AUFS_WH_PFX ".opq"
-#define AUFS_WH_DIROPQ		AUFS_WH_PFX AUFS_DIROPQ_NAME
-#endif
 #include "erofs/print.h"
 #include "erofs/cache.h"
 #include "erofs/inode.h"
@@ -18,6 +11,7 @@
 #include "erofs/io.h"
 #include "erofs/xattr.h"
 #include "erofs/blobchunk.h"
+#include "erofs/rebuild.h"
 
 static char erofs_libbuf[16384];
 
@@ -131,103 +125,6 @@ static long long tarerofs_parsenum(const char *ptr, int len)
 	return tarerofs_otoi(ptr, len);
 }
 
-static struct erofs_dentry *tarerofs_mkdir(struct erofs_inode *dir, const char *s)
-{
-	struct erofs_inode *inode;
-	struct erofs_dentry *d;
-
-	inode = erofs_new_inode();
-	if (IS_ERR(inode))
-		return ERR_CAST(inode);
-
-	inode->i_mode = S_IFDIR | 0755;
-	inode->i_parent = dir;
-	inode->i_uid = getuid();
-	inode->i_gid = getgid();
-	inode->i_mtime = inode->sbi->build_time;
-	inode->i_mtime_nsec = inode->sbi->build_time_nsec;
-	erofs_init_empty_dir(inode);
-
-	d = erofs_d_alloc(dir, s);
-	if (!IS_ERR(d)) {
-		d->type = EROFS_FT_DIR;
-		d->inode = inode;
-	}
-	return d;
-}
-
-static struct erofs_dentry *tarerofs_get_dentry(struct erofs_inode *pwd, char *path,
-					        bool aufs, bool *whout, bool *opq)
-{
-	struct erofs_dentry *d = NULL;
-	unsigned int len = strlen(path);
-	char *s = path;
-
-	*whout = false;
-	*opq = false;
-
-	while (s < path + len) {
-		char *slash = memchr(s, '/', path + len - s);
-		if (slash) {
-			if (s == slash) {
-				while (*++s == '/');	/* skip '//...' */
-				continue;
-			}
-			*slash = '\0';
-		}
-
-		if (!memcmp(s, ".", 2)) {
-			/* null */
-		} else if (!memcmp(s, "..", 3)) {
-			pwd = pwd->i_parent;
-		} else {
-			struct erofs_inode *inode = NULL;
-
-			if (aufs && !slash) {
-				if (!memcmp(s, AUFS_WH_DIROPQ, sizeof(AUFS_WH_DIROPQ))) {
-					*opq = true;
-					break;
-				}
-				if (!memcmp(s, AUFS_WH_PFX, sizeof(AUFS_WH_PFX) - 1)) {
-					s += sizeof(AUFS_WH_PFX) - 1;
-					*whout = true;
-				}
-			}
-
-			list_for_each_entry(d, &pwd->i_subdirs, d_child) {
-				if (!strcmp(d->name, s)) {
-					if (d->type != EROFS_FT_DIR && slash)
-						return ERR_PTR(-EIO);
-					inode = d->inode;
-					break;
-				}
-			}
-
-			if (inode) {
-				pwd = inode;
-			} else if (!slash) {
-				d = erofs_d_alloc(pwd, s);
-				if (IS_ERR(d))
-					return d;
-				d->type = EROFS_FT_UNKNOWN;
-				d->inode = pwd;
-			} else {
-				d = tarerofs_mkdir(pwd, s);
-				if (IS_ERR(d))
-					return d;
-				pwd = d->inode;
-			}
-		}
-		if (slash) {
-			*slash = '/';
-			s = slash + 1;
-		} else {
-			break;
-		}
-	}
-	return d;
-}
-
 int tarerofs_parse_pax_header(int fd, struct erofs_pax_header *eh, u32 size)
 {
 	char *buf, *p;
@@ -572,7 +469,7 @@ restart:
 
 	erofs_dbg("parsing %s (mode %05o)", eh.path, st.st_mode);
 
-	d = tarerofs_get_dentry(root, eh.path, tar->aufs, &whout, &opq);
+	d = erofs_rebuild_get_dentry(root, eh.path, tar->aufs, &whout, &opq);
 	if (IS_ERR(d)) {
 		ret = PTR_ERR(d);
 		goto out;
@@ -605,7 +502,7 @@ restart:
 		}
 		d->inode = NULL;
 
-		d2 = tarerofs_get_dentry(root, eh.link, tar->aufs, &dumb, &dumb);
+		d2 = erofs_rebuild_get_dentry(root, eh.link, tar->aufs, &dumb, &dumb);
 		if (IS_ERR(d2)) {
 			ret = PTR_ERR(d2);
 			goto out;
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 11/16] erofs-utils: make erofs_get_unhashed_chunk() global
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (8 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 10/16] erofs-utils: add erofs_rebuild_get_dentry() helper Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 12/16] erofs-utils: add erofs image helper Jingbo Xu
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

... so that it could be called from outside blobchunk.c later.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/blobchunk.h | 2 ++
 lib/blobchunk.c           | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/erofs/blobchunk.h b/include/erofs/blobchunk.h
index 010aee1..fb85d8e 100644
--- a/include/erofs/blobchunk.h
+++ b/include/erofs/blobchunk.h
@@ -14,6 +14,8 @@ extern "C"
 
 #include "erofs/internal.h"
 
+struct erofs_blobchunk *erofs_get_unhashed_chunk(unsigned int device_id,
+		erofs_blk_t blkaddr, erofs_off_t sourceoffset);
 int erofs_blob_write_chunk_indexes(struct erofs_inode *inode, erofs_off_t off);
 int erofs_blob_write_chunked_file(struct erofs_inode *inode, int fd);
 int tarerofs_write_chunkes(struct erofs_inode *inode, erofs_off_t data_offset);
diff --git a/lib/blobchunk.c b/lib/blobchunk.c
index cada5bb..07f18bd 100644
--- a/lib/blobchunk.c
+++ b/lib/blobchunk.c
@@ -38,7 +38,7 @@ struct erofs_blobchunk erofs_holechunk = {
 };
 static LIST_HEAD(unhashed_blobchunks);
 
-static struct erofs_blobchunk *erofs_get_unhashed_chunk(unsigned int device_id,
+struct erofs_blobchunk *erofs_get_unhashed_chunk(unsigned int device_id,
 		erofs_blk_t blkaddr, erofs_off_t sourceoffset)
 {
 	struct erofs_blobchunk *chunk;
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 12/16] erofs-utils: add erofs image helper
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (9 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 11/16] erofs-utils: make erofs_get_unhashed_chunk() global Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 13/16] erofs-utils: add erofs_rebuild_load_tree() helper Jingbo Xu
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Later we are going to introduce new feature of merging multiple erofs
images generated from tarfs mode.  Add helpers registering and cleaning
these images.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/rebuild.h | 12 +++++++++++
 lib/rebuild.c           | 45 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/include/erofs/rebuild.h b/include/erofs/rebuild.h
index 92873c9..df7613a 100644
--- a/include/erofs/rebuild.h
+++ b/include/erofs/rebuild.h
@@ -9,6 +9,18 @@ extern "C"
 
 #include "internal.h"
 
+struct erofs_img {
+	struct list_head list;
+	char *path;
+	dev_t dev;
+	struct erofs_sb_info sbi;
+};
+
+extern unsigned int imgs_count;
+struct erofs_img *erofs_get_img(const char *path);
+int erofs_add_img(const char *path);
+void erofs_cleanup_imgs(void);
+
 struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
 		char *path, bool aufs, bool *whout, bool *opq);
 
diff --git a/lib/rebuild.c b/lib/rebuild.c
index 7aaa071..e2f6c1d 100644
--- a/lib/rebuild.c
+++ b/lib/rebuild.c
@@ -16,6 +16,9 @@
 #define AUFS_WH_DIROPQ		AUFS_WH_PFX AUFS_DIROPQ_NAME
 #endif
 
+unsigned int imgs_count;
+static LIST_HEAD(imgs_list);
+
 static struct erofs_dentry *erofs_rebuild_mkdir(struct erofs_inode *dir,
 						const char *s)
 {
@@ -115,3 +118,45 @@ struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
 	}
 	return d;
 }
+
+struct erofs_img *erofs_get_img(const char *path)
+{
+	struct erofs_img *img = malloc(sizeof(*img));
+
+	if (!img)
+		return ERR_PTR(-ENOMEM);
+
+	img->path = realpath(path, NULL);
+	if (!img->path) {
+		erofs_err("failed to parse image file (%s): %s",
+			  path, erofs_strerror(-errno));
+		free(img);
+		return ERR_PTR(-ENOENT);
+	}
+
+	img->dev = ++imgs_count;
+	return img;
+}
+
+int erofs_add_img(const char *path)
+{
+	struct erofs_img *img = erofs_get_img(path);
+
+	if (IS_ERR(img))
+		return PTR_ERR(img);
+
+	list_add_tail(&img->list, &imgs_list);
+	return 0;
+}
+
+void erofs_cleanup_imgs(void)
+{
+	struct erofs_img *img, *n;
+
+	list_for_each_entry_safe(img, n, &imgs_list, list) {
+		list_del(&img->list);
+		free(img->path);
+		free(img);
+	}
+	imgs_count = 0;
+}
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 13/16] erofs-utils: add erofs_rebuild_load_tree() helper
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (10 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 12/16] erofs-utils: add erofs image helper Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 14/16] erofs-utils: generate data block bitmap when loading tree Jingbo Xu
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Add erofs_rebuild_load_tree() helper loading inode tree from given erofs
image, and making it merged into a given inode tree in an overlayfs like
model.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/rebuild.h |   2 +
 lib/rebuild.c           | 269 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 271 insertions(+)

diff --git a/include/erofs/rebuild.h b/include/erofs/rebuild.h
index df7613a..57c0e42 100644
--- a/include/erofs/rebuild.h
+++ b/include/erofs/rebuild.h
@@ -21,6 +21,8 @@ struct erofs_img *erofs_get_img(const char *path);
 int erofs_add_img(const char *path);
 void erofs_cleanup_imgs(void);
 
+int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_img *img);
+
 struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
 		char *path, bool aufs, bool *whout, bool *opq);
 
diff --git a/lib/rebuild.c b/lib/rebuild.c
index e2f6c1d..33b539f 100644
--- a/lib/rebuild.c
+++ b/lib/rebuild.c
@@ -3,9 +3,14 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include "erofs/print.h"
 #include "erofs/inode.h"
 #include "erofs/rebuild.h"
+#include "erofs/io.h"
+#include "erofs/dir.h"
+#include "erofs/xattr.h"
+#include "erofs/blobchunk.h"
 #include "erofs/internal.h"
 
 #ifdef HAVE_LINUX_AUFS_TYPE_H
@@ -119,6 +124,270 @@ struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
 	return d;
 }
 
+static int erofs_rebuild_fill_inode_map(struct erofs_inode *inode,
+				struct erofs_inode *vi, dev_t dev)
+{
+	int ret;
+	unsigned int count, unit, chunkbits, deviceid, i;
+	erofs_off_t chunksize;
+	erofs_blk_t blkaddr;
+	struct erofs_inode_chunk_index *idx;
+
+	/* TODO: fill data map in other layouts */
+	if (vi->datalayout != EROFS_INODE_CHUNK_BASED) {
+		inode->u.i_blkaddr = NULL_ADDR;
+		return 0;
+	}
+
+	inode->u.chunkformat = vi->u.chunkformat;
+	chunkbits = vi->u.chunkbits;
+	chunksize = 1ULL << chunkbits;
+	count = DIV_ROUND_UP(inode->i_size, chunksize);
+
+	if (vi->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)
+		unit = sizeof(struct erofs_inode_chunk_index);
+	else
+		unit = EROFS_BLOCK_MAP_ENTRY_SIZE;
+
+	inode->extent_isize = count * unit;
+	idx = malloc(max(sizeof(*idx), sizeof(void *)));
+	if (!idx)
+		return -ENOMEM;
+	inode->chunkindexes = idx;
+
+	if (vi->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)
+		deviceid = dev;
+	else
+		deviceid = 0;
+
+	for (i = 0; i < count; i++) {
+		struct erofs_blobchunk *chunk;
+		struct erofs_map_blocks map = {
+			.index = UINT_MAX,
+		};
+
+		map.m_la = i << chunkbits;
+		ret = erofs_map_blocks(vi, &map, 0);
+		if (ret)
+			goto err;
+
+		blkaddr = erofs_blknr(vi->sbi, map.m_pa);
+		chunk = erofs_get_unhashed_chunk(deviceid, blkaddr, 0);
+		if (IS_ERR(chunk)) {
+			ret = PTR_ERR(chunk);
+			goto err;
+		}
+		*(void **)idx++ = chunk;
+		erofs_dbg("\t%s: chunk %d (deviceid %u, blkaddr %u)",
+			inode->i_srcpath, i, deviceid, blkaddr);
+
+	}
+	inode->datalayout = EROFS_INODE_CHUNK_BASED;
+	return 0;
+err:
+	free(idx);
+	inode->chunkindexes = NULL;
+	return ret;
+}
+
+static int erofs_rebuild_fill_inode(struct erofs_inode *inode,
+			struct erofs_inode *vi, dev_t dev)
+{
+	int ret = 0;
+
+	inode->i_srcpath = strdup(vi->i_srcpath);
+	inode->i_mode = vi->i_mode;
+	inode->i_uid = vi->i_uid;
+	inode->i_gid = vi->i_gid;
+	inode->i_mtime = vi->i_mtime;
+	inode->i_ino[1] = vi->i_ino[0];
+	inode->i_nlink = 1;
+
+	switch (inode->i_mode & S_IFMT) {
+	case S_IFCHR:
+	case S_IFBLK:
+	case S_IFIFO:
+	case S_IFSOCK:
+		inode->u.i_rdev = erofs_new_encode_dev(vi->u.i_rdev);
+		inode->i_size = 0;
+		erofs_dbg("\tdev: %d %d", major(vi->u.i_rdev),
+			  minor(vi->u.i_rdev));
+		break;
+	case S_IFDIR:
+		inode->i_size = 0;
+		ret = erofs_init_empty_dir(inode);
+		break;
+	case S_IFLNK:
+		inode->i_size = vi->i_size;
+		inode->i_link = malloc(inode->i_size + 1);
+		ret = erofs_pread(vi, inode->i_link, inode->i_size, 0);
+		erofs_dbg("\tsymlink: %s -> %s", inode->i_srcpath, inode->i_link);
+		break;
+	case S_IFREG:
+		inode->i_size = vi->i_size;
+		if (inode->i_size)
+			ret = erofs_rebuild_fill_inode_map(inode, vi, dev);
+		else
+			inode->u.i_blkaddr = NULL_ADDR;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+struct erofs_rebuild_dir_context {
+	struct erofs_dir_context ctx;
+	struct erofs_inode *root;
+	dev_t dev;
+};
+
+static int erofs_rebuild_dirent_iter(struct erofs_dir_context *ctx)
+{
+	struct erofs_rebuild_dir_context *rctx = (void *)ctx;
+	struct erofs_inode *dir = ctx->dir;
+	struct erofs_sb_info *sbi = dir->sbi;
+	struct erofs_inode *inode, vi = {};
+	struct erofs_dentry *d;
+	char *path;
+	int ret;
+
+	if (ctx->dot_dotdot)
+		return 0;
+
+	vi.nid = ctx->de_nid;
+	vi.sbi = sbi;
+	ret = erofs_read_inode_from_disk(&vi);
+	if (ret) {
+		erofs_err("file %s/%.*s: read failed",
+			  dir->i_srcpath, ctx->de_namelen, ctx->dname);
+		return ret;
+	}
+
+	ret = asprintf(&path, "%s/%.*s", dir->i_srcpath, ctx->de_namelen,
+		       ctx->dname);
+	if (ret < 0) {
+		erofs_err("file %s/%.*s: failed to alloc path",
+			  dir->i_srcpath, ctx->de_namelen, ctx->dname);
+		return ret;
+	}
+	vi.i_srcpath = path;
+
+	d = erofs_rebuild_get_dentry(rctx->root, path, false, NULL, NULL);
+	if (IS_ERR(d)) {
+		ret = PTR_ERR(d);
+		goto exit;
+	}
+
+	if (d->type != EROFS_FT_UNKNOWN) {
+		inode = d->inode;
+		DBG_BUGON((inode->i_mode & S_IFMT) != (vi.i_mode & S_IFMT));
+		if (!S_ISDIR(inode->i_mode) || inode->opaque) {
+			erofs_dbg("file %s: %s (%d) exists",
+				  path, inode->i_srcpath,
+				  erofs_mode_to_ftype(inode->i_mode));
+			free(path);
+			return 0;
+		}
+		erofs_dbg("dir %s: %s merging", path, inode->i_srcpath);
+	} else {
+		erofs_dbg("loading file: %s (%d) (nid %llu)",
+			  path, erofs_mode_to_ftype(vi.i_mode), ctx->de_nid);
+		if (S_ISREG(vi.i_mode) && vi.i_nlink > 1 &&
+		    (inode = erofs_iget(rctx->dev, vi.i_ino[0]))) {
+			/* hardlink file */
+			if (S_ISDIR(inode->i_mode)) {
+				erofs_dbg("hardlink directory not supported");
+				erofs_iput(inode);
+				return -EISDIR;
+			}
+			inode->i_nlink++;
+			erofs_dbg("\thardlink: %s -> %s", vi.i_srcpath, inode->i_srcpath);
+		} else {
+			inode = erofs_new_inode();
+			if (IS_ERR(inode)) {
+				ret = PTR_ERR(inode);
+				goto exit;
+			}
+
+			inode->i_parent = d->inode;
+			inode->dev = rctx->dev;
+			ret = erofs_rebuild_fill_inode(inode, &vi, rctx->dev);
+			if (ret)
+				goto exit_inode;
+
+			ret = erofs_read_xattrs_from_disk(&vi);
+			if (ret)
+				goto exit_inode;
+			list_splice_tail(&vi.i_xattrs, &inode->i_xattrs);
+			erofs_inode_tag_opaque(inode);
+
+			erofs_insert_ihash(inode, rctx->dev, inode->i_ino[1]);
+		}
+
+		d->inode = inode;
+		d->type = erofs_mode_to_ftype(inode->i_mode);
+	}
+
+	ret = 0;
+	if (S_ISDIR(vi.i_mode)) {
+		struct erofs_rebuild_dir_context nctx = *rctx;
+
+		nctx.ctx.dir = &vi;
+		ret = erofs_iterate_dir(&nctx.ctx, false);
+	}
+exit:
+	free(path);
+	return ret;
+exit_inode:
+	erofs_iput(inode);
+	goto exit;
+}
+
+int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_img *img)
+{
+	struct erofs_inode inode = {};
+	struct erofs_sb_info *sbi = &img->sbi;
+	struct erofs_rebuild_dir_context ctx;
+	int ret;
+
+	erofs_dbg("Loading image %s...", img->path);
+
+	ret = dev_open_ro(sbi, img->path);
+	if (ret) {
+		erofs_err("failed to open image %s", img->path);
+		return ret;
+	}
+
+	ret = erofs_read_superblock(sbi);
+	if (ret) {
+		erofs_err("failed to read superblock of image %s", img->path);
+		goto exit;
+	}
+
+	inode.nid = sbi->root_nid;
+	inode.sbi = sbi;
+	ret = erofs_read_inode_from_disk(&inode);
+	if (ret) {
+		erofs_err("failed to read root inode of image %s", img->path);
+		goto exit;
+	}
+	inode.i_srcpath = strdup("/");
+
+	ctx = (struct erofs_rebuild_dir_context) {
+		.ctx.dir = &inode,
+		.ctx.cb = erofs_rebuild_dirent_iter,
+		.root = root,
+		.dev = img->dev,
+	};
+	ret = erofs_iterate_dir(&ctx.ctx, false);
+	free(inode.i_srcpath);
+exit:
+	dev_close(sbi);
+	return ret;
+}
+
 struct erofs_img *erofs_get_img(const char *path)
 {
 	struct erofs_img *img = malloc(sizeof(*img));
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 14/16] erofs-utils: generate data block bitmap when loading tree
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (11 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 13/16] erofs-utils: add erofs_rebuild_load_tree() helper Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 15/16] erofs-utils: mkfs: add dependency on zlib_LIBS Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 16/16] erofs-utils: mkfs: introduce rebuild mode Jingbo Xu
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Enhance erofs_rebuild_load_tree() making it generate a bitmap describing
used data blocks by all regular files in given erofs image.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/rebuild.h |  3 ++-
 lib/rebuild.c           | 39 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/include/erofs/rebuild.h b/include/erofs/rebuild.h
index 57c0e42..55cd856 100644
--- a/include/erofs/rebuild.h
+++ b/include/erofs/rebuild.h
@@ -21,7 +21,8 @@ struct erofs_img *erofs_get_img(const char *path);
 int erofs_add_img(const char *path);
 void erofs_cleanup_imgs(void);
 
-int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_img *img);
+int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_img *img,
+		unsigned long **datablk_map, unsigned long *datablks);
 
 struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
 		char *path, bool aufs, bool *whout, bool *opq);
diff --git a/lib/rebuild.c b/lib/rebuild.c
index 33b539f..f641c40 100644
--- a/lib/rebuild.c
+++ b/lib/rebuild.c
@@ -11,6 +11,7 @@
 #include "erofs/dir.h"
 #include "erofs/xattr.h"
 #include "erofs/blobchunk.h"
+#include "erofs/bitops.h"
 #include "erofs/internal.h"
 
 #ifdef HAVE_LINUX_AUFS_TYPE_H
@@ -125,7 +126,7 @@ struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
 }
 
 static int erofs_rebuild_fill_inode_map(struct erofs_inode *inode,
-				struct erofs_inode *vi, dev_t dev)
+		struct erofs_inode *vi, dev_t dev, unsigned long *datablk)
 {
 	int ret;
 	unsigned int count, unit, chunkbits, deviceid, i;
@@ -178,6 +179,9 @@ static int erofs_rebuild_fill_inode_map(struct erofs_inode *inode,
 			goto err;
 		}
 		*(void **)idx++ = chunk;
+
+		if (datablk)
+			__set_bit(blkaddr, datablk);
 		erofs_dbg("\t%s: chunk %d (deviceid %u, blkaddr %u)",
 			inode->i_srcpath, i, deviceid, blkaddr);
 
@@ -191,7 +195,7 @@ err:
 }
 
 static int erofs_rebuild_fill_inode(struct erofs_inode *inode,
-			struct erofs_inode *vi, dev_t dev)
+		struct erofs_inode *vi, dev_t dev, unsigned long *datablk)
 {
 	int ret = 0;
 
@@ -226,7 +230,7 @@ static int erofs_rebuild_fill_inode(struct erofs_inode *inode,
 	case S_IFREG:
 		inode->i_size = vi->i_size;
 		if (inode->i_size)
-			ret = erofs_rebuild_fill_inode_map(inode, vi, dev);
+			ret = erofs_rebuild_fill_inode_map(inode, vi, dev, datablk);
 		else
 			inode->u.i_blkaddr = NULL_ADDR;
 		break;
@@ -241,6 +245,7 @@ struct erofs_rebuild_dir_context {
 	struct erofs_dir_context ctx;
 	struct erofs_inode *root;
 	dev_t dev;
+	unsigned long *datablk;
 };
 
 static int erofs_rebuild_dirent_iter(struct erofs_dir_context *ctx)
@@ -313,7 +318,8 @@ static int erofs_rebuild_dirent_iter(struct erofs_dir_context *ctx)
 
 			inode->i_parent = d->inode;
 			inode->dev = rctx->dev;
-			ret = erofs_rebuild_fill_inode(inode, &vi, rctx->dev);
+			ret = erofs_rebuild_fill_inode(inode, &vi, rctx->dev,
+						       rctx->datablk);
 			if (ret)
 				goto exit_inode;
 
@@ -345,11 +351,13 @@ exit_inode:
 	goto exit;
 }
 
-int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_img *img)
+int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_img *img,
+		unsigned long **datablk_map, unsigned long *datablks)
 {
 	struct erofs_inode inode = {};
 	struct erofs_sb_info *sbi = &img->sbi;
 	struct erofs_rebuild_dir_context ctx;
+	unsigned long *datablk = NULL;
 	int ret;
 
 	erofs_dbg("Loading image %s...", img->path);
@@ -366,11 +374,27 @@ int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_img *img)
 		goto exit;
 	}
 
+	if (datablk_map) {
+		if (sbi->extra_devices) {
+			erofs_err("don't support scanning data blocks for extra devices");
+			ret = -EOPNOTSUPP;
+			goto exit;
+		}
+
+		datablk = calloc(BITS_TO_LONGS(sbi->total_blocks),
+				sizeof(unsigned long));
+		if (!datablk) {
+			ret = -ENOMEM;
+			goto exit;
+		}
+	}
+
 	inode.nid = sbi->root_nid;
 	inode.sbi = sbi;
 	ret = erofs_read_inode_from_disk(&inode);
 	if (ret) {
 		erofs_err("failed to read root inode of image %s", img->path);
+		free(datablk);
 		goto exit;
 	}
 	inode.i_srcpath = strdup("/");
@@ -380,9 +404,14 @@ int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_img *img)
 		.ctx.cb = erofs_rebuild_dirent_iter,
 		.root = root,
 		.dev = img->dev,
+		.datablk = datablk,
 	};
 	ret = erofs_iterate_dir(&ctx.ctx, false);
 	free(inode.i_srcpath);
+	if (datablk_map) {
+		*datablk_map = datablk;
+		*datablks = sbi->total_blocks;
+	}
 exit:
 	dev_close(sbi);
 	return ret;
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 15/16] erofs-utils: mkfs: add dependency on zlib_LIBS
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (12 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 14/16] erofs-utils: generate data block bitmap when loading tree Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  2023-08-02  9:17 ` [PATCH v2 16/16] erofs-utils: mkfs: introduce rebuild mode Jingbo Xu
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Later we are going to introduce new feature of merging multiple erofs
images generated from tarfs mode, in which mkfs.erofs may read file data
from disk.  This requires dependency on zlib_LIBS for mkfs.erofs.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 mkfs/Makefile.am | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mkfs/Makefile.am b/mkfs/Makefile.am
index 603c2f3..dd75485 100644
--- a/mkfs/Makefile.am
+++ b/mkfs/Makefile.am
@@ -6,4 +6,5 @@ AM_CPPFLAGS = ${libselinux_CFLAGS}
 mkfs_erofs_SOURCES = main.c
 mkfs_erofs_CFLAGS = -Wall -I$(top_srcdir)/include
 mkfs_erofs_LDADD = $(top_builddir)/lib/liberofs.la ${libselinux_LIBS} \
-	${libuuid_LIBS} ${liblz4_LIBS} ${liblzma_LIBS} ${libdeflate_LIBS}
+	${libuuid_LIBS} ${liblz4_LIBS} ${liblzma_LIBS} ${zlib_LIBS} \
+	${libdeflate_LIBS}
-- 
2.19.1.6.gb485710b


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

* [PATCH v2 16/16] erofs-utils: mkfs: introduce rebuild mode
  2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
                   ` (13 preceding siblings ...)
  2023-08-02  9:17 ` [PATCH v2 15/16] erofs-utils: mkfs: add dependency on zlib_LIBS Jingbo Xu
@ 2023-08-02  9:17 ` Jingbo Xu
  14 siblings, 0 replies; 16+ messages in thread
From: Jingbo Xu @ 2023-08-02  9:17 UTC (permalink / raw)
  To: xiang, linux-erofs

Introduce a new rebuild mode merging multiple erofs images generated
from tarfs mode.  This can be called like:

	mkfs.erofs IMAGE UPPER_IMAGE LOWER_IMAGE ...

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
---
 include/erofs/rebuild.h |   1 +
 lib/rebuild.c           |  25 ++++++++++
 mkfs/main.c             | 108 +++++++++++++++++++++++++---------------
 3 files changed, 93 insertions(+), 41 deletions(-)

diff --git a/include/erofs/rebuild.h b/include/erofs/rebuild.h
index 55cd856..04fcb26 100644
--- a/include/erofs/rebuild.h
+++ b/include/erofs/rebuild.h
@@ -23,6 +23,7 @@ void erofs_cleanup_imgs(void);
 
 int erofs_rebuild_load_tree(struct erofs_inode *root, struct erofs_img *img,
 		unsigned long **datablk_map, unsigned long *datablks);
+struct erofs_inode *erofs_rebuild_load_trees(void);
 
 struct erofs_dentry *erofs_rebuild_get_dentry(struct erofs_inode *pwd,
 		char *path, bool aufs, bool *whout, bool *opq);
diff --git a/lib/rebuild.c b/lib/rebuild.c
index f641c40..d23bbdf 100644
--- a/lib/rebuild.c
+++ b/lib/rebuild.c
@@ -417,6 +417,31 @@ exit:
 	return ret;
 }
 
+struct erofs_inode *erofs_rebuild_load_trees(void)
+{
+	struct erofs_img *img;
+	struct erofs_inode *root;
+	int ret, index = 0;
+
+	root = erofs_new_inode();
+	if (IS_ERR(root))
+		return root;
+	root->i_srcpath = strdup("/");
+	root->i_mode = S_IFDIR | 0777;
+	root->i_parent = root;
+	root->i_mtime = root->sbi->build_time;
+	root->i_mtime_nsec = root->sbi->build_time_nsec;
+	erofs_init_empty_dir(root);
+
+	list_for_each_entry(img, &imgs_list, list) {
+		ret = erofs_rebuild_load_tree(root, img, NULL, NULL);
+		if (ret)
+			return ERR_PTR(ret);
+		sbi.devs[index++].blocks = img->sbi.devs[0].blocks;
+	}
+	return root;
+}
+
 struct erofs_img *erofs_get_img(const char *path)
 {
 	struct erofs_img *img = malloc(sizeof(*img));
diff --git a/mkfs/main.c b/mkfs/main.c
index b495a54..3290ec8 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -26,6 +26,7 @@
 #include "erofs/compress_hints.h"
 #include "erofs/blobchunk.h"
 #include "erofs/fragments.h"
+#include "erofs/rebuild.h"
 #include "../lib/liberofs_private.h"
 #include "../lib/liberofs_uuid.h"
 
@@ -132,6 +133,7 @@ static void usage(void)
 static unsigned int pclustersize_packed, pclustersize_max;
 static struct erofs_tarfile erofstar;
 static bool tar_mode;
+static bool rebuild_mode;
 
 static int parse_extended_opts(const char *opts)
 {
@@ -275,7 +277,8 @@ static int mkfs_parse_compress_algs(char *algs)
 static int mkfs_parse_options_cfg(int argc, char *argv[])
 {
 	char *endptr;
-	int opt, i;
+	struct stat st;
+	int opt, i, err;
 	bool quiet = false;
 
 	while ((opt = getopt_long(argc, argv, "C:E:L:T:U:b:d:x:z:",
@@ -531,7 +534,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 		} else {
 			erofstar.fd = STDIN_FILENO;
 		}
-	}else {
+	} else {
 		cfg.c_src_path = realpath(argv[optind++], NULL);
 		if (!cfg.c_src_path) {
 			erofs_err("failed to parse source directory: %s",
@@ -539,11 +542,39 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 			return -ENOENT;
 		}
 
-		if (optind < argc) {
+		if (tar_mode) {
+			erofstar.fd = open(cfg.c_src_path, O_RDONLY);
+			if (erofstar.fd < 0) {
+				erofs_err("failed to open file: %s", cfg.c_src_path);
+				usage();
+				return -errno;
+			}
+		} else {
+			err = lstat(cfg.c_src_path, &st);
+			if (err)
+				return -errno;
+			if (S_ISDIR(st.st_mode))
+				erofs_set_fs_root(cfg.c_src_path);
+			else
+				rebuild_mode = true;
+		}
+
+		if (rebuild_mode) {
+			optind--;
+			while (optind < argc) {
+				err = erofs_add_img(argv[optind++]);
+				if (err) {
+					erofs_err("failed to parse image file");
+					erofs_cleanup_imgs();
+					return err;
+				}
+			}
+		} else if (optind < argc) {
 			erofs_err("unexpected argument: %s\n", argv[optind]);
 			return -EINVAL;
 		}
 	}
+
 	if (quiet) {
 		cfg.c_dbg_lvl = EROFS_ERR;
 		cfg.c_showprogress = false;
@@ -734,7 +765,6 @@ int main(int argc, char **argv)
 	struct erofs_buffer_head *sb_bh;
 	struct erofs_inode *root_inode, *packed_inode;
 	erofs_nid_t root_nid, packed_nid;
-	struct stat st;
 	erofs_blk_t nblocks;
 	struct timeval t;
 	char uuid_str[37];
@@ -757,26 +787,6 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
-	if (!tar_mode) {
-		err = lstat(cfg.c_src_path, &st);
-		if (err)
-			return 1;
-		if (!S_ISDIR(st.st_mode)) {
-			erofs_err("root of the filesystem is not a directory - %s",
-				  cfg.c_src_path);
-			usage();
-			return 1;
-		}
-		erofs_set_fs_root(cfg.c_src_path);
-	} else if (cfg.c_src_path) {
-		erofstar.fd = open(cfg.c_src_path, O_RDONLY);
-		if (erofstar.fd < 0) {
-			erofs_err("failed to open file: %s", cfg.c_src_path);
-			usage();
-			return 1;
-		}
-	}
-
 	if (cfg.c_unix_timestamp != -1) {
 		sbi.build_time      = cfg.c_unix_timestamp;
 		sbi.build_time_nsec = 0;
@@ -843,6 +853,9 @@ int main(int argc, char **argv)
 		}
 	}
 
+	if (rebuild_mode)
+		sbi.blkszbits = 9;
+
 	sb_bh = erofs_buffer_init();
 	if (IS_ERR(sb_bh)) {
 		err = PTR_ERR(sb_bh);
@@ -900,6 +913,8 @@ int main(int argc, char **argv)
 
 	if ((erofstar.index_mode && !erofstar.mapfile) || cfg.c_blobdev_path)
 		err = erofs_mkfs_init_devices(&sbi, 1);
+	else if (rebuild_mode)
+		err = erofs_mkfs_init_devices(&sbi, imgs_count);
 	if (err) {
 		erofs_err("failed to generate device table: %s",
 			  erofs_strerror(err));
@@ -913,23 +928,7 @@ int main(int argc, char **argv)
 	if (cfg.c_extra_ea_name_prefixes)
 		erofs_xattr_write_name_prefixes(&sbi, packedfile);
 
-	if (!tar_mode) {
-		err = erofs_build_shared_xattrs_from_path(&sbi, cfg.c_src_path);
-		if (err) {
-			erofs_err("failed to build shared xattrs: %s",
-				  erofs_strerror(err));
-			goto exit;
-		}
-
-		if (cfg.c_extra_ea_name_prefixes)
-			erofs_xattr_write_name_prefixes(&sbi, packedfile);
-
-		root_inode = erofs_mkfs_build_tree_from_path(cfg.c_src_path);
-		if (IS_ERR(root_inode)) {
-			err = PTR_ERR(root_inode);
-			goto exit;
-		}
-	} else {
+	if (tar_mode) {
 		root_inode = erofs_new_inode();
 		if (IS_ERR(root_inode)) {
 			err = PTR_ERR(root_inode);
@@ -950,6 +949,32 @@ int main(int argc, char **argv)
 		err = erofs_rebuild_dump_tree(root_inode, false);
 		if (err < 0)
 			goto exit;
+	} else if (rebuild_mode) {
+		root_inode = erofs_rebuild_load_trees();
+		if (IS_ERR(root_inode)) {
+			err = PTR_ERR(root_inode);
+			goto exit;
+		}
+
+		err = erofs_rebuild_dump_tree(root_inode, true);
+		if (err)
+			goto exit;
+	} else {
+		err = erofs_build_shared_xattrs_from_path(&sbi, cfg.c_src_path);
+		if (err) {
+			erofs_err("failed to build shared xattrs: %s",
+				  erofs_strerror(err));
+			goto exit;
+		}
+
+		if (cfg.c_extra_ea_name_prefixes)
+			erofs_xattr_write_name_prefixes(&sbi, packedfile);
+
+		root_inode = erofs_mkfs_build_tree_from_path(cfg.c_src_path);
+		if (IS_ERR(root_inode)) {
+			err = PTR_ERR(root_inode);
+			goto exit;
+		}
 	}
 	root_nid = erofs_lookupnid(root_inode);
 	erofs_iput(root_inode);
@@ -1003,6 +1028,7 @@ exit:
 		z_erofs_fragments_exit();
 	erofs_packedfile_exit();
 	erofs_xattr_cleanup_name_prefixes();
+	erofs_cleanup_imgs();
 	erofs_exit_configure();
 
 	if (err) {
-- 
2.19.1.6.gb485710b


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

end of thread, other threads:[~2023-08-02  9:18 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-08-02  9:17 [PATCH v2 01/16] erofs-utils: fix tar.h Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 02/16] erofs-utils: lib: add list_splice_tail() helper Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 03/16] erofs-utils: lib: add bitops library Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 04/16] erofs-utils: read i_ino in erofs_read_inode_from_disk() Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 05/16] erofs-utils: read dis->blocks in erofs_init_devices() Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 06/16] erofs-utils: add erofs_read_xattrs_from_disk() helper Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 07/16] erofs-utils: add erofs_inode_tag_opaque() helper Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 08/16] erofs-utils: add erofs_insert_ihash() helper Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 09/16] erofs-utils: add erofs_rebuild_dump_tree() helper Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 10/16] erofs-utils: add erofs_rebuild_get_dentry() helper Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 11/16] erofs-utils: make erofs_get_unhashed_chunk() global Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 12/16] erofs-utils: add erofs image helper Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 13/16] erofs-utils: add erofs_rebuild_load_tree() helper Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 14/16] erofs-utils: generate data block bitmap when loading tree Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 15/16] erofs-utils: mkfs: add dependency on zlib_LIBS Jingbo Xu
2023-08-02  9:17 ` [PATCH v2 16/16] erofs-utils: mkfs: introduce rebuild mode Jingbo Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox