zap: internal interface cleanup
Similar to previous, though a much lighter touch because these are not "public" interfaces. - reorganising functions into groups, by rough function class. - matching header order to source order, to make it a little easier to find things. - adding light documentation to functions that had none. Note that I've not added any documentation for the mzap_* and fzap_* functions, as part of this commit series is laying the groundwork to hide those functions in their backend modules; such documentation would become obsolete very quickly. No actual code changes. Sponsored-by: TrueNAS Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Akash B <akash-b@hpe.com> Signed-off-by: Rob Norris <rob.norris@truenas.com> Closes #18516
This commit is contained in:
committed by
Brian Behlendorf
parent
bb304d33bb
commit
00a941ea09
+62
-15
@@ -26,6 +26,7 @@
|
||||
* Copyright (c) 2013, 2016 by Delphix. All rights reserved.
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
* Copyright (c) 2024, Klara, Inc.
|
||||
* Copyright (c) 2026, TrueNAS.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_ZAP_IMPL_H
|
||||
@@ -33,7 +34,6 @@
|
||||
|
||||
#include <sys/zap.h>
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/avl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -170,6 +170,9 @@ typedef struct zap {
|
||||
} zap_u;
|
||||
} zap_t;
|
||||
|
||||
#define zap_f zap_u.zap_fat
|
||||
#define zap_m zap_u.zap_micro
|
||||
|
||||
static inline zap_phys_t *
|
||||
zap_f_phys(zap_t *zap)
|
||||
{
|
||||
@@ -182,6 +185,10 @@ zap_m_phys(zap_t *zap)
|
||||
return (zap->zap_dbuf->db_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* zap_name_t carries the original key and whatever we've derived from it
|
||||
* (normalised form, hash, etc) as we work through completing the operation.
|
||||
*/
|
||||
typedef struct zap_name {
|
||||
zap_t *zn_zap;
|
||||
int zn_key_intlen;
|
||||
@@ -196,35 +203,74 @@ typedef struct zap_name {
|
||||
char zn_normbuf[];
|
||||
} zap_name_t;
|
||||
|
||||
#define zap_f zap_u.zap_fat
|
||||
#define zap_m zap_u.zap_micro
|
||||
/*
|
||||
* Allocate a zap_name_t. The longname flag ensures there is enough room to
|
||||
* hold a long filename when the 'longname' pool feature is active.
|
||||
*/
|
||||
zap_name_t *zap_name_alloc(zap_t *zap, boolean_t longname);
|
||||
|
||||
/*
|
||||
* Allocate a zap_name_t for the given key. zap_name_init_str() will be
|
||||
* called to normalise the key and initialise the struct.
|
||||
*/
|
||||
zap_name_t *zap_name_alloc_str(zap_t *zap, const char *key, matchtype_t mt);
|
||||
|
||||
/*
|
||||
* Allocate a zap_name_t for a uint64 array key.
|
||||
*/
|
||||
zap_name_t *zap_name_alloc_uint64(zap_t *zap, const uint64_t *key, int numints);
|
||||
|
||||
/*
|
||||
* Free a zap_name_t.
|
||||
*/
|
||||
void zap_name_free(zap_name_t *zn);
|
||||
|
||||
/*
|
||||
* Initialise an existing zap_name_t with the normalised form of the key,
|
||||
* computed according to the given matchtype.
|
||||
*/
|
||||
int zap_name_init_str(zap_name_t *zn, const char *key, matchtype_t mt);
|
||||
|
||||
/*
|
||||
* Compare 'matchname' with the name represented by the zap_name_t, applying
|
||||
* the same normalisation method first. Returns true if the normalised forms
|
||||
* match, false otherwise.
|
||||
*/
|
||||
boolean_t zap_match(zap_name_t *zn, const char *matchname);
|
||||
|
||||
/*
|
||||
* Compute and return the 64-bit hash for the name, according to the name
|
||||
* type and hash flags.
|
||||
*/
|
||||
uint64_t zap_hash(zap_name_t *zn);
|
||||
|
||||
/*
|
||||
* Return a zap_t for the given on-disk object, locked and ready for use.
|
||||
* The zap_t will be allocated and loaded from disk if its not already loaded.
|
||||
*/
|
||||
int zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
|
||||
krw_t lti, boolean_t fatreader, boolean_t adding, const void *tag,
|
||||
zap_t **zapp);
|
||||
int zap_lockdir_by_dnode(dnode_t *dn, dmu_tx_t *tx,
|
||||
krw_t lti, boolean_t fatreader, boolean_t adding, const void *tag,
|
||||
zap_t **zapp);
|
||||
|
||||
/* Underlying implementation for above; do not use. */
|
||||
int zap_lockdir_impl(dnode_t *dn, dmu_buf_t *db, const void *tag, dmu_tx_t *tx,
|
||||
krw_t lti, boolean_t fatreader, boolean_t adding, zap_t **zapp);
|
||||
|
||||
/* Unlock and release a zap_t. */
|
||||
void zap_unlockdir(zap_t *zap, const void *tag);
|
||||
|
||||
/* zap_t release function for when associated dbuf is evicted. */
|
||||
void zap_evict_sync(void *dbu);
|
||||
zap_name_t * zap_name_alloc_uint64(zap_t *zap, const uint64_t *key,
|
||||
int numints);
|
||||
zap_name_t *zap_name_alloc_str(zap_t *zap, const char *key, matchtype_t mt);
|
||||
int zap_name_init_str(zap_name_t *zn, const char *key, matchtype_t mt);
|
||||
zap_name_t * zap_name_alloc(zap_t *zap, boolean_t longname);
|
||||
void zap_name_free(zap_name_t *zn);
|
||||
|
||||
/* Misc internal state & config. */
|
||||
int zap_hashbits(zap_t *zap);
|
||||
uint32_t zap_maxcd(zap_t *zap);
|
||||
uint64_t zap_getflags(zap_t *zap);
|
||||
int zap_normalize(zap_t *zap, const char *name, char *namenorm, int normflags,
|
||||
size_t outlen);
|
||||
uint64_t zap_hash(zap_name_t *zn);
|
||||
|
||||
uint64_t zap_get_micro_max_size(spa_t *spa);
|
||||
|
||||
/* Microzap implementation. */
|
||||
zap_t *mzap_open(dmu_buf_t *db);
|
||||
int mzap_upgrade(zap_t **zapp, const void *tag, dmu_tx_t *tx,
|
||||
zap_flags_t flags);
|
||||
@@ -235,7 +281,9 @@ boolean_t mzap_normalization_conflict(zap_t *zap, zap_name_t *zn,
|
||||
mzap_ent_t *mze, zfs_btree_index_t *idx);
|
||||
void mzap_addent(zap_name_t *zn, uint64_t value);
|
||||
void mzap_byteswap(mzap_phys_t *buf, size_t size);
|
||||
uint64_t zap_get_micro_max_size(spa_t *spa);
|
||||
|
||||
/* Fatzap implementation. */
|
||||
void fzap_byteswap(void *buf, size_t size);
|
||||
int fzap_count(zap_t *zap, uint64_t *count);
|
||||
int fzap_lookup(zap_name_t *zn,
|
||||
@@ -254,7 +302,6 @@ int fzap_remove(zap_name_t *zn, dmu_tx_t *tx);
|
||||
int fzap_cursor_retrieve(zap_t *zap, zap_cursor_t *zc, zap_attribute_t *za);
|
||||
void fzap_get_stats(zap_t *zap, zap_stats_t *zs);
|
||||
void zap_put_leaf(struct zap_leaf *l);
|
||||
|
||||
int fzap_add_cd(zap_name_t *zn,
|
||||
uint64_t integer_size, uint64_t num_integers,
|
||||
const void *val, uint32_t cd, const void *tag, dmu_tx_t *tx);
|
||||
|
||||
+263
-256
@@ -26,6 +26,7 @@
|
||||
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
|
||||
* Copyright 2017 Nexenta Systems, Inc.
|
||||
* Copyright (c) 2024, Klara, Inc.
|
||||
* Copyright (c) 2026, TrueNAS.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
@@ -35,6 +36,255 @@
|
||||
#include <sys/zap.h>
|
||||
#include <sys/zap_impl.h>
|
||||
|
||||
static kmem_cache_t *zap_name_cache;
|
||||
static kmem_cache_t *zap_attr_cache;
|
||||
static kmem_cache_t *zap_name_long_cache;
|
||||
static kmem_cache_t *zap_attr_long_cache;
|
||||
|
||||
/* Setup/teardown caches. Part of the public interface in zap.h. */
|
||||
void
|
||||
zap_init(void)
|
||||
{
|
||||
zap_name_cache = kmem_cache_create("zap_name",
|
||||
sizeof (zap_name_t) + ZAP_MAXNAMELEN, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, 0);
|
||||
|
||||
zap_attr_cache = kmem_cache_create("zap_attr_cache",
|
||||
sizeof (zap_attribute_t) + ZAP_MAXNAMELEN, 0, NULL,
|
||||
NULL, NULL, NULL, NULL, 0);
|
||||
|
||||
zap_name_long_cache = kmem_cache_create("zap_name_long",
|
||||
sizeof (zap_name_t) + ZAP_MAXNAMELEN_NEW, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, 0);
|
||||
|
||||
zap_attr_long_cache = kmem_cache_create("zap_attr_long_cache",
|
||||
sizeof (zap_attribute_t) + ZAP_MAXNAMELEN_NEW, 0, NULL,
|
||||
NULL, NULL, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
zap_fini(void)
|
||||
{
|
||||
kmem_cache_destroy(zap_name_cache);
|
||||
kmem_cache_destroy(zap_attr_cache);
|
||||
kmem_cache_destroy(zap_name_long_cache);
|
||||
kmem_cache_destroy(zap_attr_long_cache);
|
||||
}
|
||||
|
||||
static int
|
||||
zap_normalize(zap_t *zap, const char *name, char *namenorm, int normflags,
|
||||
size_t outlen)
|
||||
{
|
||||
ASSERT(!(zap_getflags(zap) & ZAP_FLAG_UINT64_KEY));
|
||||
|
||||
size_t inlen = strlen(name) + 1;
|
||||
|
||||
int err = 0;
|
||||
(void) u8_textprep_str((char *)name, &inlen, namenorm, &outlen,
|
||||
normflags | U8_TEXTPREP_IGNORE_NULL | U8_TEXTPREP_IGNORE_INVALID,
|
||||
U8_UNICODE_LATEST, &err);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
zap_name_t *
|
||||
zap_name_alloc(zap_t *zap, boolean_t longname)
|
||||
{
|
||||
kmem_cache_t *cache = longname ? zap_name_long_cache : zap_name_cache;
|
||||
zap_name_t *zn = kmem_cache_alloc(cache, KM_SLEEP);
|
||||
|
||||
zn->zn_zap = zap;
|
||||
zn->zn_normbuf_len = longname ? ZAP_MAXNAMELEN_NEW : ZAP_MAXNAMELEN;
|
||||
return (zn);
|
||||
}
|
||||
|
||||
zap_name_t *
|
||||
zap_name_alloc_str(zap_t *zap, const char *key, matchtype_t mt)
|
||||
{
|
||||
size_t key_len = strlen(key) + 1;
|
||||
zap_name_t *zn = zap_name_alloc(zap, (key_len > ZAP_MAXNAMELEN));
|
||||
if (zap_name_init_str(zn, key, mt) != 0) {
|
||||
zap_name_free(zn);
|
||||
return (NULL);
|
||||
}
|
||||
return (zn);
|
||||
}
|
||||
|
||||
zap_name_t *
|
||||
zap_name_alloc_uint64(zap_t *zap, const uint64_t *key, int numints)
|
||||
{
|
||||
zap_name_t *zn = kmem_cache_alloc(zap_name_cache, KM_SLEEP);
|
||||
|
||||
ASSERT0(zap->zap_normflags);
|
||||
zn->zn_zap = zap;
|
||||
zn->zn_key_intlen = sizeof (*key);
|
||||
zn->zn_key_orig = zn->zn_key_norm = key;
|
||||
zn->zn_key_orig_numints = zn->zn_key_norm_numints = numints;
|
||||
zn->zn_matchtype = 0;
|
||||
zn->zn_normbuf_len = ZAP_MAXNAMELEN;
|
||||
|
||||
zn->zn_hash = zap_hash(zn);
|
||||
return (zn);
|
||||
}
|
||||
|
||||
void
|
||||
zap_name_free(zap_name_t *zn)
|
||||
{
|
||||
if (zn->zn_normbuf_len == ZAP_MAXNAMELEN) {
|
||||
kmem_cache_free(zap_name_cache, zn);
|
||||
} else {
|
||||
ASSERT3U(zn->zn_normbuf_len, ==, ZAP_MAXNAMELEN_NEW);
|
||||
kmem_cache_free(zap_name_long_cache, zn);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
zap_name_init_str(zap_name_t *zn, const char *key, matchtype_t mt)
|
||||
{
|
||||
zap_t *zap = zn->zn_zap;
|
||||
size_t key_len = strlen(key) + 1;
|
||||
|
||||
/* Make sure zn is allocated for longname if key is long */
|
||||
IMPLY(key_len > ZAP_MAXNAMELEN,
|
||||
zn->zn_normbuf_len == ZAP_MAXNAMELEN_NEW);
|
||||
|
||||
zn->zn_key_intlen = sizeof (*key);
|
||||
zn->zn_key_orig = key;
|
||||
zn->zn_key_orig_numints = key_len;
|
||||
zn->zn_matchtype = mt;
|
||||
zn->zn_normflags = zap->zap_normflags;
|
||||
|
||||
/*
|
||||
* If we're dealing with a case sensitive lookup on a mixed or
|
||||
* insensitive fs, remove U8_TEXTPREP_TOUPPER or the lookup
|
||||
* will fold case to all caps overriding the lookup request.
|
||||
*/
|
||||
if (mt & MT_MATCH_CASE)
|
||||
zn->zn_normflags &= ~U8_TEXTPREP_TOUPPER;
|
||||
|
||||
if (zap->zap_normflags) {
|
||||
/*
|
||||
* We *must* use zap_normflags because this normalization is
|
||||
* what the hash is computed from.
|
||||
*/
|
||||
if (zap_normalize(zap, key, zn->zn_normbuf,
|
||||
zap->zap_normflags, zn->zn_normbuf_len) != 0)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
zn->zn_key_norm = zn->zn_normbuf;
|
||||
zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1;
|
||||
} else {
|
||||
if (mt != 0)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
zn->zn_key_norm = zn->zn_key_orig;
|
||||
zn->zn_key_norm_numints = zn->zn_key_orig_numints;
|
||||
}
|
||||
|
||||
zn->zn_hash = zap_hash(zn);
|
||||
|
||||
if (zap->zap_normflags != zn->zn_normflags) {
|
||||
/*
|
||||
* We *must* use zn_normflags because this normalization is
|
||||
* what the matching is based on. (Not the hash!)
|
||||
*/
|
||||
if (zap_normalize(zap, key, zn->zn_normbuf,
|
||||
zn->zn_normflags, zn->zn_normbuf_len) != 0)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zap_match(zap_name_t *zn, const char *matchname)
|
||||
{
|
||||
boolean_t res = B_FALSE;
|
||||
ASSERT(!(zap_getflags(zn->zn_zap) & ZAP_FLAG_UINT64_KEY));
|
||||
|
||||
if (zn->zn_matchtype & MT_NORMALIZE) {
|
||||
size_t namelen = zn->zn_normbuf_len;
|
||||
char normbuf[ZAP_MAXNAMELEN];
|
||||
char *norm = normbuf;
|
||||
|
||||
/*
|
||||
* Cannot allocate this on-stack as it exceed the stack-limit of
|
||||
* 1024.
|
||||
*/
|
||||
if (namelen > ZAP_MAXNAMELEN)
|
||||
norm = kmem_alloc(namelen, KM_SLEEP);
|
||||
|
||||
if (zap_normalize(zn->zn_zap, matchname, norm,
|
||||
zn->zn_normflags, namelen) != 0) {
|
||||
res = B_FALSE;
|
||||
} else {
|
||||
res = (strcmp(zn->zn_key_norm, norm) == 0);
|
||||
}
|
||||
if (norm != normbuf)
|
||||
kmem_free(norm, namelen);
|
||||
} else {
|
||||
res = (strcmp(zn->zn_key_orig, matchname) == 0);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
zap_hash(zap_name_t *zn)
|
||||
{
|
||||
zap_t *zap = zn->zn_zap;
|
||||
uint64_t h = 0;
|
||||
|
||||
if (zap_getflags(zap) & ZAP_FLAG_PRE_HASHED_KEY) {
|
||||
ASSERT(zap_getflags(zap) & ZAP_FLAG_UINT64_KEY);
|
||||
h = *(uint64_t *)zn->zn_key_orig;
|
||||
} else {
|
||||
h = zap->zap_salt;
|
||||
ASSERT(h != 0);
|
||||
ASSERT(zfs_crc64_table[128] == ZFS_CRC64_POLY);
|
||||
|
||||
if (zap_getflags(zap) & ZAP_FLAG_UINT64_KEY) {
|
||||
const uint64_t *wp = zn->zn_key_norm;
|
||||
|
||||
ASSERT(zn->zn_key_intlen == 8);
|
||||
for (int i = 0; i < zn->zn_key_norm_numints;
|
||||
wp++, i++) {
|
||||
uint64_t word = *wp;
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
h = (h >> 8) ^
|
||||
zfs_crc64_table[(h ^ word) & 0xFF];
|
||||
word >>= NBBY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const uint8_t *cp = zn->zn_key_norm;
|
||||
|
||||
/*
|
||||
* We previously stored the terminating null on
|
||||
* disk, but didn't hash it, so we need to
|
||||
* continue to not hash it. (The
|
||||
* zn_key_*_numints includes the terminating
|
||||
* null for non-binary keys.)
|
||||
*/
|
||||
int len = zn->zn_key_norm_numints - 1;
|
||||
|
||||
ASSERT(zn->zn_key_intlen == 1);
|
||||
for (int i = 0; i < len; cp++, i++) {
|
||||
h = (h >> 8) ^
|
||||
zfs_crc64_table[(h ^ *cp) & 0xFF];
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Don't use all 64 bits, since we need some in the cookie for
|
||||
* the collision differentiator. We MUST use the high bits,
|
||||
* since those are the ones that we first pay attention to when
|
||||
* choosing the bucket.
|
||||
*/
|
||||
h &= ~((1ULL << (64 - zap_hashbits(zap))) - 1);
|
||||
|
||||
return (h);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine "consumes" the caller's hold on the dbuf, which must
|
||||
* have the specified tag.
|
||||
@@ -190,146 +440,19 @@ zap_unlockdir(zap_t *zap, const void *tag)
|
||||
dmu_buf_rele(zap->zap_dbuf, tag);
|
||||
}
|
||||
|
||||
static kmem_cache_t *zap_name_cache;
|
||||
static kmem_cache_t *zap_attr_cache;
|
||||
static kmem_cache_t *zap_name_long_cache;
|
||||
static kmem_cache_t *zap_attr_long_cache;
|
||||
|
||||
void
|
||||
zap_init(void)
|
||||
zap_evict_sync(void *dbu)
|
||||
{
|
||||
zap_name_cache = kmem_cache_create("zap_name",
|
||||
sizeof (zap_name_t) + ZAP_MAXNAMELEN, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, 0);
|
||||
zap_t *zap = dbu;
|
||||
|
||||
zap_attr_cache = kmem_cache_create("zap_attr_cache",
|
||||
sizeof (zap_attribute_t) + ZAP_MAXNAMELEN, 0, NULL,
|
||||
NULL, NULL, NULL, NULL, 0);
|
||||
rw_destroy(&zap->zap_rwlock);
|
||||
|
||||
zap_name_long_cache = kmem_cache_create("zap_name_long",
|
||||
sizeof (zap_name_t) + ZAP_MAXNAMELEN_NEW, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, 0);
|
||||
if (zap->zap_ismicro)
|
||||
mze_destroy(zap);
|
||||
else
|
||||
mutex_destroy(&zap->zap_f.zap_num_entries_mtx);
|
||||
|
||||
zap_attr_long_cache = kmem_cache_create("zap_attr_long_cache",
|
||||
sizeof (zap_attribute_t) + ZAP_MAXNAMELEN_NEW, 0, NULL,
|
||||
NULL, NULL, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
zap_fini(void)
|
||||
{
|
||||
kmem_cache_destroy(zap_name_cache);
|
||||
kmem_cache_destroy(zap_attr_cache);
|
||||
kmem_cache_destroy(zap_name_long_cache);
|
||||
kmem_cache_destroy(zap_attr_long_cache);
|
||||
}
|
||||
|
||||
zap_name_t *
|
||||
zap_name_alloc(zap_t *zap, boolean_t longname)
|
||||
{
|
||||
kmem_cache_t *cache = longname ? zap_name_long_cache : zap_name_cache;
|
||||
zap_name_t *zn = kmem_cache_alloc(cache, KM_SLEEP);
|
||||
|
||||
zn->zn_zap = zap;
|
||||
zn->zn_normbuf_len = longname ? ZAP_MAXNAMELEN_NEW : ZAP_MAXNAMELEN;
|
||||
return (zn);
|
||||
}
|
||||
|
||||
void
|
||||
zap_name_free(zap_name_t *zn)
|
||||
{
|
||||
if (zn->zn_normbuf_len == ZAP_MAXNAMELEN) {
|
||||
kmem_cache_free(zap_name_cache, zn);
|
||||
} else {
|
||||
ASSERT3U(zn->zn_normbuf_len, ==, ZAP_MAXNAMELEN_NEW);
|
||||
kmem_cache_free(zap_name_long_cache, zn);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
zap_name_init_str(zap_name_t *zn, const char *key, matchtype_t mt)
|
||||
{
|
||||
zap_t *zap = zn->zn_zap;
|
||||
size_t key_len = strlen(key) + 1;
|
||||
|
||||
/* Make sure zn is allocated for longname if key is long */
|
||||
IMPLY(key_len > ZAP_MAXNAMELEN,
|
||||
zn->zn_normbuf_len == ZAP_MAXNAMELEN_NEW);
|
||||
|
||||
zn->zn_key_intlen = sizeof (*key);
|
||||
zn->zn_key_orig = key;
|
||||
zn->zn_key_orig_numints = key_len;
|
||||
zn->zn_matchtype = mt;
|
||||
zn->zn_normflags = zap->zap_normflags;
|
||||
|
||||
/*
|
||||
* If we're dealing with a case sensitive lookup on a mixed or
|
||||
* insensitive fs, remove U8_TEXTPREP_TOUPPER or the lookup
|
||||
* will fold case to all caps overriding the lookup request.
|
||||
*/
|
||||
if (mt & MT_MATCH_CASE)
|
||||
zn->zn_normflags &= ~U8_TEXTPREP_TOUPPER;
|
||||
|
||||
if (zap->zap_normflags) {
|
||||
/*
|
||||
* We *must* use zap_normflags because this normalization is
|
||||
* what the hash is computed from.
|
||||
*/
|
||||
if (zap_normalize(zap, key, zn->zn_normbuf,
|
||||
zap->zap_normflags, zn->zn_normbuf_len) != 0)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
zn->zn_key_norm = zn->zn_normbuf;
|
||||
zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1;
|
||||
} else {
|
||||
if (mt != 0)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
zn->zn_key_norm = zn->zn_key_orig;
|
||||
zn->zn_key_norm_numints = zn->zn_key_orig_numints;
|
||||
}
|
||||
|
||||
zn->zn_hash = zap_hash(zn);
|
||||
|
||||
if (zap->zap_normflags != zn->zn_normflags) {
|
||||
/*
|
||||
* We *must* use zn_normflags because this normalization is
|
||||
* what the matching is based on. (Not the hash!)
|
||||
*/
|
||||
if (zap_normalize(zap, key, zn->zn_normbuf,
|
||||
zn->zn_normflags, zn->zn_normbuf_len) != 0)
|
||||
return (SET_ERROR(ENOTSUP));
|
||||
zn->zn_key_norm_numints = strlen(zn->zn_key_norm) + 1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
zap_name_t *
|
||||
zap_name_alloc_str(zap_t *zap, const char *key, matchtype_t mt)
|
||||
{
|
||||
size_t key_len = strlen(key) + 1;
|
||||
zap_name_t *zn = zap_name_alloc(zap, (key_len > ZAP_MAXNAMELEN));
|
||||
if (zap_name_init_str(zn, key, mt) != 0) {
|
||||
zap_name_free(zn);
|
||||
return (NULL);
|
||||
}
|
||||
return (zn);
|
||||
}
|
||||
|
||||
zap_name_t *
|
||||
zap_name_alloc_uint64(zap_t *zap, const uint64_t *key, int numints)
|
||||
{
|
||||
zap_name_t *zn = kmem_cache_alloc(zap_name_cache, KM_SLEEP);
|
||||
|
||||
ASSERT0(zap->zap_normflags);
|
||||
zn->zn_zap = zap;
|
||||
zn->zn_key_intlen = sizeof (*key);
|
||||
zn->zn_key_orig = zn->zn_key_norm = key;
|
||||
zn->zn_key_orig_numints = zn->zn_key_norm_numints = numints;
|
||||
zn->zn_matchtype = 0;
|
||||
zn->zn_normbuf_len = ZAP_MAXNAMELEN;
|
||||
|
||||
zn->zn_hash = zap_hash(zn);
|
||||
return (zn);
|
||||
kmem_free(zap, sizeof (zap_t));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@@ -358,112 +481,7 @@ zap_maxcd(zap_t *zap)
|
||||
return (-1U);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
zap_hash(zap_name_t *zn)
|
||||
{
|
||||
zap_t *zap = zn->zn_zap;
|
||||
uint64_t h = 0;
|
||||
|
||||
if (zap_getflags(zap) & ZAP_FLAG_PRE_HASHED_KEY) {
|
||||
ASSERT(zap_getflags(zap) & ZAP_FLAG_UINT64_KEY);
|
||||
h = *(uint64_t *)zn->zn_key_orig;
|
||||
} else {
|
||||
h = zap->zap_salt;
|
||||
ASSERT(h != 0);
|
||||
ASSERT(zfs_crc64_table[128] == ZFS_CRC64_POLY);
|
||||
|
||||
if (zap_getflags(zap) & ZAP_FLAG_UINT64_KEY) {
|
||||
const uint64_t *wp = zn->zn_key_norm;
|
||||
|
||||
ASSERT(zn->zn_key_intlen == 8);
|
||||
for (int i = 0; i < zn->zn_key_norm_numints;
|
||||
wp++, i++) {
|
||||
uint64_t word = *wp;
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
h = (h >> 8) ^
|
||||
zfs_crc64_table[(h ^ word) & 0xFF];
|
||||
word >>= NBBY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const uint8_t *cp = zn->zn_key_norm;
|
||||
|
||||
/*
|
||||
* We previously stored the terminating null on
|
||||
* disk, but didn't hash it, so we need to
|
||||
* continue to not hash it. (The
|
||||
* zn_key_*_numints includes the terminating
|
||||
* null for non-binary keys.)
|
||||
*/
|
||||
int len = zn->zn_key_norm_numints - 1;
|
||||
|
||||
ASSERT(zn->zn_key_intlen == 1);
|
||||
for (int i = 0; i < len; cp++, i++) {
|
||||
h = (h >> 8) ^
|
||||
zfs_crc64_table[(h ^ *cp) & 0xFF];
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Don't use all 64 bits, since we need some in the cookie for
|
||||
* the collision differentiator. We MUST use the high bits,
|
||||
* since those are the ones that we first pay attention to when
|
||||
* choosing the bucket.
|
||||
*/
|
||||
h &= ~((1ULL << (64 - zap_hashbits(zap))) - 1);
|
||||
|
||||
return (h);
|
||||
}
|
||||
|
||||
int
|
||||
zap_normalize(zap_t *zap, const char *name, char *namenorm, int normflags,
|
||||
size_t outlen)
|
||||
{
|
||||
ASSERT(!(zap_getflags(zap) & ZAP_FLAG_UINT64_KEY));
|
||||
|
||||
size_t inlen = strlen(name) + 1;
|
||||
|
||||
int err = 0;
|
||||
(void) u8_textprep_str((char *)name, &inlen, namenorm, &outlen,
|
||||
normflags | U8_TEXTPREP_IGNORE_NULL | U8_TEXTPREP_IGNORE_INVALID,
|
||||
U8_UNICODE_LATEST, &err);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
zap_match(zap_name_t *zn, const char *matchname)
|
||||
{
|
||||
boolean_t res = B_FALSE;
|
||||
ASSERT(!(zap_getflags(zn->zn_zap) & ZAP_FLAG_UINT64_KEY));
|
||||
|
||||
if (zn->zn_matchtype & MT_NORMALIZE) {
|
||||
size_t namelen = zn->zn_normbuf_len;
|
||||
char normbuf[ZAP_MAXNAMELEN];
|
||||
char *norm = normbuf;
|
||||
|
||||
/*
|
||||
* Cannot allocate this on-stack as it exceed the stack-limit of
|
||||
* 1024.
|
||||
*/
|
||||
if (namelen > ZAP_MAXNAMELEN)
|
||||
norm = kmem_alloc(namelen, KM_SLEEP);
|
||||
|
||||
if (zap_normalize(zn->zn_zap, matchname, norm,
|
||||
zn->zn_normflags, namelen) != 0) {
|
||||
res = B_FALSE;
|
||||
} else {
|
||||
res = (strcmp(zn->zn_key_norm, norm) == 0);
|
||||
}
|
||||
if (norm != normbuf)
|
||||
kmem_free(norm, namelen);
|
||||
} else {
|
||||
res = (strcmp(zn->zn_key_orig, matchname) == 0);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/* DNU byteswap callback for DMU_BSWAP_ZAP, see dmu_ot_byteswap. */
|
||||
void
|
||||
zap_byteswap(void *buf, size_t size)
|
||||
{
|
||||
@@ -477,21 +495,10 @@ zap_byteswap(void *buf, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
zap_evict_sync(void *dbu)
|
||||
{
|
||||
zap_t *zap = dbu;
|
||||
|
||||
rw_destroy(&zap->zap_rwlock);
|
||||
|
||||
if (zap->zap_ismicro)
|
||||
mze_destroy(zap);
|
||||
else
|
||||
mutex_destroy(&zap->zap_f.zap_num_entries_mtx);
|
||||
|
||||
kmem_free(zap, sizeof (zap_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Cursor attribute allocator/free. Part of the public interface in zap.h,
|
||||
* in this file to get access to the kmem caches.
|
||||
*/
|
||||
static zap_attribute_t *
|
||||
zap_attribute_alloc_impl(boolean_t longname)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user