Linux-EROFS Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] erofs-utils: lib: add erofs_inode_has_xattr helper
@ 2026-11-07  4:27 Wenyuan Xu
  2026-11-07  4:27 ` [PATCH 2/2] erofs-utils: mkfs: fix origin xattrs when merging layers Wenyuan Xu
  0 siblings, 1 reply; 3+ messages in thread
From: Wenyuan Xu @ 2026-11-07  4:27 UTC (permalink / raw)
  To: xiang, linux-erofs

Allow callers to check whether an inode already has an in-memory xattr
with a given name without exposing the internal xattr structures.

Assisted-by: LLM
Signed-off-by: Wenyuan Xu <sereno.xu@deepseek.com>
---
 include/erofs/xattr.h |  1 +
 lib/xattr.c           | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index d12c292..0016ad2 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -45,6 +45,7 @@ int erofs_setxattr(struct erofs_inode *inode, int index, const char *name,
 		   const void *value, size_t size);
 int erofs_vfs_setxattr(struct erofs_inode *inode, const char *name,
 		       const void *value, size_t size);
+bool erofs_inode_has_xattr(struct erofs_inode *inode, const char *name);
 int erofs_set_opaque_xattr(struct erofs_inode *inode);
 void erofs_clear_opaque_xattr(struct erofs_inode *inode);
 bool erofs_get_opaque_from_disk(struct erofs_inode *inode);
diff --git a/lib/xattr.c b/lib/xattr.c
index d86d94a..a0ac76f 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -579,6 +579,16 @@ int erofs_vfs_setxattr(struct erofs_inode *inode, const char *name,
 	return erofs_setxattr(inode, 0, name, value, size);
 }
 
+bool erofs_inode_has_xattr(struct erofs_inode *inode, const char *name)
+{
+	struct erofs_inode_xattr_node *node;
+
+	list_for_each_entry(node, &inode->i_xattrs, list)
+		if (!strcmp(node->item->kvbuf, name))
+			return true;
+	return false;
+}
+
 static void erofs_removexattr(struct erofs_inode *inode, const char *key)
 {
 	struct erofs_inode_xattr_node *node, *n;
-- 
2.43.0



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

* [PATCH 2/2] erofs-utils: mkfs: fix origin xattrs when merging layers
  2026-11-07  4:27 [PATCH 1/2] erofs-utils: lib: add erofs_inode_has_xattr helper Wenyuan Xu
@ 2026-11-07  4:27 ` Wenyuan Xu
  2026-11-09  8:51   ` Gao Xiang
  0 siblings, 1 reply; 3+ messages in thread
From: Wenyuan Xu @ 2026-11-07  4:27 UTC (permalink / raw)
  To: xiang, linux-erofs

Only supplement empty trusted.overlay.origin xattrs on whiteout parents
during incremental builds or multi-source rebuilds. Ordinary local
directory builds and single-source rebuilds should not synthesize this
merge marker.

Preserve any existing origin xattr instead of appending a duplicate
empty entry.

Fixes: 8680f3cf94ef ("erofs-utils: mkfs: enable incremental builds for local files")
Assisted-by: LLM
Signed-off-by: Wenyuan Xu <sereno.xu@deepseek.com>
---
 include/erofs/importer.h |   1 +
 lib/inode.c              |   2 +-
 lib/xattr.c              |   2 +
 mkfs/main.c              |   2 +
 tests/Makefile.am        |   3 +
 tests/erofs/033          | 122 +++++++++++++++++++++++++++++++++++++++
 tests/erofs/033.out      |   2 +
 7 files changed, 133 insertions(+), 1 deletion(-)
 create mode 100755 tests/erofs/033
 create mode 100644 tests/erofs/033.out

diff --git a/include/erofs/importer.h b/include/erofs/importer.h
index 5141965..b8dcaf8 100644
--- a/include/erofs/importer.h
+++ b/include/erofs/importer.h
@@ -54,6 +54,7 @@ struct erofs_importer_params {
 	bool dirdata_in_metazone;
 	bool hard_dereference;
 	bool ovlfs_strip;
+	bool ovlfs_merge;		/* build involves overlayfs-style merging */
 	bool dot_omitted;
 	bool no_xattrs;			/* don't store extended attributes */
 	bool no_zcompact;
diff --git a/lib/inode.c b/lib/inode.c
index da29b5a..185bcfc 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -2134,7 +2134,7 @@ static int erofs_mkfs_handle_inode(const struct erofs_mkfs_btctx *ctx,
 	/* strip all unnecessary overlayfs xattrs when ovlfs_strip is enabled */
 	if (params->ovlfs_strip)
 		erofs_clear_opaque_xattr(inode);
-	else if (inode->whiteouts)
+	else if (params->ovlfs_merge && inode->whiteouts)
 		erofs_set_origin_xattr(inode);
 
 	if (!S_ISDIR(inode->i_mode)) {
diff --git a/lib/xattr.c b/lib/xattr.c
index a0ac76f..01a8547 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -619,6 +619,8 @@ bool erofs_get_opaque_from_disk(struct erofs_inode *inode)
 
 int erofs_set_origin_xattr(struct erofs_inode *inode)
 {
+	if (erofs_inode_has_xattr(inode, OVL_XATTR_ORIGIN))
+		return 0;
 	return erofs_vfs_setxattr(inode, OVL_XATTR_ORIGIN, NULL, 0);
 }
 
diff --git a/mkfs/main.c b/mkfs/main.c
index 93123c1..06d868a 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -1899,6 +1899,8 @@ int main(int argc, char **argv)
 	importer_params.source = cfg.c_src_path;
 	importer_params.no_datainline = mkfs_no_datainline;
 	importer_params.dot_omitted = mkfs_dot_omitted;
+	importer_params.ovlfs_merge = incremental_mode ||
+		(source_mode == EROFS_MKFS_SOURCE_REBUILD && rebuild_src_count > 1);
 	if (importer_params.dedupe == EROFS_DEDUPE_FORCE_ON &&
 	    !mkfscfg.chunkbits && !mkfscfg.total_zcfgs) {
 		erofs_err("Compression is not enabled.  Turn on chunk-based data deduplication instead.");
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 363b93d..bfd1fc2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -135,6 +135,9 @@ TESTS += erofs/031
 # 032 - check that the xattr layout does not depend on listxattr(2) order
 TESTS += erofs/032
 
+# 033 - preserve existing origin and only add empty origin when merging
+TESTS += erofs/033
+
 # NEW TEST CASE HERE
 # TESTS += erofs/999
 
diff --git a/tests/erofs/033 b/tests/erofs/033
new file mode 100755
index 0000000..1da7bca
--- /dev/null
+++ b/tests/erofs/033
@@ -0,0 +1,122 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Only supplement missing origin xattrs on whiteout parents when merging.
+# Existing origin values must survive without duplicate xattr names.
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$(echo $0 | awk '{print $((NF-1))"/"$NF}' FS="/")
+
+. "${srcdir}/common/rc"
+
+cleanup()
+{
+	cd /
+	rm -rf $tmp.*
+}
+
+_require_root
+_require_erofs
+_require_xattr
+command -v getfattr >/dev/null 2>&1 || _notrun "getfattr isn't installed"
+
+rm -f $seqres.full
+
+localdir=$tmp/$seq
+mkdir -p "$localdir/source" "$localdir/base" || _fail "mkdir failed"
+
+# Probe capabilities as root alone does not guarantee CAP_MKNOD/SYS_ADMIN.
+mknod "$localdir/probe" c 0 0 >> $seqres.full 2>&1 ||
+	_notrun "cannot create whiteouts"
+setfattr -n trusted.overlay.origin -v xxx "$localdir/source" \
+	>> $seqres.full 2>&1 || _notrun "cannot set trusted xattrs"
+getfattr -n trusted.overlay.origin --only-values "$localdir/source" \
+	> "$localdir/probe-value" 2>> $seqres.full ||
+	_notrun "cannot read trusted xattrs"
+[ "$(cat "$localdir/probe-value")" = xxx ] ||
+	_notrun "trusted xattrs are not visible"
+setfattr -x trusted.overlay.origin "$localdir/source" \
+	>> $seqres.full 2>&1 || _fail "cannot remove probe xattr"
+
+echo "QA output created by $seq"
+
+for state in absent empty value; do
+	mkdir "$localdir/source/$state" || _fail "mkdir failed"
+	mknod "$localdir/source/$state/whiteout" c 0 0 \
+		>> $seqres.full 2>&1 || _fail "cannot create whiteout"
+done
+setfattr -n trusted.overlay.origin -v '' "$localdir/source/empty" \
+	>> $seqres.full 2>&1 || _fail "cannot set empty origin"
+setfattr -n trusted.overlay.origin -v xxx "$localdir/source/value" \
+	>> $seqres.full 2>&1 || _fail "cannot set nonempty origin"
+echo base > "$localdir/base/file"
+
+# Dumping all matching names also catches duplicate names: getxattr alone
+# would retrieve the same first value for each occurrence of the name.
+check_origin()
+{
+	getfattr --absolute-names -d -m '^trusted\.overlay\.origin$' \
+		"$SCRATCH_MNT/$1" > "$localdir/attrs" 2>> $seqres.full ||
+		_fail "cannot read $case_name/$1 xattrs"
+	cat "$localdir/attrs" >> $seqres.full
+	actual=$(sed -n '/^trusted\.overlay\.origin=/p' "$localdir/attrs")
+	[ "$actual" = "$2" ] || _fail "unexpected origin in $case_name/$1"
+	[ -c "$SCRATCH_MNT/$1/whiteout" ] ||
+		_fail "whiteout lost in $case_name/$1"
+}
+
+build_image()
+{
+	$MKFS_EROFS_PROG "$@" >> $seqres.full 2>&1 ||
+		_fail "mkfs failed for $case_name"
+}
+
+case_name=localdir
+SCRATCH_DEV=$localdir/source.erofs
+build_image "$SCRATCH_DEV" "$localdir/source"
+_scratch_mount >> $seqres.full 2>&1
+check_origin absent ''
+check_origin empty 'trusted.overlay.origin=""'
+check_origin value 'trusted.overlay.origin="xxx"'
+_scratch_unmount >> $seqres.full 2>&1 || _fail "unmount failed"
+
+case_name=single-source
+SCRATCH_DEV=$localdir/single.erofs
+build_image --clean=data "$SCRATCH_DEV" "$localdir/source.erofs"
+_scratch_mount >> $seqres.full 2>&1
+check_origin absent ''
+check_origin value 'trusted.overlay.origin="xxx"'
+_scratch_unmount >> $seqres.full 2>&1 || _fail "unmount failed"
+
+case_name=base
+build_image "$localdir/base.erofs" "$localdir/base"
+
+for case_name in multi-source incremental-localdir incremental-rebuild; do
+	SCRATCH_DEV=$localdir/$case_name.erofs
+	case $case_name in
+	multi-source)
+		build_image --clean=data "$SCRATCH_DEV" \
+			"$localdir/base.erofs" "$localdir/source.erofs"
+		;;
+	incremental-*)
+		cp "$localdir/base.erofs" "$SCRATCH_DEV" || _fail "copy failed"
+		if [ "$case_name" = incremental-localdir ]; then
+			source=$localdir/source
+		else
+			source=$localdir/source.erofs
+		fi
+		build_image --incremental=data "$SCRATCH_DEV" "$source"
+		;;
+	esac
+	_scratch_mount >> $seqres.full 2>&1
+	check_origin absent 'trusted.overlay.origin=""'
+	check_origin empty 'trusted.overlay.origin=""'
+	check_origin value 'trusted.overlay.origin="xxx"'
+	[ "$(cat "$SCRATCH_MNT/file")" = base ] ||
+		_fail "base file lost in $case_name"
+	_scratch_unmount >> $seqres.full 2>&1 || _fail "unmount failed"
+done
+
+echo Silence is golden
+status=0
+exit 0
diff --git a/tests/erofs/033.out b/tests/erofs/033.out
new file mode 100644
index 0000000..c5d2914
--- /dev/null
+++ b/tests/erofs/033.out
@@ -0,0 +1,2 @@
+QA output created by 033
+Silence is golden
-- 
2.43.0



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

* Re: [PATCH 2/2] erofs-utils: mkfs: fix origin xattrs when merging layers
  2026-11-07  4:27 ` [PATCH 2/2] erofs-utils: mkfs: fix origin xattrs when merging layers Wenyuan Xu
@ 2026-11-09  8:51   ` Gao Xiang
  0 siblings, 0 replies; 3+ messages in thread
From: Gao Xiang @ 2026-11-09  8:51 UTC (permalink / raw)
  To: Wenyuan Xu; +Cc: xiang, linux-erofs

Hi Wenyuan,

On Sat, Nov 07, 2026 at 04:27:03AM +0000, Wenyuan Xu wrote:
> Only supplement empty trusted.overlay.origin xattrs on whiteout parents
> during incremental builds or multi-source rebuilds. Ordinary local
> directory builds and single-source rebuilds should not synthesize this
> merge marker.
> 
> Preserve any existing origin xattr instead of appending a duplicate
> empty entry.
> 
> Fixes: 8680f3cf94ef ("erofs-utils: mkfs: enable incremental builds for local files")
> Assisted-by: LLM
> Signed-off-by: Wenyuan Xu <sereno.xu@deepseek.com>

Can the following diff resolve the issue as well? (untested)
If possible, could you ask LLM to refine this way?

Thanks,
Gao Xiang


diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 19e38fb..1eeb78f 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -269,6 +269,7 @@ struct erofs_inode {
 	char idata_type;
 	bool lazy_tailblock;
 	bool opaque;
+	bool origin;
 	/* OVL: non-merge dir that may contain whiteout entries */
 	bool whiteouts;
 	bool dot_omitted;
diff --git a/lib/tar.c b/lib/tar.c
index 72d867c..2f3e189 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -1080,7 +1080,6 @@ out_eot:
 		 * needed if the tar tree is used soon, thus we have no chance
 		 * to generate it from xattrs.  No impact to mergefs.
 		 */
-		d->inode->opaque = true;
 		ret = erofs_set_opaque_xattr(d->inode);
 		goto out;
 	} else if (th->typeflag == '1') {	/* hard link cases */
diff --git a/lib/xattr.c b/lib/xattr.c
index c670b12..59281d3 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -452,7 +452,7 @@ static bool erofs_is_skipped_xattr(const char *key)
 }
 
 static int read_xattrs_from_file(struct erofs_sb_info *sbi, const char *path,
-				 mode_t mode, struct list_head *ixattrs)
+				 mode_t mode, struct erofs_inode *inode)
 {
 	ssize_t kllen = erofs_sys_llistxattr(path, NULL, 0);
 	char *keylst, *key, *klend;
@@ -507,10 +507,16 @@ static int read_xattrs_from_file(struct erofs_sb_info *sbi, const char *path,
 			goto err;
 		}
 
-		if (ixattrs) {
-			ret = erofs_inode_xattr_add(ixattrs, item);
+		if (inode) {
+			ret = erofs_inode_xattr_add(&inode->i_xattrs, item);
 			if (ret < 0)
 				goto err;
+			if (!strcmp(key, OVL_XATTR_OPAQUE))
+				inode->opaque = S_ISDIR(inode->i_mode);
+			if (!strcmp(key, OVL_XATTR_ORIGIN)) {
+				inode->origin = true;
+				inode->whiteouts |= S_ISDIR(inode->i_mode);
+			}
 		}
 	}
 	free(keylst);
@@ -520,8 +526,8 @@ out:
 	item = erofs_get_selabel_xattr(sbi, path, mode);
 	if (IS_ERR(item))
 		return PTR_ERR(item);
-	if (item && ixattrs)
-		ret = erofs_inode_xattr_add(ixattrs, item);
+	if (item && inode)
+		ret = erofs_inode_xattr_add(&inode->i_xattrs, item);
 	return ret;
 
 err:
@@ -595,12 +601,18 @@ static void erofs_removexattr(struct erofs_inode *inode, const char *key)
 
 int erofs_set_opaque_xattr(struct erofs_inode *inode)
 {
+	if (inode->opaque)
+		return 0;
+	inode->opaque = true;
 	return erofs_vfs_setxattr(inode, OVL_XATTR_OPAQUE, "y", 1);
 }
 
 void erofs_clear_opaque_xattr(struct erofs_inode *inode)
 {
+	if (!inode->opaque)
+		return;
 	erofs_removexattr(inode, OVL_XATTR_OPAQUE);
+	inode->opaque = false;
 }
 
 bool erofs_get_opaque_from_disk(struct erofs_inode *inode)
@@ -610,6 +622,9 @@ bool erofs_get_opaque_from_disk(struct erofs_inode *inode)
 
 int erofs_set_origin_xattr(struct erofs_inode *inode)
 {
+	if (inode->origin)
+		return 0;
+	inode->origin = true;
 	return erofs_vfs_setxattr(inode, OVL_XATTR_ORIGIN, NULL, 0);
 }
 
@@ -659,10 +674,9 @@ static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
 int erofs_scan_file_xattrs(struct erofs_inode *inode)
 {
 	int ret;
-	struct list_head *ixattrs = &inode->i_xattrs;
 
 	ret = read_xattrs_from_file(inode->sbi, inode->i_srcpath,
-				    inode->i_mode, ixattrs);
+				    inode->i_mode, inode);
 	if (ret < 0)
 		return ret;
 
@@ -721,11 +735,9 @@ int erofs_read_xattrs_from_disk(struct erofs_inode *inode)
 				goto out;
 			}
 			DBG_BUGON(ret != size);
-		} else if (S_ISDIR(inode->i_mode) &&
-			   !strcmp(key, OVL_XATTR_ORIGIN)) {
-			ret = 0;
-			inode->whiteouts = true;
-			continue;
+		} else if (!strcmp(key, OVL_XATTR_ORIGIN)) {
+			inode->origin = true;
+			inode->whiteouts |= S_ISDIR(inode->i_mode);
 		}
 
 		ret = erofs_vfs_setxattr(inode, key, value, size);
-- 
2.50.1 (Apple Git-155)


> ---
>  include/erofs/importer.h |   1 +
>  lib/inode.c              |   2 +-
>  lib/xattr.c              |   2 +
>  mkfs/main.c              |   2 +
>  tests/Makefile.am        |   3 +
>  tests/erofs/033          | 122 +++++++++++++++++++++++++++++++++++++++
>  tests/erofs/033.out      |   2 +
>  7 files changed, 133 insertions(+), 1 deletion(-)
>  create mode 100755 tests/erofs/033
>  create mode 100644 tests/erofs/033.out
> 
> diff --git a/include/erofs/importer.h b/include/erofs/importer.h
> index 5141965..b8dcaf8 100644
> --- a/include/erofs/importer.h
> +++ b/include/erofs/importer.h
> @@ -54,6 +54,7 @@ struct erofs_importer_params {
>  	bool dirdata_in_metazone;
>  	bool hard_dereference;
>  	bool ovlfs_strip;
> +	bool ovlfs_merge;		/* build involves overlayfs-style merging */
>  	bool dot_omitted;
>  	bool no_xattrs;			/* don't store extended attributes */
>  	bool no_zcompact;
> diff --git a/lib/inode.c b/lib/inode.c
> index da29b5a..185bcfc 100644
> --- a/lib/inode.c
> +++ b/lib/inode.c
> @@ -2134,7 +2134,7 @@ static int erofs_mkfs_handle_inode(const struct erofs_mkfs_btctx *ctx,
>  	/* strip all unnecessary overlayfs xattrs when ovlfs_strip is enabled */
>  	if (params->ovlfs_strip)
>  		erofs_clear_opaque_xattr(inode);
> -	else if (inode->whiteouts)
> +	else if (params->ovlfs_merge && inode->whiteouts)
>  		erofs_set_origin_xattr(inode);
>  
>  	if (!S_ISDIR(inode->i_mode)) {
> diff --git a/lib/xattr.c b/lib/xattr.c
> index a0ac76f..01a8547 100644
> --- a/lib/xattr.c
> +++ b/lib/xattr.c
> @@ -619,6 +619,8 @@ bool erofs_get_opaque_from_disk(struct erofs_inode *inode)
>  
>  int erofs_set_origin_xattr(struct erofs_inode *inode)
>  {
> +	if (erofs_inode_has_xattr(inode, OVL_XATTR_ORIGIN))
> +		return 0;
>  	return erofs_vfs_setxattr(inode, OVL_XATTR_ORIGIN, NULL, 0);
>  }
>  
> diff --git a/mkfs/main.c b/mkfs/main.c
> index 93123c1..06d868a 100644
> --- a/mkfs/main.c
> +++ b/mkfs/main.c
> @@ -1899,6 +1899,8 @@ int main(int argc, char **argv)
>  	importer_params.source = cfg.c_src_path;
>  	importer_params.no_datainline = mkfs_no_datainline;
>  	importer_params.dot_omitted = mkfs_dot_omitted;
> +	importer_params.ovlfs_merge = incremental_mode ||
> +		(source_mode == EROFS_MKFS_SOURCE_REBUILD && rebuild_src_count > 1);
>  	if (importer_params.dedupe == EROFS_DEDUPE_FORCE_ON &&
>  	    !mkfscfg.chunkbits && !mkfscfg.total_zcfgs) {
>  		erofs_err("Compression is not enabled.  Turn on chunk-based data deduplication instead.");
> diff --git a/tests/Makefile.am b/tests/Makefile.am
> index 363b93d..bfd1fc2 100644
> --- a/tests/Makefile.am
> +++ b/tests/Makefile.am
> @@ -135,6 +135,9 @@ TESTS += erofs/031
>  # 032 - check that the xattr layout does not depend on listxattr(2) order
>  TESTS += erofs/032
>  
> +# 033 - preserve existing origin and only add empty origin when merging
> +TESTS += erofs/033
> +
>  # NEW TEST CASE HERE
>  # TESTS += erofs/999
>  
> diff --git a/tests/erofs/033 b/tests/erofs/033
> new file mode 100755
> index 0000000..1da7bca
> --- /dev/null
> +++ b/tests/erofs/033
> @@ -0,0 +1,122 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# Only supplement missing origin xattrs on whiteout parents when merging.
> +# Existing origin values must survive without duplicate xattr names.
> +#
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$(echo $0 | awk '{print $((NF-1))"/"$NF}' FS="/")
> +
> +. "${srcdir}/common/rc"
> +
> +cleanup()
> +{
> +	cd /
> +	rm -rf $tmp.*
> +}
> +
> +_require_root
> +_require_erofs
> +_require_xattr
> +command -v getfattr >/dev/null 2>&1 || _notrun "getfattr isn't installed"
> +
> +rm -f $seqres.full
> +
> +localdir=$tmp/$seq
> +mkdir -p "$localdir/source" "$localdir/base" || _fail "mkdir failed"
> +
> +# Probe capabilities as root alone does not guarantee CAP_MKNOD/SYS_ADMIN.
> +mknod "$localdir/probe" c 0 0 >> $seqres.full 2>&1 ||
> +	_notrun "cannot create whiteouts"
> +setfattr -n trusted.overlay.origin -v xxx "$localdir/source" \
> +	>> $seqres.full 2>&1 || _notrun "cannot set trusted xattrs"
> +getfattr -n trusted.overlay.origin --only-values "$localdir/source" \
> +	> "$localdir/probe-value" 2>> $seqres.full ||
> +	_notrun "cannot read trusted xattrs"
> +[ "$(cat "$localdir/probe-value")" = xxx ] ||
> +	_notrun "trusted xattrs are not visible"
> +setfattr -x trusted.overlay.origin "$localdir/source" \
> +	>> $seqres.full 2>&1 || _fail "cannot remove probe xattr"
> +
> +echo "QA output created by $seq"
> +
> +for state in absent empty value; do
> +	mkdir "$localdir/source/$state" || _fail "mkdir failed"
> +	mknod "$localdir/source/$state/whiteout" c 0 0 \
> +		>> $seqres.full 2>&1 || _fail "cannot create whiteout"
> +done
> +setfattr -n trusted.overlay.origin -v '' "$localdir/source/empty" \
> +	>> $seqres.full 2>&1 || _fail "cannot set empty origin"
> +setfattr -n trusted.overlay.origin -v xxx "$localdir/source/value" \
> +	>> $seqres.full 2>&1 || _fail "cannot set nonempty origin"
> +echo base > "$localdir/base/file"
> +
> +# Dumping all matching names also catches duplicate names: getxattr alone
> +# would retrieve the same first value for each occurrence of the name.
> +check_origin()
> +{
> +	getfattr --absolute-names -d -m '^trusted\.overlay\.origin$' \
> +		"$SCRATCH_MNT/$1" > "$localdir/attrs" 2>> $seqres.full ||
> +		_fail "cannot read $case_name/$1 xattrs"
> +	cat "$localdir/attrs" >> $seqres.full
> +	actual=$(sed -n '/^trusted\.overlay\.origin=/p' "$localdir/attrs")
> +	[ "$actual" = "$2" ] || _fail "unexpected origin in $case_name/$1"
> +	[ -c "$SCRATCH_MNT/$1/whiteout" ] ||
> +		_fail "whiteout lost in $case_name/$1"
> +}
> +
> +build_image()
> +{
> +	$MKFS_EROFS_PROG "$@" >> $seqres.full 2>&1 ||
> +		_fail "mkfs failed for $case_name"
> +}
> +
> +case_name=localdir
> +SCRATCH_DEV=$localdir/source.erofs
> +build_image "$SCRATCH_DEV" "$localdir/source"
> +_scratch_mount >> $seqres.full 2>&1
> +check_origin absent ''
> +check_origin empty 'trusted.overlay.origin=""'
> +check_origin value 'trusted.overlay.origin="xxx"'
> +_scratch_unmount >> $seqres.full 2>&1 || _fail "unmount failed"
> +
> +case_name=single-source
> +SCRATCH_DEV=$localdir/single.erofs
> +build_image --clean=data "$SCRATCH_DEV" "$localdir/source.erofs"
> +_scratch_mount >> $seqres.full 2>&1
> +check_origin absent ''
> +check_origin value 'trusted.overlay.origin="xxx"'
> +_scratch_unmount >> $seqres.full 2>&1 || _fail "unmount failed"
> +
> +case_name=base
> +build_image "$localdir/base.erofs" "$localdir/base"
> +
> +for case_name in multi-source incremental-localdir incremental-rebuild; do
> +	SCRATCH_DEV=$localdir/$case_name.erofs
> +	case $case_name in
> +	multi-source)
> +		build_image --clean=data "$SCRATCH_DEV" \
> +			"$localdir/base.erofs" "$localdir/source.erofs"
> +		;;
> +	incremental-*)
> +		cp "$localdir/base.erofs" "$SCRATCH_DEV" || _fail "copy failed"
> +		if [ "$case_name" = incremental-localdir ]; then
> +			source=$localdir/source
> +		else
> +			source=$localdir/source.erofs
> +		fi
> +		build_image --incremental=data "$SCRATCH_DEV" "$source"
> +		;;
> +	esac
> +	_scratch_mount >> $seqres.full 2>&1
> +	check_origin absent 'trusted.overlay.origin=""'
> +	check_origin empty 'trusted.overlay.origin=""'
> +	check_origin value 'trusted.overlay.origin="xxx"'
> +	[ "$(cat "$SCRATCH_MNT/file")" = base ] ||
> +		_fail "base file lost in $case_name"
> +	_scratch_unmount >> $seqres.full 2>&1 || _fail "unmount failed"
> +done
> +
> +echo Silence is golden
> +status=0
> +exit 0
> diff --git a/tests/erofs/033.out b/tests/erofs/033.out
> new file mode 100644
> index 0000000..c5d2914
> --- /dev/null
> +++ b/tests/erofs/033.out
> @@ -0,0 +1,2 @@
> +QA output created by 033
> +Silence is golden
> -- 
> 2.43.0
> 
> 


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

end of thread, other threads:[~2026-11-09  8:51 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-07  4:27 [PATCH 1/2] erofs-utils: lib: add erofs_inode_has_xattr helper Wenyuan Xu
2026-11-07  4:27 ` [PATCH 2/2] erofs-utils: mkfs: fix origin xattrs when merging layers Wenyuan Xu
2026-11-09  8:51   ` Gao Xiang

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