[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