FreeBSD ZFS
The Zettabyte File System

dmu_traverse.c

Go to the documentation of this file.
00001 /*
00002  * CDDL HEADER START
00003  *
00004  * The contents of this file are subject to the terms of the
00005  * Common Development and Distribution License (the "License").
00006  * You may not use this file except in compliance with the License.
00007  *
00008  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
00009  * or http://www.opensolaris.org/os/licensing.
00010  * See the License for the specific language governing permissions
00011  * and limitations under the License.
00012  *
00013  * When distributing Covered Code, include this CDDL HEADER in each
00014  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
00015  * If applicable, add the following below this CDDL HEADER, with the
00016  * fields enclosed by brackets "[]" replaced with your own identifying
00017  * information: Portions Copyright [yyyy] [name of copyright owner]
00018  *
00019  * CDDL HEADER END
00020  */
00021 /*
00022  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
00023  * Copyright (c) 2012 by Delphix. All rights reserved.
00024  */
00025 
00026 #include <sys/zfs_context.h>
00027 #include <sys/dmu_objset.h>
00028 #include <sys/dmu_traverse.h>
00029 #include <sys/dsl_dataset.h>
00030 #include <sys/dsl_dir.h>
00031 #include <sys/dsl_pool.h>
00032 #include <sys/dnode.h>
00033 #include <sys/spa.h>
00034 #include <sys/zio.h>
00035 #include <sys/dmu_impl.h>
00036 #include <sys/sa.h>
00037 #include <sys/sa_impl.h>
00038 #include <sys/callb.h>
00039 
00040 int zfs_pd_blks_max = 100;
00041 
00042 typedef struct prefetch_data {
00043         kmutex_t pd_mtx;
00044         kcondvar_t pd_cv;
00045         int pd_blks_max;
00046         int pd_blks_fetched;
00047         int pd_flags;
00048         boolean_t pd_cancel;
00049         boolean_t pd_exited;
00050 } prefetch_data_t;
00051 
00052 typedef struct traverse_data {
00053         spa_t *td_spa;
00054         uint64_t td_objset;
00055         blkptr_t *td_rootbp;
00056         uint64_t td_min_txg;
00057         zbookmark_t *td_resume;
00058         int td_flags;
00059         prefetch_data_t *td_pfd;
00060         blkptr_cb_t *td_func;
00061         void *td_arg;
00062 } traverse_data_t;
00063 
00064 static int traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
00065     arc_buf_t *buf, uint64_t objset, uint64_t object);
00066 static void prefetch_dnode_metadata(traverse_data_t *td, const dnode_phys_t *,
00067     arc_buf_t *buf, uint64_t objset, uint64_t object);
00068 
00069 static int
00070 traverse_zil_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
00071 {
00072         traverse_data_t *td = arg;
00073         zbookmark_t zb;
00074 
00075         if (bp->blk_birth == 0)
00076                 return (0);
00077 
00078         if (claim_txg == 0 && bp->blk_birth >= spa_first_txg(td->td_spa))
00079                 return (0);
00080 
00081         SET_BOOKMARK(&zb, td->td_objset, ZB_ZIL_OBJECT, ZB_ZIL_LEVEL,
00082             bp->blk_cksum.zc_word[ZIL_ZC_SEQ]);
00083 
00084         (void) td->td_func(td->td_spa, zilog, bp, NULL, &zb, NULL, td->td_arg);
00085 
00086         return (0);
00087 }
00088 
00089 static int
00090 traverse_zil_record(zilog_t *zilog, lr_t *lrc, void *arg, uint64_t claim_txg)
00091 {
00092         traverse_data_t *td = arg;
00093 
00094         if (lrc->lrc_txtype == TX_WRITE) {
00095                 lr_write_t *lr = (lr_write_t *)lrc;
00096                 blkptr_t *bp = &lr->lr_blkptr;
00097                 zbookmark_t zb;
00098 
00099                 if (bp->blk_birth == 0)
00100                         return (0);
00101 
00102                 if (claim_txg == 0 || bp->blk_birth < claim_txg)
00103                         return (0);
00104 
00105                 SET_BOOKMARK(&zb, td->td_objset, lr->lr_foid,
00106                     ZB_ZIL_LEVEL, lr->lr_offset / BP_GET_LSIZE(bp));
00107 
00108                 (void) td->td_func(td->td_spa, zilog, bp, NULL, &zb, NULL,
00109                     td->td_arg);
00110         }
00111         return (0);
00112 }
00113 
00114 static void
00115 traverse_zil(traverse_data_t *td, zil_header_t *zh)
00116 {
00117         uint64_t claim_txg = zh->zh_claim_txg;
00118         zilog_t *zilog;
00119 
00120         /*
00121          * We only want to visit blocks that have been claimed but not yet
00122          * replayed; plus, in read-only mode, blocks that are already stable.
00123          */
00124         if (claim_txg == 0 && spa_writeable(td->td_spa))
00125                 return;
00126 
00127         zilog = zil_alloc(spa_get_dsl(td->td_spa)->dp_meta_objset, zh);
00128 
00129         (void) zil_parse(zilog, traverse_zil_block, traverse_zil_record, td,
00130             claim_txg);
00131 
00132         zil_free(zilog);
00133 }
00134 
00135 typedef enum resume_skip {
00136         RESUME_SKIP_ALL,
00137         RESUME_SKIP_NONE,
00138         RESUME_SKIP_CHILDREN
00139 } resume_skip_t;
00140 
00152 static resume_skip_t
00153 resume_skip_check(traverse_data_t *td, const dnode_phys_t *dnp,
00154     const zbookmark_t *zb)
00155 {
00156         if (td->td_resume != NULL && !ZB_IS_ZERO(td->td_resume)) {
00157                 /*
00158                  * If we already visited this bp & everything below,
00159                  * don't bother doing it again.
00160                  */
00161                 if (zbookmark_is_before(dnp, zb, td->td_resume))
00162                         return (RESUME_SKIP_ALL);
00163 
00164                 /*
00165                  * If we found the block we're trying to resume from, zero
00166                  * the bookmark out to indicate that we have resumed.
00167                  */
00168                 ASSERT3U(zb->zb_object, <=, td->td_resume->zb_object);
00169                 if (bcmp(zb, td->td_resume, sizeof (*zb)) == 0) {
00170                         bzero(td->td_resume, sizeof (*zb));
00171                         if (td->td_flags & TRAVERSE_POST)
00172                                 return (RESUME_SKIP_CHILDREN);
00173                 }
00174         }
00175         return (RESUME_SKIP_NONE);
00176 }
00177 
00178 static void
00179 traverse_pause(traverse_data_t *td, const zbookmark_t *zb)
00180 {
00181         ASSERT(td->td_resume != NULL);
00182         ASSERT0(zb->zb_level);
00183         bcopy(zb, td->td_resume, sizeof (*td->td_resume));
00184 }
00185 
00186 static void
00187 traverse_prefetch_metadata(traverse_data_t *td,
00188     arc_buf_t *pbuf, const blkptr_t *bp, const zbookmark_t *zb)
00189 {
00190         uint32_t flags = ARC_NOWAIT | ARC_PREFETCH;
00191 
00192         if (!(td->td_flags & TRAVERSE_PREFETCH_METADATA))
00193                 return;
00194         /*
00195          * If we are in the process of resuming, don't prefetch, because
00196          * some children will not be needed (and in fact may have already
00197          * been freed).
00198          */
00199         if (td->td_resume != NULL && !ZB_IS_ZERO(td->td_resume))
00200                 return;
00201         if (BP_IS_HOLE(bp) || bp->blk_birth <= td->td_min_txg)
00202                 return;
00203         if (BP_GET_LEVEL(bp) == 0 && BP_GET_TYPE(bp) != DMU_OT_DNODE)
00204                 return;
00205 
00206         (void) arc_read(NULL, td->td_spa, bp,
00207             pbuf, NULL, NULL, ZIO_PRIORITY_ASYNC_READ,
00208             ZIO_FLAG_CANFAIL, &flags, zb);
00209 }
00210 
00211 static int
00212 traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
00213     arc_buf_t *pbuf, const blkptr_t *bp, const zbookmark_t *zb)
00214 {
00215         zbookmark_t czb;
00216         int err = 0, lasterr = 0;
00217         arc_buf_t *buf = NULL;
00218         prefetch_data_t *pd = td->td_pfd;
00219         boolean_t hard = td->td_flags & TRAVERSE_HARD;
00220         boolean_t pause = B_FALSE;
00221 
00222         switch (resume_skip_check(td, dnp, zb)) {
00223         case RESUME_SKIP_ALL:
00224                 return (0);
00225         case RESUME_SKIP_CHILDREN:
00226                 goto post;
00227         case RESUME_SKIP_NONE:
00228                 break;
00229         default:
00230                 ASSERT(0);
00231         }
00232 
00233         if (BP_IS_HOLE(bp)) {
00234                 err = td->td_func(td->td_spa, NULL, NULL, pbuf, zb, dnp,
00235                     td->td_arg);
00236                 return (err);
00237         }
00238 
00239         if (bp->blk_birth <= td->td_min_txg)
00240                 return (0);
00241 
00242         if (pd && !pd->pd_exited &&
00243             ((pd->pd_flags & TRAVERSE_PREFETCH_DATA) ||
00244             BP_GET_TYPE(bp) == DMU_OT_DNODE || BP_GET_LEVEL(bp) > 0)) {
00245                 mutex_enter(&pd->pd_mtx);
00246                 ASSERT(pd->pd_blks_fetched >= 0);
00247                 while (pd->pd_blks_fetched == 0 && !pd->pd_exited)
00248                         cv_wait(&pd->pd_cv, &pd->pd_mtx);
00249                 pd->pd_blks_fetched--;
00250                 cv_broadcast(&pd->pd_cv);
00251                 mutex_exit(&pd->pd_mtx);
00252         }
00253 
00254         if (td->td_flags & TRAVERSE_PRE) {
00255                 err = td->td_func(td->td_spa, NULL, bp, pbuf, zb, dnp,
00256                     td->td_arg);
00257                 if (err == TRAVERSE_VISIT_NO_CHILDREN)
00258                         return (0);
00259                 if (err == ERESTART)
00260                         pause = B_TRUE; /* handle pausing at a common point */
00261                 if (err != 0)
00262                         goto post;
00263         }
00264 
00265         if (BP_GET_LEVEL(bp) > 0) {
00266                 uint32_t flags = ARC_WAIT;
00267                 int i;
00268                 blkptr_t *cbp;
00269                 int epb = BP_GET_LSIZE(bp) >> SPA_BLKPTRSHIFT;
00270 
00271                 err = dsl_read(NULL, td->td_spa, bp, pbuf,
00272                     arc_getbuf_func, &buf,
00273                     ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
00274                 if (err)
00275                         return (err);
00276                 cbp = buf->b_data;
00277 
00278                 for (i = 0; i < epb; i++) {
00279                         SET_BOOKMARK(&czb, zb->zb_objset, zb->zb_object,
00280                             zb->zb_level - 1,
00281                             zb->zb_blkid * epb + i);
00282                         traverse_prefetch_metadata(td, buf, &cbp[i], &czb);
00283                 }
00284 
00285                 /* recursively visitbp() blocks below this */
00286                 for (i = 0; i < epb; i++) {
00287                         SET_BOOKMARK(&czb, zb->zb_objset, zb->zb_object,
00288                             zb->zb_level - 1,
00289                             zb->zb_blkid * epb + i);
00290                         err = traverse_visitbp(td, dnp, buf, &cbp[i], &czb);
00291                         if (err) {
00292                                 if (!hard)
00293                                         break;
00294                                 lasterr = err;
00295                         }
00296                 }
00297         } else if (BP_GET_TYPE(bp) == DMU_OT_DNODE) {
00298                 uint32_t flags = ARC_WAIT;
00299                 int i;
00300                 int epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT;
00301 
00302                 err = dsl_read(NULL, td->td_spa, bp, pbuf,
00303                     arc_getbuf_func, &buf,
00304                     ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
00305                 if (err)
00306                         return (err);
00307                 dnp = buf->b_data;
00308 
00309                 for (i = 0; i < epb; i++) {
00310                         prefetch_dnode_metadata(td, &dnp[i], buf, zb->zb_objset,
00311                             zb->zb_blkid * epb + i);
00312                 }
00313 
00314                 /* recursively visitbp() blocks below this */
00315                 for (i = 0; i < epb; i++) {
00316                         err = traverse_dnode(td, &dnp[i], buf, zb->zb_objset,
00317                             zb->zb_blkid * epb + i);
00318                         if (err) {
00319                                 if (!hard)
00320                                         break;
00321                                 lasterr = err;
00322                         }
00323                 }
00324         } else if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) {
00325                 uint32_t flags = ARC_WAIT;
00326                 objset_phys_t *osp;
00327                 dnode_phys_t *dnp;
00328 
00329                 err = dsl_read_nolock(NULL, td->td_spa, bp,
00330                     arc_getbuf_func, &buf,
00331                     ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
00332                 if (err)
00333                         return (err);
00334 
00335                 osp = buf->b_data;
00336                 dnp = &osp->os_meta_dnode;
00337                 prefetch_dnode_metadata(td, dnp, buf, zb->zb_objset,
00338                     DMU_META_DNODE_OBJECT);
00339                 if (arc_buf_size(buf) >= sizeof (objset_phys_t)) {
00340                         prefetch_dnode_metadata(td, &osp->os_userused_dnode,
00341                             buf, zb->zb_objset, DMU_USERUSED_OBJECT);
00342                         prefetch_dnode_metadata(td, &osp->os_groupused_dnode,
00343                             buf, zb->zb_objset, DMU_USERUSED_OBJECT);
00344                 }
00345 
00346                 err = traverse_dnode(td, dnp, buf, zb->zb_objset,
00347                     DMU_META_DNODE_OBJECT);
00348                 if (err && hard) {
00349                         lasterr = err;
00350                         err = 0;
00351                 }
00352                 if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) {
00353                         dnp = &osp->os_userused_dnode;
00354                         err = traverse_dnode(td, dnp, buf, zb->zb_objset,
00355                             DMU_USERUSED_OBJECT);
00356                 }
00357                 if (err && hard) {
00358                         lasterr = err;
00359                         err = 0;
00360                 }
00361                 if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) {
00362                         dnp = &osp->os_groupused_dnode;
00363                         err = traverse_dnode(td, dnp, buf, zb->zb_objset,
00364                             DMU_GROUPUSED_OBJECT);
00365                 }
00366         }
00367 
00368         if (buf)
00369                 (void) arc_buf_remove_ref(buf, &buf);
00370 
00371 post:
00372         if (err == 0 && lasterr == 0 && (td->td_flags & TRAVERSE_POST)) {
00373                 err = td->td_func(td->td_spa, NULL, bp, pbuf, zb, dnp,
00374                     td->td_arg);
00375                 if (err == ERESTART)
00376                         pause = B_TRUE;
00377         }
00378 
00379         if (pause && td->td_resume != NULL) {
00380                 ASSERT3U(err, ==, ERESTART);
00381                 ASSERT(!hard);
00382                 traverse_pause(td, zb);
00383         }
00384 
00385         return (err != 0 ? err : lasterr);
00386 }
00387 
00388 static void
00389 prefetch_dnode_metadata(traverse_data_t *td, const dnode_phys_t *dnp,
00390     arc_buf_t *buf, uint64_t objset, uint64_t object)
00391 {
00392         int j;
00393         zbookmark_t czb;
00394 
00395         for (j = 0; j < dnp->dn_nblkptr; j++) {
00396                 SET_BOOKMARK(&czb, objset, object, dnp->dn_nlevels - 1, j);
00397                 traverse_prefetch_metadata(td, buf, &dnp->dn_blkptr[j], &czb);
00398         }
00399 
00400         if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) {
00401                 SET_BOOKMARK(&czb, objset, object, 0, DMU_SPILL_BLKID);
00402                 traverse_prefetch_metadata(td, buf, &dnp->dn_spill, &czb);
00403         }
00404 }
00405 
00406 static int
00407 traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
00408     arc_buf_t *buf, uint64_t objset, uint64_t object)
00409 {
00410         int j, err = 0, lasterr = 0;
00411         zbookmark_t czb;
00412         boolean_t hard = (td->td_flags & TRAVERSE_HARD);
00413 
00414         for (j = 0; j < dnp->dn_nblkptr; j++) {
00415                 SET_BOOKMARK(&czb, objset, object, dnp->dn_nlevels - 1, j);
00416                 err = traverse_visitbp(td, dnp, buf, &dnp->dn_blkptr[j], &czb);
00417                 if (err) {
00418                         if (!hard)
00419                                 break;
00420                         lasterr = err;
00421                 }
00422         }
00423 
00424         if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) {
00425                 SET_BOOKMARK(&czb, objset, object, 0, DMU_SPILL_BLKID);
00426                 err = traverse_visitbp(td, dnp, buf, &dnp->dn_spill, &czb);
00427                 if (err) {
00428                         if (!hard)
00429                                 return (err);
00430                         lasterr = err;
00431                 }
00432         }
00433         return (err != 0 ? err : lasterr);
00434 }
00435 
00436 /* ARGSUSED */
00437 static int
00438 traverse_prefetcher(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
00439     arc_buf_t *pbuf, const zbookmark_t *zb, const dnode_phys_t *dnp,
00440     void *arg)
00441 {
00442         prefetch_data_t *pfd = arg;
00443         uint32_t aflags = ARC_NOWAIT | ARC_PREFETCH;
00444 
00445         ASSERT(pfd->pd_blks_fetched >= 0);
00446         if (pfd->pd_cancel)
00447                 return (EINTR);
00448 
00449         if (bp == NULL || !((pfd->pd_flags & TRAVERSE_PREFETCH_DATA) ||
00450             BP_GET_TYPE(bp) == DMU_OT_DNODE || BP_GET_LEVEL(bp) > 0) ||
00451             BP_GET_TYPE(bp) == DMU_OT_INTENT_LOG)
00452                 return (0);
00453 
00454         mutex_enter(&pfd->pd_mtx);
00455         while (!pfd->pd_cancel && pfd->pd_blks_fetched >= pfd->pd_blks_max)
00456                 cv_wait(&pfd->pd_cv, &pfd->pd_mtx);
00457         pfd->pd_blks_fetched++;
00458         cv_broadcast(&pfd->pd_cv);
00459         mutex_exit(&pfd->pd_mtx);
00460 
00461         (void) dsl_read(NULL, spa, bp, pbuf, NULL, NULL,
00462             ZIO_PRIORITY_ASYNC_READ,
00463             ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE,
00464             &aflags, zb);
00465 
00466         return (0);
00467 }
00468 
00469 static void
00470 traverse_prefetch_thread(void *arg)
00471 {
00472         traverse_data_t *td_main = arg;
00473         traverse_data_t td = *td_main;
00474         zbookmark_t czb;
00475 
00476         td.td_func = traverse_prefetcher;
00477         td.td_arg = td_main->td_pfd;
00478         td.td_pfd = NULL;
00479 
00480         SET_BOOKMARK(&czb, td.td_objset,
00481             ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
00482         (void) traverse_visitbp(&td, NULL, NULL, td.td_rootbp, &czb);
00483 
00484         mutex_enter(&td_main->td_pfd->pd_mtx);
00485         td_main->td_pfd->pd_exited = B_TRUE;
00486         cv_broadcast(&td_main->td_pfd->pd_cv);
00487         mutex_exit(&td_main->td_pfd->pd_mtx);
00488 }
00489 
00494 static int
00495 traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
00496     uint64_t txg_start, zbookmark_t *resume, int flags,
00497     blkptr_cb_t func, void *arg)
00498 {
00499         traverse_data_t td;
00500         prefetch_data_t pd = { 0 };
00501         zbookmark_t czb;
00502         int err;
00503 
00504         ASSERT(ds == NULL || objset == ds->ds_object);
00505         ASSERT(!(flags & TRAVERSE_PRE) || !(flags & TRAVERSE_POST));
00506 
00507         /*
00508          * The data prefetching mechanism (the prefetch thread) is incompatible
00509          * with resuming from a bookmark.
00510          */
00511         ASSERT(resume == NULL || !(flags & TRAVERSE_PREFETCH_DATA));
00512 
00513         td.td_spa = spa;
00514         td.td_objset = objset;
00515         td.td_rootbp = rootbp;
00516         td.td_min_txg = txg_start;
00517         td.td_resume = resume;
00518         td.td_func = func;
00519         td.td_arg = arg;
00520         td.td_pfd = &pd;
00521         td.td_flags = flags;
00522 
00523         pd.pd_blks_max = zfs_pd_blks_max;
00524         pd.pd_flags = flags;
00525         mutex_init(&pd.pd_mtx, NULL, MUTEX_DEFAULT, NULL);
00526         cv_init(&pd.pd_cv, NULL, CV_DEFAULT, NULL);
00527 
00528         /* See comment on ZIL traversal in dsl_scan_visitds. */
00529         if (ds != NULL && !dsl_dataset_is_snapshot(ds)) {
00530                 objset_t *os;
00531 
00532                 err = dmu_objset_from_ds(ds, &os);
00533                 if (err)
00534                         return (err);
00535 
00536                 traverse_zil(&td, &os->os_zil_header);
00537         }
00538 
00539         if (!(flags & TRAVERSE_PREFETCH_DATA) ||
00540             0 == taskq_dispatch(system_taskq, traverse_prefetch_thread,
00541             &td, TQ_NOQUEUE))
00542                 pd.pd_exited = B_TRUE;
00543 
00544         SET_BOOKMARK(&czb, td.td_objset,
00545             ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
00546         err = traverse_visitbp(&td, NULL, NULL, rootbp, &czb);
00547 
00548         mutex_enter(&pd.pd_mtx);
00549         pd.pd_cancel = B_TRUE;
00550         cv_broadcast(&pd.pd_cv);
00551         while (!pd.pd_exited)
00552                 cv_wait(&pd.pd_cv, &pd.pd_mtx);
00553         mutex_exit(&pd.pd_mtx);
00554 
00555         mutex_destroy(&pd.pd_mtx);
00556         cv_destroy(&pd.pd_cv);
00557 
00558         return (err);
00559 }
00560 
00565 int
00566 traverse_dataset(dsl_dataset_t *ds, uint64_t txg_start, int flags,
00567     blkptr_cb_t func, void *arg)
00568 {
00569         return (traverse_impl(ds->ds_dir->dd_pool->dp_spa, ds, ds->ds_object,
00570             &ds->ds_phys->ds_bp, txg_start, NULL, flags, func, arg));
00571 }
00572 
00573 int
00574 traverse_dataset_destroyed(spa_t *spa, blkptr_t *blkptr,
00575     uint64_t txg_start, zbookmark_t *resume, int flags,
00576     blkptr_cb_t func, void *arg)
00577 {
00578         return (traverse_impl(spa, NULL, ZB_DESTROYED_OBJSET,
00579             blkptr, txg_start, resume, flags, func, arg));
00580 }
00581 
00585 int
00586 traverse_pool(spa_t *spa, uint64_t txg_start, int flags,
00587     blkptr_cb_t func, void *arg)
00588 {
00589         int err, lasterr = 0;
00590         uint64_t obj;
00591         dsl_pool_t *dp = spa_get_dsl(spa);
00592         objset_t *mos = dp->dp_meta_objset;
00593         boolean_t hard = (flags & TRAVERSE_HARD);
00594 
00595         /* visit the MOS */
00596         err = traverse_impl(spa, NULL, 0, spa_get_rootblkptr(spa),
00597             txg_start, NULL, flags, func, arg);
00598         if (err)
00599                 return (err);
00600 
00601         /* visit each dataset */
00602         for (obj = 1; err == 0 || (err != ESRCH && hard);
00603             err = dmu_object_next(mos, &obj, FALSE, txg_start)) {
00604                 dmu_object_info_t doi;
00605 
00606                 err = dmu_object_info(mos, obj, &doi);
00607                 if (err) {
00608                         if (!hard)
00609                                 return (err);
00610                         lasterr = err;
00611                         continue;
00612                 }
00613 
00614                 if (doi.doi_type == DMU_OT_DSL_DATASET) {
00615                         dsl_dataset_t *ds;
00616                         uint64_t txg = txg_start;
00617 
00618                         rw_enter(&dp->dp_config_rwlock, RW_READER);
00619                         err = dsl_dataset_hold_obj(dp, obj, FTAG, &ds);
00620                         rw_exit(&dp->dp_config_rwlock);
00621                         if (err) {
00622                                 if (!hard)
00623                                         return (err);
00624                                 lasterr = err;
00625                                 continue;
00626                         }
00627                         if (ds->ds_phys->ds_prev_snap_txg > txg)
00628                                 txg = ds->ds_phys->ds_prev_snap_txg;
00629                         err = traverse_dataset(ds, txg, flags, func, arg);
00630                         dsl_dataset_rele(ds, FTAG);
00631                         if (err) {
00632                                 if (!hard)
00633                                         return (err);
00634                                 lasterr = err;
00635                         }
00636                 }
00637         }
00638         if (err == ESRCH)
00639                 err = 0;
00640         return (err != 0 ? err : lasterr);
00641 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines