Linux-EROFS Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Gao Xiang <xiang@kernel.org>
To: Martin Pitt <martin@piware.de>
Cc: linux-erofs@lists.ozlabs.org, Gao Xiang <xiang@kernel.org>,
	Yifan Zhao <zhaoyifan28@huawei.com>
Subject: Re: [PATCH] erofs-utils: mkfs: emit an inode's xattrs in a canonical order
Date: Sun, 2 Aug 2026 21:25:07 +0800	[thread overview]
Message-ID: <am9FM_v9vAAzlR5H@XiangdeMacBook-Pro.local> (raw)
In-Reply-To: <ampZ6MVV1nN3YzQ_@piware.de>

Hi Martin,

On Wed, Jul 29, 2026 at 09:52:08PM +0200, Martin Pitt wrote:
> listxattr(2) makes no promise about the order it reports: while e.g.
> ext4 returns a reproducible order, tmpfs varies it from inode to inode,
> so building the same tree twice can lay the same set of xattrs out
> differently and yield images that differ byte for byte. This makes the
> erofs images unreproducible.
> 
> Insert into the inode's list ordered by attribute name instead, and move
> inline attributes onto the on-stack list with list_add_tail() so the
> emitted order matches. This is the same approach as the shared attribute
> pool already does with comp_shared_xattritem().
> 
> Signed-off-by: Martin Pitt <martin@amutable.com>

Thanks for the patch!

I wonder if the following diff works too (but untested):

diff --git a/lib/xattr.c b/lib/xattr.c
index a9486e4..ed53de9 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -400,17 +400,44 @@ static struct erofs_xattritem *erofs_get_selabel_xattr(struct erofs_sb_info *sbi
 	return NULL;
 }
 
+static int erofs_comp_xattritem(const void *a, const void *b)
+{
+	const struct erofs_xattritem *ia, *ib;
+	unsigned int la, lb;
+	int ret;
+
+	ia = *((const struct erofs_xattritem **)a);
+	ib = *((const struct erofs_xattritem **)b);
+	la = EROFS_XATTR_KVSIZE(ia->len);
+	lb = EROFS_XATTR_KVSIZE(ib->len);
+
+	ret = memcmp(ia->kvbuf, ib->kvbuf, min(la, lb));
+	if (ret != 0)
+		return ret;
+	return cmpsgn(la, lb);
+}
+
 static int erofs_inode_xattr_add(struct list_head *hlist,
 				 struct erofs_xattritem *item)
 {
-	struct erofs_inode_xattr_node *node;
+	struct erofs_inode_xattr_node *node, *pos;
 
 	node = malloc(sizeof(*node));
 	if (!node)
 		return -ENOMEM;
 	init_list_head(&node->list);
 	node->item = item;
-	list_add(&node->list, hlist);
+
+	/*
+	 * Keep each inode's xattrs ordered by name.  listxattr(2) makes no
+	 * promise about the order it reports, and tmpfs varies it from inode
+	 * to inode, so appending in listing order would emit the same set of
+	 * xattrs differently from run to run and make images unreproducible.
+	 */
+	list_for_each_entry(pos, hlist, list)
+		if (erofs_comp_xattritem(item, pos->item) < 0)
+			break;
+	list_add_tail(&node->list, &pos->list);
 	return 0;
 }
 
@@ -848,24 +875,6 @@ static unsigned int erofs_cleanxattrs(struct erofs_xattrmgr *xamgr,
 	return count;
 }
 
-static int comp_shared_xattritem(const void *a, const void *b)
-{
-	const struct erofs_xattritem *ia, *ib;
-	unsigned int la, lb;
-	int ret;
-
-	ia = *((const struct erofs_xattritem **)a);
-	ib = *((const struct erofs_xattritem **)b);
-	la = EROFS_XATTR_KVSIZE(ia->len);
-	lb = EROFS_XATTR_KVSIZE(ib->len);
-
-	ret = memcmp(ia->kvbuf, ib->kvbuf, min(la, lb));
-	if (ret != 0)
-		return ret;
-
-	return la > lb;
-}
-
 int erofs_xattr_flush_name_prefixes(struct erofs_importer *im, bool plain)
 {
 	const struct erofs_importer_params *params = im->params;
@@ -1015,7 +1024,7 @@ int erofs_load_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *pa
 	}
 	DBG_BUGON(i != sharedxattr_count);
 	sorted_n[i] = NULL;
-	qsort(sorted_n, sharedxattr_count, sizeof(n), comp_shared_xattritem);
+	qsort(sorted_n, sharedxattr_count, sizeof(n), erofs_comp_xattritem);
 
 	buf = calloc(1, shared_xattrs_size);
 	if (!buf) {


Since I'd like to unify comp_shared_xattritem, if yes, could you resend
a new version (or if some bug happens) as this so I could merge this.

Thanks,
Gao Xiang



  reply	other threads:[~2026-08-02 13:25 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-29 19:52 [PATCH] erofs-utils: mkfs: emit an inode's xattrs in a canonical order Martin Pitt
2026-08-02 13:25 ` Gao Xiang [this message]
2026-08-02 13:30   ` Gao Xiang
2026-08-03 11:49     ` Martin Pitt
2026-08-03 23:14       ` Gao Xiang
2026-08-04  3:37         ` Martin Pitt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=am9FM_v9vAAzlR5H@XiangdeMacBook-Pro.local \
    --to=xiang@kernel.org \
    --cc=linux-erofs@lists.ozlabs.org \
    --cc=martin@piware.de \
    --cc=zhaoyifan28@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox