[PATCH 2/5] erofs-utils: lib: introduce `struct erofs_xattrmgr`

Gao Xiang hsiangkao at linux.alibaba.com
Tue Sep 30 16:38:44 AEST 2025


Leave it as global `g_xattrmgr` for now in this patch.

Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 include/erofs/xattr.h |   1 +
 lib/importer.c        |   4 +
 lib/xattr.c           | 170 +++++++++++++++++++++---------------------
 3 files changed, 91 insertions(+), 84 deletions(-)

diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index 3a82ad7..dc1e3ed 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -45,6 +45,7 @@ static inline unsigned int xattrblock_offset(struct erofs_inode *vi,
 
 struct erofs_importer;
 
+void erofs_xattr_init(struct erofs_sb_info *sbi);
 int erofs_scan_file_xattrs(struct erofs_inode *inode);
 int erofs_prepare_xattr_ibody(struct erofs_inode *inode, bool noroom);
 char *erofs_export_xattr_ibody(struct erofs_inode *inode);
diff --git a/lib/importer.c b/lib/importer.c
index c855d34..48d6640 100644
--- a/lib/importer.c
+++ b/lib/importer.c
@@ -9,6 +9,7 @@
 #include "erofs/inode.h"
 #include "erofs/print.h"
 #include "erofs/lock.h"
+#include "erofs/xattr.h"
 #include "liberofs_cache.h"
 #include "liberofs_compress.h"
 #include "liberofs_metabox.h"
@@ -46,6 +47,9 @@ int erofs_importer_init(struct erofs_importer *im)
 
 	erofs_importer_global_init();
 
+	subsys = "xattr";
+	erofs_xattr_init(sbi);
+
 	subsys = "compression";
 	err = z_erofs_compress_init(im);
 	if (err)
diff --git a/lib/xattr.c b/lib/xattr.c
index 2e109dc..ec3eb5e 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -1,8 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
 /*
- * Originally contributed by an anonymous person,
- * heavily changed by Li Guifu <blucerlee at gmail.com>
- *                and Gao Xiang <hsiangkao at aol.com>
+ * Copyright (C) 2019 Li Guifu <blucerlee at gmail.com>
+ *                    Gao Xiang <xiang at kernel.org>
+ * Copyright (C) 2025 Alibaba Cloud
  */
 #define _GNU_SOURCE
 #include <stdlib.h>
@@ -13,7 +13,7 @@
 #include <sys/stat.h>
 #include <dirent.h>
 #include "erofs/print.h"
-#include "erofs/hashtable.h"
+#include "erofs/list.h"
 #include "erofs/xattr.h"
 #include "erofs/fragments.h"
 #include "erofs/importer.h"
@@ -99,8 +99,6 @@ static ssize_t erofs_sys_lgetxattr(const char *path, const char *name,
 	return -1;
 }
 
-#define EA_HASHTABLE_BITS 16
-
 /* one extra byte for the trailing `\0` of attribute name */
 #define EROFS_XATTR_KSIZE(kvlen)	(kvlen[0] + 1)
 #define EROFS_XATTR_KVSIZE(kvlen)	(EROFS_XATTR_KSIZE(kvlen) + kvlen[1])
@@ -112,26 +110,37 @@ static ssize_t erofs_sys_lgetxattr(const char *path, const char *name,
  * @prefix_len:	the length of the matched long prefix if any;
  *		the length of the matched predefined short prefix otherwise
  */
-struct xattr_item {
-	struct xattr_item *next_shared_xattr;
+struct erofs_xattritem {
+	struct list_head node;
+	struct erofs_xattritem *next_shared_xattr;
 	const char *kvbuf;
 	unsigned int hash[2], len[2], count;
 	int shared_xattr_id;
 	unsigned int prefix, base_index, prefix_len;
-	struct hlist_node node;
 };
 
-struct inode_xattr_node {
+struct erofs_inode_xattr_node {
 	struct list_head list;
-	struct xattr_item *item;
+	struct erofs_xattritem *item;
 };
 
-static DECLARE_HASHTABLE(ea_hashtable, EA_HASHTABLE_BITS);
+static struct erofs_xattrmgr {
+	struct list_head hash[1 << 14];
+	struct erofs_xattritem *shared_xattrs;
+	unsigned int sharedxattr_count;
+} g_xattrmgr;
 
-static struct xattr_item *shared_xattrs_list;
-static unsigned int shared_xattrs_count;
+void erofs_xattr_init(struct erofs_sb_info *sbi)
+{
+	unsigned int i;
 
-static struct xattr_prefix {
+	if (g_xattrmgr.hash[0].next)
+		return;
+	for (i = 0; i < ARRAY_SIZE(g_xattrmgr.hash); ++i)
+		init_list_head(&g_xattrmgr.hash[i]);
+}
+
+static struct erofs_xattr_prefix {
 	const char *prefix;
 	unsigned int prefix_len;
 } xattr_types[] = {
@@ -155,7 +164,7 @@ static struct xattr_prefix {
 
 struct ea_type_node {
 	struct list_head list;
-	struct xattr_prefix type;
+	struct erofs_xattr_prefix type;
 	unsigned int index, base_index, base_len;
 };
 
@@ -165,7 +174,7 @@ static unsigned int ea_prefix_count;
 bool erofs_xattr_prefix_matches(const char *key, unsigned int *index,
 				unsigned int *len)
 {
-	struct xattr_prefix *p;
+	struct erofs_xattr_prefix *p;
 
 	*index = 0;
 	*len = 0;
@@ -191,26 +200,28 @@ static unsigned int BKDRHash(char *str, unsigned int len)
 	return hash;
 }
 
-static unsigned int put_xattritem(struct xattr_item *item)
+static unsigned int put_xattritem(struct erofs_xattritem *item)
 {
 	if (item->count > 1)
 		return --item->count;
-	hash_del(&item->node);
+	list_del(&item->node);
 	free((void *)item->kvbuf);
 	free(item);
 	return 0;
 }
 
-static struct xattr_item *get_xattritem(char *kvbuf, unsigned int len[2])
+static struct erofs_xattritem *get_xattritem(char *kvbuf, unsigned int len[2])
 {
-	struct xattr_item *item;
+	struct erofs_xattritem *item;
 	struct ea_type_node *tnode;
+	struct list_head *head;
 	unsigned int hash[2], hkey;
 
 	hash[0] = BKDRHash(kvbuf, len[0]);
 	hash[1] = BKDRHash(kvbuf + EROFS_XATTR_KSIZE(len), len[1]);
-	hkey = hash[0] ^ hash[1];
-	hash_for_each_possible(ea_hashtable, item, node, hkey) {
+	hkey = (hash[0] ^ hash[1]) & (ARRAY_SIZE(g_xattrmgr.hash) - 1);
+	head = g_xattrmgr.hash + hkey;
+	list_for_each_entry(item, head, node) {
 		if (item->len[0] == len[0] && item->len[1] == len[1] &&
 		    item->hash[0] == hash[0] && item->hash[1] == hash[1] &&
 		    !memcmp(kvbuf, item->kvbuf, EROFS_XATTR_KVSIZE(len))) {
@@ -227,7 +238,7 @@ static struct xattr_item *get_xattritem(char *kvbuf, unsigned int len[2])
 	(void)erofs_xattr_prefix_matches(kvbuf, &item->base_index,
 					 &item->prefix_len);
 	DBG_BUGON(len[0] < item->prefix_len);
-	INIT_HLIST_NODE(&item->node);
+	init_list_head(&item->node);
 	item->count = 1;
 	item->kvbuf = kvbuf;
 	item->len[0] = len[0];
@@ -246,15 +257,15 @@ static struct xattr_item *get_xattritem(char *kvbuf, unsigned int len[2])
 			break;
 		}
 	}
-	hash_add(ea_hashtable, &item->node, hkey);
+	list_add(&item->node, head);
 	return item;
 }
 
-static struct xattr_item *parse_one_xattr(const char *path, const char *key,
-					  unsigned int keylen)
+static struct erofs_xattritem *parse_one_xattr(const char *path, const char *key,
+					       unsigned int keylen)
 {
 	ssize_t ret;
-	struct xattr_item *item;
+	struct erofs_xattritem *item;
 	unsigned int len[2];
 	char *kvbuf;
 
@@ -299,8 +310,8 @@ out:
 	return ERR_PTR(ret);
 }
 
-static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
-						  mode_t mode)
+static struct erofs_xattritem *erofs_get_selabel_xattr(const char *srcpath,
+						       mode_t mode)
 {
 #ifdef HAVE_LIBSELINUX
 	if (cfg.sehnd) {
@@ -308,7 +319,7 @@ static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
 		int ret;
 		unsigned int len[2];
 		char *kvbuf, *fspath;
-		struct xattr_item *item;
+		struct erofs_xattritem *item;
 
 		if (cfg.mount_point)
 			ret = asprintf(&fspath, "/%s/%s", cfg.mount_point,
@@ -351,9 +362,9 @@ static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
 	return NULL;
 }
 
-static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
+static int inode_xattr_add(struct list_head *hlist, struct erofs_xattritem *item)
 {
-	struct inode_xattr_node *node = malloc(sizeof(*node));
+	struct erofs_inode_xattr_node *node = malloc(sizeof(*node));
 
 	if (!node)
 		return -ENOMEM;
@@ -363,23 +374,15 @@ static int inode_xattr_add(struct list_head *hlist, struct xattr_item *item)
 	return 0;
 }
 
-static int shared_xattr_add(struct xattr_item *item)
-{
-	item->next_shared_xattr = shared_xattrs_list;
-	shared_xattrs_list = item;
-	return ++shared_xattrs_count;
-}
-
-static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
+static int erofs_xattr_add(struct list_head *ixattrs, struct erofs_xattritem *item)
 {
 	if (ixattrs)
 		return inode_xattr_add(ixattrs, item);
 
 	if (item->count == cfg.c_inline_xattr_tolerance + 1) {
-		int ret = shared_xattr_add(item);
-
-		if (ret < 0)
-			return ret;
+		item->next_shared_xattr = g_xattrmgr.shared_xattrs;
+		g_xattrmgr.shared_xattrs = item;
+		++g_xattrmgr.sharedxattr_count;
 	}
 	return 0;
 }
@@ -400,7 +403,7 @@ static int read_xattrs_from_file(const char *path, mode_t mode,
 	ssize_t kllen = erofs_sys_llistxattr(path, NULL, 0);
 	char *keylst, *key, *klend;
 	unsigned int keylen;
-	struct xattr_item *item;
+	struct erofs_xattritem *item;
 	int ret;
 
 	if (kllen < 0 && errno != ENODATA && errno != EOPNOTSUPP) {
@@ -475,7 +478,7 @@ int erofs_setxattr(struct erofs_inode *inode, char *key,
 {
 	char *kvbuf;
 	unsigned int len[2];
-	struct xattr_item *item;
+	struct erofs_xattritem *item;
 
 	len[0] = strlen(key);
 	len[1] = size;
@@ -499,7 +502,7 @@ int erofs_setxattr(struct erofs_inode *inode, char *key,
 
 static void erofs_removexattr(struct erofs_inode *inode, const char *key)
 {
-	struct inode_xattr_node *node, *n;
+	struct erofs_inode_xattr_node *node, *n;
 
 	list_for_each_entry_safe(node, n, &inode->i_xattrs, list) {
 		if (!strcmp(node->item->kvbuf, key)) {
@@ -532,7 +535,7 @@ static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
 	char *kvbuf;
 	unsigned int len[2];
 	struct vfs_cap_data caps;
-	struct xattr_item *item;
+	struct erofs_xattritem *item;
 
 	if (!capabilities)
 		return 0;
@@ -654,7 +657,7 @@ out:
 }
 
 static inline unsigned int erofs_next_xattr_align(unsigned int pos,
-						  struct xattr_item *item)
+						  struct erofs_xattritem *item)
 {
 	return EROFS_XATTR_ALIGN(pos + sizeof(struct erofs_xattr_entry) +
 			item->len[0] + item->len[1] - item->prefix_len);
@@ -664,7 +667,7 @@ int erofs_prepare_xattr_ibody(struct erofs_inode *inode, bool noroom)
 {
 	unsigned int target_xattr_isize = inode->xattr_isize;
 	struct list_head *ixattrs = &inode->i_xattrs;
-	struct inode_xattr_node *node;
+	struct erofs_inode_xattr_node *node;
 	unsigned int h_shared_count;
 	int ret;
 
@@ -677,7 +680,7 @@ int erofs_prepare_xattr_ibody(struct erofs_inode *inode, bool noroom)
 	h_shared_count = 0;
 	ret = sizeof(struct erofs_xattr_ibody_header);
 	list_for_each_entry(node, ixattrs, list) {
-		struct xattr_item *item = node->item;
+		struct erofs_xattritem *item = node->item;
 
 		if (item->shared_xattr_id >= 0 && h_shared_count < UCHAR_MAX) {
 			++h_shared_count;
@@ -769,33 +772,32 @@ fail:
 
 static void erofs_cleanxattrs(bool sharedxattrs)
 {
+	struct erofs_xattritem *item, *n;
 	unsigned int i;
-	struct xattr_item *item;
-	struct hlist_node *tmp;
 
-	hash_for_each_safe(ea_hashtable, i, tmp, item, node) {
-		if (sharedxattrs && item->shared_xattr_id >= 0)
-			continue;
-
-		hash_del(&item->node);
-		free((void *)item->kvbuf);
-		free(item);
+	for (i = 0; i < ARRAY_SIZE(g_xattrmgr.hash); ++i) {
+		list_for_each_entry_safe(item, n, g_xattrmgr.hash + i, node) {
+			if (sharedxattrs && item->shared_xattr_id >= 0)
+				continue;
+			list_del(&item->node);
+			free((void *)item->kvbuf);
+			free(item);
+		}
 	}
 
 	if (sharedxattrs)
 		return;
-
-	shared_xattrs_count = 0;
+	g_xattrmgr.sharedxattr_count = 0;
 }
 
-static int comp_shared_xattr_item(const void *a, const void *b)
+static int comp_shared_xattritem(const void *a, const void *b)
 {
-	const struct xattr_item *ia, *ib;
+	const struct erofs_xattritem *ia, *ib;
 	unsigned int la, lb;
 	int ret;
 
-	ia = *((const struct xattr_item **)a);
-	ib = *((const struct xattr_item **)b);
+	ia = *((const struct erofs_xattritem **)a);
+	ib = *((const struct erofs_xattritem **)b);
 	la = EROFS_XATTR_KVSIZE(ia->len);
 	lb = EROFS_XATTR_KVSIZE(ib->len);
 
@@ -898,7 +900,7 @@ int erofs_xattr_flush_name_prefixes(struct erofs_importer *im, bool plain)
 	return 0;
 }
 
-static void erofs_write_xattr_entry(char *buf, struct xattr_item *item)
+static void erofs_write_xattr_entry(char *buf, struct erofs_xattritem *item)
 {
 	struct erofs_xattr_entry entry = {
 		.e_name_index = item->prefix,
@@ -919,11 +921,11 @@ static void erofs_write_xattr_entry(char *buf, struct xattr_item *item)
 
 int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *path)
 {
-	int ret;
+	struct erofs_xattritem *item, *n, **sorted_n;
+	unsigned int sharedxattr_count, p, i;
 	struct erofs_buffer_head *bh;
-	struct xattr_item *item, *n, **sorted_n;
 	char *buf;
-	unsigned int p, i;
+	int ret;
 	erofs_off_t off;
 	erofs_off_t shared_xattrs_size = 0;
 
@@ -932,7 +934,7 @@ int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *p
 	    cfg.c_inline_xattr_tolerance == INT_MAX)
 		return 0;
 
-	if (shared_xattrs_count) {
+	if (g_xattrmgr.sharedxattr_count) {
 		DBG_BUGON(1);
 		return -EINVAL;
 	}
@@ -940,25 +942,25 @@ int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *p
 	ret = erofs_count_all_xattrs_from_path(path);
 	if (ret)
 		return ret;
-
-	if (!shared_xattrs_count)
+	sharedxattr_count = g_xattrmgr.sharedxattr_count;
+	if (!sharedxattr_count)
 		goto out;
 
-	sorted_n = malloc((shared_xattrs_count + 1) * sizeof(n));
+	sorted_n = malloc((sharedxattr_count + 1) * sizeof(n));
 	if (!sorted_n)
 		return -ENOMEM;
 
 	i = 0;
-	while (shared_xattrs_list) {
-		item = shared_xattrs_list;
+	while (g_xattrmgr.shared_xattrs) {
+		item = g_xattrmgr.shared_xattrs;
 		sorted_n[i++] = item;
-		shared_xattrs_list = item->next_shared_xattr;
+		g_xattrmgr.shared_xattrs = item->next_shared_xattr;
 		shared_xattrs_size = erofs_next_xattr_align(shared_xattrs_size,
 							    item);
 	}
-	DBG_BUGON(i != shared_xattrs_count);
+	DBG_BUGON(i != sharedxattr_count);
 	sorted_n[i] = NULL;
-	qsort(sorted_n, shared_xattrs_count, sizeof(n), comp_shared_xattr_item);
+	qsort(sorted_n, sharedxattr_count, sizeof(n), comp_shared_xattritem);
 
 	buf = calloc(1, shared_xattrs_size);
 	if (!buf) {
@@ -980,14 +982,14 @@ int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *p
 	sbi->xattr_blkaddr = off / erofs_blksiz(sbi);
 	off %= erofs_blksiz(sbi);
 	p = 0;
-	for (i = 0; i < shared_xattrs_count; i++) {
+	for (i = 0; i < sharedxattr_count; i++) {
 		item = sorted_n[i];
 		erofs_write_xattr_entry(buf + p, item);
 		item->next_shared_xattr = sorted_n[i + 1];
 		item->shared_xattr_id = (off + p) / sizeof(__le32);
 		p = erofs_next_xattr_align(p, item);
 	}
-	shared_xattrs_list = sorted_n[0];
+	g_xattrmgr.shared_xattrs = sorted_n[0];
 	free(sorted_n);
 	bh->op = &erofs_drop_directly_bhops;
 	ret = erofs_dev_write(sbi, buf, erofs_btell(bh, false), shared_xattrs_size);
@@ -1002,8 +1004,8 @@ char *erofs_export_xattr_ibody(struct erofs_inode *inode)
 {
 	struct list_head *ixattrs = &inode->i_xattrs;
 	unsigned int size = inode->xattr_isize;
-	struct inode_xattr_node *node, *n;
-	struct xattr_item *item;
+	struct erofs_inode_xattr_node *node, *n;
+	struct erofs_xattritem *item;
 	struct erofs_xattr_ibody_header *header;
 	LIST_HEAD(ilst);
 	unsigned int p;
-- 
2.43.5



More information about the Linux-erofs mailing list