From 1ce79a9a7b0cd4a3d4a73c18c096c63f5534a89c Mon Sep 17 00:00:00 2001 From: Jingbo Xu Date: Tue, 29 Aug 2023 22:55:04 +0800 Subject: [PATCH] erofs-utils: mkfs,dump: introduce xattr name filter feature Introduce "-Exattr-name-filter" option to enable the xattr name bloom filter feature. Also support listing this feature in dump.erofs. Signed-off-by: Jingbo Xu Link: https://lore.kernel.org/r/20230829145504.93567-4-jefflexu@linux.alibaba.com [ Gao Xiang: update the commit subject. ] Signed-off-by: Gao Xiang --- dump/main.c | 1 + include/erofs/config.h | 1 + include/erofs/internal.h | 1 + lib/xattr.c | 65 ++++++++++++++++++++++++++++++++++++++++ mkfs/main.c | 7 +++++ 5 files changed, 75 insertions(+) diff --git a/dump/main.c b/dump/main.c index 7980f78..5425b7b 100644 --- a/dump/main.c +++ b/dump/main.c @@ -91,6 +91,7 @@ struct erofsdump_feature { static struct erofsdump_feature feature_lists[] = { { true, EROFS_FEATURE_COMPAT_SB_CHKSUM, "sb_csum" }, { true, EROFS_FEATURE_COMPAT_MTIME, "mtime" }, + { true, EROFS_FEATURE_COMPAT_XATTR_FILTER, "xattr_filter" }, { false, EROFS_FEATURE_INCOMPAT_ZERO_PADDING, "0padding" }, { false, EROFS_FEATURE_INCOMPAT_COMPR_CFGS, "compr_cfgs" }, { false, EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER, "big_pcluster" }, diff --git a/include/erofs/config.h b/include/erofs/config.h index 8f52d2c..c51f0cd 100644 --- a/include/erofs/config.h +++ b/include/erofs/config.h @@ -53,6 +53,7 @@ struct erofs_configure { bool c_ignore_mtime; bool c_showprogress; bool c_extra_ea_name_prefixes; + bool c_xattr_name_filter; #ifdef HAVE_LIBSELINUX struct selabel_handle *sehnd; diff --git a/include/erofs/internal.h b/include/erofs/internal.h index 3e73eef..382024a 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -139,6 +139,7 @@ EROFS_FEATURE_FUNCS(fragments, incompat, INCOMPAT_FRAGMENTS) EROFS_FEATURE_FUNCS(dedupe, incompat, INCOMPAT_DEDUPE) EROFS_FEATURE_FUNCS(xattr_prefixes, incompat, INCOMPAT_XATTR_PREFIXES) EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) +EROFS_FEATURE_FUNCS(xattr_filter, compat, COMPAT_XATTR_FILTER) #define EROFS_I_EA_INITED (1 << 0) #define EROFS_I_Z_INITED (1 << 1) diff --git a/lib/xattr.c b/lib/xattr.c index 46a301a..65dd9a0 100644 --- a/lib/xattr.c +++ b/lib/xattr.c @@ -18,6 +18,7 @@ #include "erofs/cache.h" #include "erofs/io.h" #include "erofs/fragments.h" +#include "erofs/xxhash.h" #include "liberofs_private.h" #define EA_HASHTABLE_BITS 16 @@ -783,6 +784,65 @@ out: return ret; } +static int erofs_xattr_filter_hashbit(struct xattr_item *item) +{ + u8 prefix = item->prefix; + const char *key = item->kvbuf; + unsigned int len = item->len[0]; + char *name = NULL; + uint32_t hashbit; + + if (prefix & EROFS_XATTR_LONG_PREFIX) { + struct ea_type_node *tnode; + u16 prefix_len; + int ret; + + list_for_each_entry(tnode, &ea_name_prefixes, list) { + if (tnode->index == item->prefix) { + ret = asprintf(&name, "%s%.*s", + tnode->type.prefix, len, key); + if (ret < 0) + return -ENOMEM; + break; + } + } + if (!name) + return -ENOENT; + + if (!match_base_prefix(name, &prefix, &prefix_len)) { + free(name); + return -ENOENT; + } + key = name + prefix_len; + len = strlen(key); + } + + hashbit = xxh32(key, len, EROFS_XATTR_FILTER_SEED + prefix) & + (EROFS_XATTR_FILTER_BITS - 1); + if (name) + free(name); + return hashbit; +} + +static u32 erofs_xattr_filter_map(struct list_head *ixattrs) +{ + struct inode_xattr_node *node, *n; + u32 name_filter; + int hashbit; + + name_filter = 0; + list_for_each_entry_safe(node, n, ixattrs, list) { + hashbit = erofs_xattr_filter_hashbit(node->item); + if (hashbit < 0) { + erofs_warn("failed to generate xattr name filter: %s", + strerror(-hashbit)); + return 0; + } + name_filter |= (1UL << hashbit); + } + return EROFS_XATTR_FILTER_DEFAULT & ~name_filter; +} + char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size) { struct inode_xattr_node *node, *n; @@ -797,6 +857,11 @@ char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size) header = (struct erofs_xattr_ibody_header *)buf; header->h_shared_count = 0; + if (cfg.c_xattr_name_filter) { + header->h_name_filter = + cpu_to_le32(erofs_xattr_filter_map(ixattrs)); + } + p = sizeof(struct erofs_xattr_ibody_header); list_for_each_entry_safe(node, n, ixattrs, list) { struct xattr_item *const item = node->item; diff --git a/mkfs/main.c b/mkfs/main.c index c03a7a8..fad80b1 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -245,6 +245,13 @@ handle_fragment: return -EINVAL; cfg.c_dedupe = true; } + + if (MATCH_EXTENTED_OPT("xattr-name-filter", token, keylen)) { + if (vallen) + return -EINVAL; + cfg.c_xattr_name_filter = true; + erofs_sb_set_xattr_filter(&sbi); + } } return 0; } -- 2.34.1