zap.c revision f65e61c04bc28ffd6bda04619c84330b420450b5
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains the top half of the zfs directory structure
* implementation. The bottom half is in zap_leaf.c.
*
* The zdir is an extendable hash data structure. There is a table of
* pointers to buckets (zap_t->zd_data->zd_leafs). The buckets are
* each a constant size and hold a variable number of directory entries.
* The buckets (aka "leaf nodes") are implemented in zap_leaf.c.
*
* The pointer table holds a power of 2 number of pointers.
* (1<<zap_t->zd_data->zd_phys->zd_prefix_len). The bucket pointed to
* by the pointer at index i in the table holds entries whose hash value
* has a zd_prefix_len - bit prefix
*/
#include <sys/zfs_context.h>
#include <sys/zap_impl.h>
#include <sys/zap_leaf.h>
void
{
switch (block_type) {
case ZBT_LEAF:
return;
case ZBT_HEADER:
case BSWAP_64(ZBT_HEADER):
default:
/* it's a ptrtbl block */
return;
}
}
void
{
zap_leaf_t *l;
int i;
zap_phys_t *zp;
/*
* explicitly zero it since it might be coming from an
* initialized microzap
*/
zp->zap_num_entries = 0;
/* block 1 will be the first leaf */
/*
* set up block 1 - the first leaf
*/
zap_leaf_init(l);
kmem_free(l, sizeof (zap_leaf_t));
}
static int
{
return (1);
return (1);
}
return (0);
}
/*
* Generic routines for dealing with the pointer & cookie tables.
*/
static void
{
/* hepb = half the number of entries in a block */
if (tbl->zt_nextblk != 0) {
} else {
}
/*
* Copy the ptrtbl from the old to new location, leaving the odd
* entries blank as we go.
*/
b = tbl->zt_blks_copied;
/* first half of entries in old[b] go to new[2*b+0] */
/* second half of entries in old[b] go to new[2*b+1] */
tbl->zt_blks_copied++;
dprintf("copied block %llu of %llu\n",
tbl->zt_nextblk = 0;
tbl->zt_blks_copied = 0;
dprintf("finished; numblocks now %llu (%lluk entries)\n",
}
}
static uint64_t
{
if (tbl->zt_nextblk != 0) {
idx *= 2;
}
return (oldval);
}
static uint64_t
{
return (val);
}
/*
* Routines for growing the ptrtbl.
*/
static void
{
int i;
for (i = 0; i < n; i++) {
}
}
static void
{
return;
/*
* We are outgrowing the "embedded" ptrtbl (the one
* stored in the header block). Give it its own entire
* block, which will double the size of the ptrtbl.
*/
} else {
}
}
static void
{
}
{
}
return (newblk);
}
/*
* This function doesn't increment zap_num_leafs because it's used to
* allocate a leaf chain, which doesn't count against zap_num_leafs.
* The directory must be held exclusively for this tx.
*/
{
void *winner;
/* hence we already dirtied zap->zap_dbuf */
zap_leaf_init(l);
return (l);
}
/* ARGSUSED */
void
{
/* uint64_t offset = l->l_blkid << ZAP_BLOCK_SHIFT; */
dmu_buf_rele(l->l_dbuf);
/* XXX there are still holds on this block, so we can't free it? */
/* dmu_free_range(zap->zap_objset, zap->zap_object, */
/* offset, 1<<ZAP_BLOCK_SHIFT, tx); */
}
int
{
return (0);
}
/*
* Routines for obtaining zap_leaf_t's
*/
void
{
while (nl) {
}
dmu_buf_rele(l->l_dbuf);
}
static void
{
zap_leaf_t *l = vl;
rw_destroy(&l->l_rwlock);
kmem_free(l, sizeof (zap_leaf_t));
}
static zap_leaf_t *
{
zap_leaf_t *l, *winner;
/* someone else set it first */
zap_leaf_pageout(NULL, l);
l = winner;
}
/*
* There should be more hash entries than there can be
* chunks to put in the hash table
*/
/* The chunks should begin at the end of the hash table */
ASSERT3P(&ZAP_LEAF_CHUNK(l, 0), ==,
/* The chunks should end at the end of the block */
return (l);
}
static zap_leaf_t *
{
zap_leaf_t *l;
l = dmu_buf_get_user(db);
if (l == NULL)
/*
* Must lock before dirtying, otherwise l->l_phys could change,
* causing ASSERT below to fail.
*/
return (l);
}
static zap_leaf_t *
{
zap_leaf_t *l, *nl;
nl = l;
}
return (l);
}
static uint64_t
{
} else {
idx));
}
}
static void
{
} else {
}
}
static zap_leaf_t *
{
zap_leaf_t *l;
return (l);
}
static zap_leaf_t *
{
zap_leaf_t *nl;
int prefix_diff, i, err;
ASSERT3U(l->lh_prefix_len, <=,
/* failed to upgrade */
int old_prefix_len = l->lh_prefix_len;
zap_put_leaf(l);
if (l->lh_prefix_len != old_prefix_len)
/* it split while our locks were down */
return (l);
}
/* There's only one pointer to us. Chain on another leaf blk. */
l->lh_prefix_len);
return (l);
}
/* There's more than one pointer to us. Split this leaf. */
/* set sibling pointers */
for (i = 0; i < (1ULL<<prefix_diff); i++) {
/* dprintf("set %d to %u %x\n", sibling+i, nl->l_blkid, nl); */
}
/* we want the sibling */
zap_put_leaf(l);
l = nl;
} else {
}
return (l);
}
static void
{
if (l->lh_prefix_len == shift &&
/* this leaf will soon make us grow the pointer table */
zap_put_leaf(l);
goto again;
}
zap_put_leaf(l);
} else {
zap_put_leaf(l);
}
}
static int
{
/* Only integer sizes supported by C */
switch (integer_size) {
case 1:
case 2:
case 4:
case 8:
break;
default:
return (EINVAL);
}
/* Make sure we won't overflow */
return (EINVAL);
return (EINVAL);
return (0);
}
/*
* Routines for maniplulating attributes.
*/
int
{
zap_leaf_t *l;
int err;
if (err != 0)
return (err);
if (err != 0)
goto out;
out:
zap_put_leaf(l);
return (err);
}
int
{
zap_leaf_t *l;
int err;
if (err == 0) {
goto out;
}
/* XXX If this leaf is chained, split it if we can. */
if (err == 0) {
goto retry;
}
out:
if (lp)
*lp = l;
else
zap_put_leaf(l);
return (err);
}
int
{
int err;
zap_leaf_t *l;
if (err != 0)
return (err);
return (err);
}
int
{
zap_leaf_t *l;
if (err != 0)
return (err);
/* XXX If this leaf is chained, split it if we can. */
if (create) {
if (err == 0)
} else {
}
goto retry;
}
return (err);
}
int
{
zap_leaf_t *l;
int err;
if (err != 0)
goto out;
if (integer_size)
if (num_integers)
out:
zap_put_leaf(l);
return (err);
}
int
{
zap_leaf_t *l;
int err;
if (err == 0) {
}
zap_put_leaf(l);
dprintf("fzap_remove: ds=%p obj=%llu name=%s err=%d\n",
return (err);
}
int
{
int err;
zap_cursor_advance(&zc)) {
break;
}
}
return (err);
}
/*
* Routines for iterating over the attributes.
*/
int
{
zap_leaf_t *l;
/* if no entry, return ENOENT */
}
} else {
}
} else {
goto again;
}
}
if (err == 0) {
if (zeh.zeh_num_integers == 0) {
za->za_first_integer = 0;
} else {
}
}
return (err);
}
static void
{
int i;
/*
* NB: if a leaf has more pointers than an entire ptrtbl block
* can hold, then it'll be accounted for more than once, since
* we won't have lastblk.
*/
for (i = 0; i < len; i++) {
zap_leaf_t *l;
continue;
zap_put_leaf(l);
}
}
void
{
/* the ptrtbl is entirely in the header block. */
} else {
int b;
b++) {
}
}
}