dmu_traverse.c revision 2a89c2c59b7c2beb2373c14368cbe7e32af6ffc1
/*
* 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, 2014 by Delphix. All rights reserved.
*/
#include <sys/zfs_context.h>
#include <sys/dmu_objset.h>
#include <sys/dmu_traverse.h>
#include <sys/dsl_dataset.h>
#include <sys/dsl_pool.h>
#include <sys/dmu_impl.h>
#include <sys/zfeature.h>
int zfs_pd_blks_max = 100;
typedef struct prefetch_data {
int pd_blks_max;
int pd_blks_fetched;
int pd_flags;
typedef struct traverse_data {
int td_flags;
void *td_arg;
static int
{
if (BP_IS_HOLE(bp))
return (0);
return (0);
return (0);
}
static int
{
if (BP_IS_HOLE(bp))
return (0);
return (0);
}
return (0);
}
static void
{
/*
* We only want to visit blocks that have been claimed but not yet
* replayed; plus, in read-only mode, blocks that are already stable.
*/
return;
}
typedef enum resume_skip {
/*
* Returns RESUME_SKIP_ALL if td indicates that we are resuming a traversal and
* the block indicated by zb does not need to be visited at all. Returns
* RESUME_SKIP_CHILDREN if we are resuming a post traversal and we reach the
* resume point. This indicates that this block should be visited but not its
* children (since they must have been visited in a previous traversal).
* Otherwise returns RESUME_SKIP_NONE.
*/
static resume_skip_t
const zbookmark_phys_t *zb)
{
/*
* If we already visited this bp & everything below,
* don't bother doing it again.
*/
return (RESUME_SKIP_ALL);
/*
* If we found the block we're trying to resume from, zero
* the bookmark out to indicate that we have resumed.
*/
return (RESUME_SKIP_CHILDREN);
}
}
return (RESUME_SKIP_NONE);
}
static void
{
return;
/*
* If we are in the process of resuming, don't prefetch, because
* some children will not be needed (and in fact may have already
* been freed).
*/
return;
return;
return;
}
static boolean_t
{
return (B_FALSE);
return (B_TRUE);
}
static int
{
int err = 0;
case RESUME_SKIP_ALL:
return (0);
case RESUME_SKIP_CHILDREN:
goto post;
case RESUME_SKIP_NONE:
break;
default:
ASSERT(0);
}
/*
* Since this block has a birth time of 0 it must be a
* hole created before the SPA_FEATURE_HOLE_BIRTH
* feature was enabled. If SPA_FEATURE_HOLE_BIRTH
* was enabled before the min_txg for this traveral we
* know the hole must have been created before the
* min_txg for this traveral, so we can skip it. If
* SPA_FEATURE_HOLE_BIRTH was enabled after the min_txg
* for this traveral we cannot tell if the hole was
* created before or after the min_txg for this
* traversal, so we cannot skip it.
*/
return (0);
return (0);
}
pd->pd_blks_fetched--;
}
if (BP_IS_HOLE(bp)) {
if (err != 0)
goto post;
return (0);
}
if (err == TRAVERSE_VISIT_NO_CHILDREN)
return (0);
if (err != 0)
goto post;
}
if (BP_GET_LEVEL(bp) > 0) {
int i;
if (err != 0)
goto post;
for (i = 0; i < epb; i++) {
}
/* recursively visitbp() blocks below this */
for (i = 0; i < epb; i++) {
if (err != 0)
break;
}
int i;
if (err != 0)
goto post;
for (i = 0; i < epb; i++) {
}
/* recursively visitbp() blocks below this */
for (i = 0; i < epb; i++) {
if (err != 0)
break;
}
if (err != 0)
goto post;
}
}
}
}
if (buf)
post:
/*
* Ignore this disk error as requested by the HARD flag,
* and continue traversal.
*/
err = 0;
}
/*
* If we are stopping here, set td_resume.
*/
/*
* If we have stopped on an indirect block (e.g. due to
* i/o error), we have not visited anything below it.
* Set the bookmark to the first level-0 block that we need
* to visit. This way, the resuming code does not need to
* deal with resuming from indirect blocks.
*/
}
return (err);
}
static void
{
int j;
for (j = 0; j < dnp->dn_nblkptr; j++) {
}
}
}
static int
{
int j, err = 0;
for (j = 0; j < dnp->dn_nblkptr; j++) {
if (err != 0)
break;
}
}
return (err);
}
/* ARGSUSED */
static int
{
return (0);
pfd->pd_blks_fetched++;
return (0);
}
static void
traverse_prefetch_thread(void *arg)
{
}
/*
* NB: dataset must not be changing on-disk (eg, is a snapshot or we are
* in syncing context).
*/
static int
{
prefetch_data_t pd = { 0 };
int err;
/*
* The data prefetching mechanism (the prefetch thread) is incompatible
* with resuming from a bookmark.
*/
} else {
}
/* See comment on ZIL traversal in dsl_scan_visitds. */
if (err != 0)
return (err);
}
if (!(flags & TRAVERSE_PREFETCH_DATA) ||
&td, TQ_NOQUEUE))
return (err);
}
/*
* NB: dataset must not be changing on-disk (eg, is a snapshot or we are
* in syncing context).
*/
int
{
}
int
{
}
/*
* NB: pool must not be changing on-disk (eg, from zdb or sync context).
*/
int
{
int err;
/* visit the MOS */
if (err != 0)
return (err);
/* visit each dataset */
if (err != 0) {
if (hard)
continue;
break;
}
if (err != 0) {
if (hard)
continue;
break;
}
if (err != 0)
break;
}
}
err = 0;
return (err);
}