zap.c revision 40510e8eba18690b9a9843b26393725eeb0f1dac
/*
* 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 (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
*/
/*
* 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/zfs_znode.h>
#include <sys/refcount.h>
#include <sys/zap_impl.h>
#include <sys/zap_leaf.h>
void
{
else {
/* it's a ptrtbl block */
}
}
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
*/
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 int
{
int err;
/* hepb = half the number of entries in a block */
if (tbl->zt_nextblk != 0) {
} else {
}
/*
* Copy the ptrtbl from the old to new location.
*/
b = tbl->zt_blks_copied;
if (err)
return (err);
/* 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",
}
return (0);
}
static int
{
int err;
if (err)
return (err);
if (tbl->zt_nextblk != 0) {
if (err) {
return (err);
}
}
return (0);
}
static int
{
int err;
/*
* Note: this is equivalent to dmu_buf_hold(), but we use
* _dnode_enter / _by_dnode because it's faster because we don't
* have to hold the dnode.
*/
if (err)
return (err);
if (tbl->zt_nextblk != 0) {
/*
* read the nextblk for the sake of i/o error checking,
* so that zap_table_load() will catch errors for
* zap_table_store.
*/
if (err == 0)
}
return (err);
}
/*
* Routines for growing the ptrtbl.
*/
static void
{
int i;
for (i = 0; i < n; i++) {
}
}
static int
{
/*
* The pointer table should never use more hash bits than we
* have (otherwise we'd be using useless zero bits to index it).
* If we are within 2 bits of running out, stop growing, since
* this is already an aberrant condition.
*/
/*
* 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.
*/
int err;
if (err)
return (err);
return (0);
} else {
}
}
static void
{
}
static uint64_t
{
return (newblk);
}
static void
zap_leaf_evict_sync(void *dbu)
{
zap_leaf_t *l = dbu;
rw_destroy(&l->l_rwlock);
kmem_free(l, sizeof (zap_leaf_t));
}
static zap_leaf_t *
{
void *winner;
return (l);
}
int
{
return (0);
}
/*
* Routines for obtaining zap_leaf_t's
*/
void
{
}
static zap_leaf_t *
{
zap_leaf_t *l, *winner;
/* someone else set it first */
zap_leaf_evict_sync(&l->l_dbu);
l = winner;
}
/*
* lhr_pad was previously used for the next leaf in the leaf
* chain. There should be no chained leafs (as we have removed
* support for them).
*/
/*
* 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 int
zap_leaf_t **lp)
{
zap_leaf_t *l;
int err;
if (err)
return (err);
l = dmu_buf_get_user(db);
if (l == NULL)
/*
* Must lock before dirtying, otherwise zap_leaf_phys(l) could change,
* causing ASSERT below to fail.
*/
*lp = l;
return (0);
}
static int
{
return (0);
} else {
}
}
static int
{
return (0);
} else {
}
}
static int
{
int err;
/* Reality check for corrupt zap objects (leaf or header). */
}
if (err != 0)
return (err);
return (err);
}
static int
{
zap_leaf_t *nl;
int prefix_diff, i, err;
/* We failed to upgrade, or need to grow the pointer table */
zap_put_leaf(l);
if (err)
return (err);
while (old_prefix_len ==
if (err)
return (err);
}
if (err)
return (err);
/* it split while our locks were down */
*lp = l;
return (0);
}
}
(old_prefix_len + 1);
/* check for i/o errors before doing zap_leaf_split */
for (i = 0; i < (1ULL<<prefix_diff); i++) {
if (err)
return (err);
}
/* set sibling pointers */
for (i = 0; i < (1ULL << prefix_diff); i++) {
}
/* we want the sibling */
zap_put_leaf(l);
} else {
*lp = l;
}
return (0);
}
static void
{
zap_put_leaf(l);
int err;
/*
* We are in the middle of growing the pointer table, or
* this leaf will soon make us grow it.
*/
if (err)
return;
}
/* could have finished growing while our locks were down */
}
}
static int
{
return (SET_ERROR(ENAMETOOLONG));
return (0);
}
static int
{
/* Only integer sizes supported by C */
switch (integer_size) {
case 1:
case 2:
case 4:
case 8:
break;
default:
}
return (E2BIG);
return (0);
}
static int
{
int err;
return (err);
}
/*
* Routines for manipulating attributes.
*/
int
{
zap_leaf_t *l;
int err;
return (err);
if (err != 0)
return (err);
if (err == 0) {
zap_put_leaf(l);
return (err);
}
if (ncp) {
}
}
zap_put_leaf(l);
return (err);
}
int
{
zap_leaf_t *l;
int err;
if (err != 0)
return (err);
if (err == 0) {
goto out;
}
goto out;
if (err == 0) {
if (err == 0)
goto retry;
}
out:
return (err);
}
int
{
if (err != 0)
return (err);
}
int
{
zap_leaf_t *l;
if (err != 0)
return (err);
if (err != 0)
return (err);
if (create) {
if (err == 0)
} else {
}
if (err == 0)
goto retry;
}
return (err);
}
int
{
zap_leaf_t *l;
int err;
if (err != 0)
return (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)
return (err);
if (err == 0) {
}
zap_put_leaf(l);
return (err);
}
void
{
int bs;
return;
}
/*
* Helper functions for consumers.
*/
{
tx));
return (new_obj);
}
int
char *name)
{
int err;
if (mask == 0)
mask = -1ULL;
zap_cursor_advance(&zc)) {
break;
}
}
return (err);
}
int
{
int err;
err = 0;
(void) zap_cursor_advance(&zc)) {
break;
}
if (err)
break;
}
return (err);
}
int
{
int err;
err = 0;
(void) zap_cursor_advance(&zc)) {
break;
}
if (err)
break;
}
return (err);
}
int
{
int err;
err = 0;
(void) zap_cursor_advance(&zc)) {
break;
}
break;
if (err)
break;
}
return (err);
}
int
{
char name[20];
}
int
{
char name[20];
}
int
{
char name[20];
}
int
{
char name[20];
}
int
{
char name[20];
}
int
{
char name[20];
}
int
{
int err;
if (delta == 0)
return (0);
return (err);
if (value == 0)
else
return (err);
}
int
{
char name[20];
}
/*
* Routines for iterating over the attributes.
*/
int
{
zap_leaf_t *l;
/* if no entry, return ENOENT */
}
if (err != 0)
return (err);
} 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, err;
/*
* 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;
if (err == 0) {
zap_put_leaf(l);
}
}
}
void
{
/*
* Set zap_phys_t fields
*/
/*
* Set zap_ptrtbl fields
*/
/* the ptrtbl is entirely in the header block. */
} else {
int b;
b++) {
int err;
if (err == 0) {
}
}
}
}
int
{
zap_leaf_t *l;
int err;
/*
* Account for the header block of the fatzap.
*/
(void) refcount_add_many(tooverwrite,
} else {
(void) refcount_add_many(towrite,
}
/*
* Account for the pointer table blocks.
* If we are adding we need to account for the following cases :
* - If the pointer table is embedded, this operation could force an
* external pointer table.
* - If this already has an external pointer table this operation
* could extend the table.
*/
if (add) {
(void) refcount_add_many(towrite,
} else {
(void) refcount_add_many(towrite,
}
}
/*
* Now, check if the block containing leaf is freeable
* and account accordingly.
*/
if (err != 0) {
return (err);
}
} else {
/*
* If this an add operation, the leaf block could split.
* Hence, we need to account for an additional leaf block.
*/
(void) refcount_add_many(towrite,
}
zap_put_leaf(l);
return (0);
}