Introduce "--xattr-filter" option to enable the xattr name bloom filter feature.
Signed-off-by: Jingbo Xu <[email protected]> --- include/erofs/config.h | 1 + include/erofs/internal.h | 1 + lib/xattr.c | 74 +++++++++++++++++++++++++++++++--------- mkfs/main.c | 6 ++++ 4 files changed, 66 insertions(+), 16 deletions(-) diff --git a/include/erofs/config.h b/include/erofs/config.h index 8f52d2c..2803f37 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_filter; #ifdef HAVE_LIBSELINUX struct selabel_handle *sehnd; diff --git a/include/erofs/internal.h b/include/erofs/internal.h index ab964d4..1d7ef73 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -133,6 +133,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 7d7dc54..c9126c6 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 @@ -26,6 +27,7 @@ struct xattr_item { struct xattr_item *next_shared_xattr; const char *kvbuf; unsigned int hash[2], len[2], count; + unsigned int name_filter_bit; int shared_xattr_id; u8 prefix; struct hlist_node node; @@ -101,7 +103,8 @@ static unsigned int put_xattritem(struct xattr_item *item) } static struct xattr_item *get_xattritem(u8 prefix, char *kvbuf, - unsigned int len[2]) + unsigned int len[2], + unsigned int name_filter_bit) { struct xattr_item *item; unsigned int hash[2], hkey; @@ -133,40 +136,59 @@ static struct xattr_item *get_xattritem(u8 prefix, char *kvbuf, item->hash[1] = hash[1]; item->shared_xattr_id = -1; item->prefix = prefix; + item->name_filter_bit = name_filter_bit; hash_add(ea_hashtable, &item->node, hkey); return item; } -static bool match_prefix(const char *key, u8 *index, u16 *len) +static unsigned int erofs_xattr_calc_name_filter_bit(u8 prefix, const char *key, + unsigned int len) +{ + if (!cfg.c_xattr_filter) + return 0; + return xxh32(key, len, EROFS_XATTR_FILTER_SEED + prefix) & + EROFS_XATTR_FILTER_MASK; +} + +static bool match_short_prefix(const char *key, u8 *index, u16 *len) { struct xattr_prefix *p; - struct ea_type_node *tnode; - list_for_each_entry(tnode, &ea_name_prefixes, list) { - p = &tnode->type; + for (p = xattr_types; p < xattr_types + ARRAY_SIZE(xattr_types); ++p) { if (p->prefix && !strncmp(p->prefix, key, p->prefix_len)) { *len = p->prefix_len; - *index = tnode->index; + *index = p - xattr_types; return true; } } - for (p = xattr_types; p < xattr_types + ARRAY_SIZE(xattr_types); ++p) { + return false; +} + +static bool match_prefix(const char *key, u8 *index, u16 *len) +{ + struct xattr_prefix *p; + struct ea_type_node *tnode; + + list_for_each_entry(tnode, &ea_name_prefixes, list) { + p = &tnode->type; if (p->prefix && !strncmp(p->prefix, key, p->prefix_len)) { *len = p->prefix_len; - *index = p - xattr_types; + *index = tnode->index; return true; } } - return false; + + return match_short_prefix(key, index, len); } static struct xattr_item *parse_one_xattr(const char *path, const char *key, unsigned int keylen) { ssize_t ret; - u8 prefix; - u16 prefixlen; + u8 prefix, o_prefix; + u16 prefixlen, o_prefixlen; unsigned int len[2]; + unsigned int bit = 0; char *kvbuf; erofs_dbg("parse xattr [%s] of %s", path, key); @@ -176,6 +198,13 @@ static struct xattr_item *parse_one_xattr(const char *path, const char *key, DBG_BUGON(keylen < prefixlen); + if (cfg.c_xattr_filter) { + if (!match_short_prefix(key, &o_prefix, &o_prefixlen)) + return ERR_PTR(-ENODATA); + bit = erofs_xattr_calc_name_filter_bit(o_prefix, + key + o_prefixlen, keylen - o_prefixlen); + } + /* determine length of the value */ #ifdef HAVE_LGETXATTR ret = lgetxattr(path, key, NULL, 0); @@ -216,7 +245,7 @@ static struct xattr_item *parse_one_xattr(const char *path, const char *key, len[1] = ret; } } - return get_xattritem(prefix, kvbuf, len); + return get_xattritem(prefix, kvbuf, len, bit); } static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath, @@ -226,7 +255,7 @@ static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath, if (cfg.sehnd) { char *secontext; int ret; - unsigned int len[2]; + unsigned int bit, len[2]; char *kvbuf, *fspath; if (cfg.mount_point) @@ -260,7 +289,8 @@ static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath, } sprintf(kvbuf, "selinux%s", secontext); freecon(secontext); - return get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len); + bit = erofs_xattr_calc_name_filter_bit(EROFS_XATTR_INDEX_SECURITY, "selinux", len[0]); + return get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len, bit); } #endif return NULL; @@ -408,7 +438,7 @@ static int erofs_droid_xattr_set_caps(struct erofs_inode *inode) { const u64 capabilities = inode->capabilities; char *kvbuf; - unsigned int len[2]; + unsigned int bit, len[2]; struct vfs_cap_data caps; struct xattr_item *item; @@ -430,7 +460,8 @@ static int erofs_droid_xattr_set_caps(struct erofs_inode *inode) caps.data[1].inheritable = 0; memcpy(kvbuf + len[0], &caps, len[1]); - item = get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len); + bit = erofs_xattr_calc_name_filter_bit(EROFS_XATTR_INDEX_SECURITY, "capability", len[0]); + item = get_xattritem(EROFS_XATTR_INDEX_SECURITY, kvbuf, len, bit); if (IS_ERR(item)) return PTR_ERR(item); if (!item) @@ -754,6 +785,17 @@ 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_filter) { + u32 name_filter = 0; + + list_for_each_entry_safe(node, n, ixattrs, list) { + struct xattr_item *const item = node->item; + name_filter |= 1UL << item->name_filter_bit; + } + name_filter = EROFS_XATTR_FILTER_DEFAULT & ~name_filter; + header->h_name_filter = cpu_to_le32(name_filter); + } + 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 ac208e5..84d4414 100644 --- a/mkfs/main.c +++ b/mkfs/main.c @@ -58,6 +58,7 @@ static struct option long_options[] = { {"gid-offset", required_argument, NULL, 17}, {"mount-point", required_argument, NULL, 512}, {"xattr-prefix", required_argument, NULL, 19}, + {"xattr-filter", no_argument, NULL, 20}, #ifdef WITH_ANDROID {"product-out", required_argument, NULL, 513}, {"fs-config-file", required_argument, NULL, 514}, @@ -118,6 +119,7 @@ static void usage(void) " --random-algorithms randomize per-file algorithms (debugging only)\n" #endif " --xattr-prefix=X X=extra xattr name prefix\n" + " --xattr-filter enable xattr name bloom filter\n" " --mount-point=X X=prefix of target fs path (default: /)\n" #ifdef WITH_ANDROID "\nwith following android-specific options:\n" @@ -482,6 +484,10 @@ static int mkfs_parse_options_cfg(int argc, char *argv[]) } cfg.c_extra_ea_name_prefixes = true; break; + case 20: + cfg.c_xattr_filter = true; + erofs_sb_set_xattr_filter(); + break; case 1: usage(); exit(0); -- 2.19.1.6.gb485710b
