zap_leaf.c revision 9621b9b1b5a73bcacf144283477ff14c5845d6c4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* The 512-byte leaf is broken into 32 16-byte chunks.
* chunk number n means l_chunk[n], even though the header precedes it.
* the names are stored null-terminated.
*/
#include <sys/zfs_context.h>
#include <sys/zap_impl.h>
#include <sys/zap_leaf.h>
/* somewhat arbitrary, could go up to around 100k ... */
/*
* XXX This will >> by a negative number when
* lh_prefix_len > 64-ZAP_LEAF_HASH_SHIFT.
*/
#define LEAF_HASH(l, h) \
((ZAP_LEAF_HASH_NUMENTRIES-1) & \
/* #define MEMCHECK */
static void
zap_memset(void *a, int c, size_t n)
{
char *cp = a;
*cp++ = c;
}
static void
{
switch (len) {
case 1:
return;
case 2:
return;
case 4:
return;
case 8:
return;
}
ASSERT(!"bad int len");
}
static uint64_t
{
switch (len) {
case 1:
case 2:
case 4:
case 8:
}
ASSERT(!"bad int len");
return (0xFEEDFACEDEADBEEF);
}
void
{
int i;
for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES; i++)
for (i = 0; i < ZAP_LEAF_NUMCHUNKS; i++) {
struct zap_leaf_entry *le;
case ZAP_LEAF_ENTRY:
break;
case ZAP_LEAF_FREE:
break;
case ZAP_LEAF_ARRAY:
/* zap_leaf_array */
/* la_array doesn't need swapping */
break;
default:
ASSERT(!"bad leaf type");
}
}
}
void
{
int i;
for (i = 0; i < ZAP_LEAF_NUMCHUNKS; i++) {
}
l->lh_block_type = ZBT_LEAF;
l->lh_magic = ZAP_LEAF_MAGIC;
l->lh_nfree = ZAP_LEAF_NUMCHUNKS;
}
{
return (nl);
}
/*
* Routines which manipulate leaf chunks (l_chunk[]).
*/
static uint16_t
{
int chunk;
#ifdef MEMCHECK
#endif
l->lh_nfree--;
return (chunk);
}
static void
{
#ifdef MEMCHECK
#endif
l->lh_nfree++;
}
/*
* Routines which manipulate leaf arrays (zap_leaf_array type chunks).
*/
static uint16_t
int integer_size, int num_integers)
{
int byten = 0;
int len = num_integers;
while (len > 0) {
int i;
for (i = 0; i < ZAP_LEAF_ARRAY_BYTES; i++) {
if (byten == 0)
value <<= 8;
if (++byten == integer_size) {
byten = 0;
buf += integer_size;
if (--len == 0)
break;
}
}
}
return (chunk_head);
}
static void
{
zap_leaf_chunk_free(l, chunk);
}
}
/* array_len and buf_len are in integers, not bytes */
static void
char *buf)
{
int byten = 0;
/* Fast path for one 8-byte integer */
return;
}
/* Fast path for an array of 1-byte integers (eg. the entry name) */
struct zap_leaf_array *la =
}
return;
}
while (len > 0) {
int i;
for (i = 0; i < ZAP_LEAF_ARRAY_BYTES && len > 0; i++) {
byten++;
if (byten == array_int_len) {
byten = 0;
len--;
if (len == 0)
return;
buf += buf_int_len;
}
}
}
}
/*
* Only to be used on 8-bit arrays.
* array_len is actual len in bytes (not encoded le_value_length).
* buf is null-terminated.
*/
static int
{
int bseen = 0;
break;
}
}
/*
* Routines which manipulate leaf entries.
*/
int
{
struct zap_leaf_entry *le;
zeh->zeh_head_leaf = l;
for (chunkp = LEAF_HASH_ENTPTR(l, h);
continue;
zeh->zeh_found_leaf = l;
zeh->zeh_found_leaf = l;
return (0);
}
}
if (l->l_next) {
l = l->l_next;
goto again;
}
return (ENOENT);
}
/* Return (h1,cd1 >= h2,cd2) */
int
{
struct zap_leaf_entry *le;
zeh->zeh_head_leaf = l;
zeh->zeh_found_leaf = l;
}
}
}
if (l->l_next) {
l = l->l_next;
goto again;
}
}
int
{
struct zap_leaf_entry *le;
return (EINVAL);
return (EOVERFLOW);
return (0);
}
int
{
struct zap_leaf_entry *le;
return (EOVERFLOW);
return (0);
}
int
{
int delta_chunks;
struct zap_leaf_entry *le;
return (EAGAIN);
/*
* We should search other chained leaves (via
* zap_entry_remove,create?) otherwise returning EAGAIN will
* just send us into an infinite loop if we have to chain
* another leaf block, rather than being able to split this
* block.
*/
le->le_value_chunk =
return (0);
}
void
{
struct zap_leaf_entry *le;
l->lh_nentries--;
}
int
{
struct zap_leaf_entry *le;
int numchunks;
zeh->zeh_head_leaf = l;
if (namelen > MAXNAMELEN)
return (ENAMETOOLONG);
/* find the first leaf in the chain that has sufficient free space */
if (numchunks > ZAP_LEAF_NUMCHUNKS)
return (E2BIG);
zap_leaf_t *ll;
break;
}
}
/*
* if this cd is in use, no need to
* check more chained leafs
*/
break;
}
/* If this cd is not in use, we are good. */
break;
}
/* If we tried all the cd's, we lose. */
return (ENOSPC);
}
for (; l; l = l->l_next)
break;
if (l == NULL)
return (EAGAIN);
zeh->zeh_found_leaf = l;
/* make the entry */
chunk = zap_leaf_chunk_alloc(l);
le->le_value_chunk =
/* link it into the hash chain */
chunkp = LEAF_HASH_ENTPTR(l, h);
l->lh_nentries++;
return (0);
}
/*
* Routines for transferring entries between leafs.
*/
static void
{
}
static void
{
int i;
if (l->lh_nentries == 0)
return;
/* break existing hash chains */
for (i = 0; i < ZAP_LEAF_NUMCHUNKS; i++) {
continue;
zap_leaf_rehash_entry(l, i);
}
}
static uint16_t
{
struct zap_leaf_array *nla =
struct zap_leaf_array *la =
zap_leaf_chunk_free(l, chunk);
}
return (new_chunk);
}
static void
{
zap_leaf_t *nl;
/* find a leaf in the destination leaf chain with enough free space */
break;
dprintf("transfer_entry: chaining leaf %x/%d\n",
}
zap_leaf_chunk_free(l, entry);
l->lh_nentries--;
nl->lh_nentries++;
}
/*
* Transfer entries whose hash bit 'bit' is 1 to nl1, and 0 to nl0.
* Ignore leaf chaining in source (l), but chain in destinations.
* We'll re-chain all the entries in l as we go along.
*/
static void
{
int i;
/* break existing hash chains */
if (nl0 != l)
for (i = 0; i < ZAP_LEAF_NUMCHUNKS; i++) {
continue;
/*
* We could find entries via hashtable instead. That
* would be O(hashents+numents) rather than
* O(numblks+numents), but this accesses memory more
* sequentially, and when we're called, the block is
* usually pretty full.
*/
} else {
if (nl0 == l)
zap_leaf_rehash_entry(l, i);
else
}
}
}
/*
* nl will contain the entries whose hash prefix ends in 1
* handles leaf chaining
*/
{
zap_leaf_t *l = hl;
/* set new prefix and prefix_len */
hl->lh_prefix_len++;
/* transfer odd entries from first leaf in hl chain to nl */
/* take rest of chain off hl */
/* transfer even entries from hl chain back to hl, odd entries to nl */
while (l) {
l = next;
}
return (nl);
}
void
{
int n, nchained = 0;
zs->zs_leafs_with_2n_pointers[n]++;
do {
int i;
n = l->lh_nentries/5;
zs->zs_blocks_with_n5_entries[n]++;
n = ((1<<ZAP_BLOCK_SHIFT) -
(1<<ZAP_BLOCK_SHIFT);
zs->zs_blocks_n_tenths_full[n]++;
for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES; i++) {
int nentries = 0;
struct zap_leaf_entry *le =
le->le_int_size);
zs->zs_entries_using_n_chunks[n]++;
nentries++;
}
n = nentries;
zs->zs_buckets_with_n_entries[n]++;
}
nchained++;
l = l->l_next;
} while (l);
n = nchained-1;
zs->zs_leafs_with_n_chained[n]++;
}