1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 22e7cbe64fSgw * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/zfs_context.h> 27fa9e4066Sahrens #include <sys/dmu_objset.h> 28fa9e4066Sahrens #include <sys/dmu_traverse.h> 29fa9e4066Sahrens #include <sys/dsl_dataset.h> 30fa9e4066Sahrens #include <sys/dsl_dir.h> 31fa9e4066Sahrens #include <sys/dsl_pool.h> 32fa9e4066Sahrens #include <sys/dnode.h> 33fa9e4066Sahrens #include <sys/spa.h> 34fa9e4066Sahrens #include <sys/zio.h> 35fa9e4066Sahrens #include <sys/dmu_impl.h> 36*88b7b0f2SMatthew Ahrens #include <sys/callb.h> 37*88b7b0f2SMatthew Ahrens 38*88b7b0f2SMatthew Ahrens #define SET_BOOKMARK(zb, objset, object, level, blkid) \ 39*88b7b0f2SMatthew Ahrens { \ 40*88b7b0f2SMatthew Ahrens (zb)->zb_objset = objset; \ 41*88b7b0f2SMatthew Ahrens (zb)->zb_object = object; \ 42*88b7b0f2SMatthew Ahrens (zb)->zb_level = level; \ 43*88b7b0f2SMatthew Ahrens (zb)->zb_blkid = blkid; \ 44fa9e4066Sahrens } 45fa9e4066Sahrens 46*88b7b0f2SMatthew Ahrens struct prefetch_data { 47*88b7b0f2SMatthew Ahrens kmutex_t pd_mtx; 48*88b7b0f2SMatthew Ahrens kcondvar_t pd_cv; 49*88b7b0f2SMatthew Ahrens int pd_blks_max; 50*88b7b0f2SMatthew Ahrens int pd_blks_fetched; 51*88b7b0f2SMatthew Ahrens int pd_flags; 52*88b7b0f2SMatthew Ahrens boolean_t pd_cancel; 53*88b7b0f2SMatthew Ahrens boolean_t pd_exited; 54*88b7b0f2SMatthew Ahrens }; 55*88b7b0f2SMatthew Ahrens 56*88b7b0f2SMatthew Ahrens struct traverse_data { 57*88b7b0f2SMatthew Ahrens spa_t *td_spa; 58*88b7b0f2SMatthew Ahrens uint64_t td_objset; 59*88b7b0f2SMatthew Ahrens blkptr_t *td_rootbp; 60*88b7b0f2SMatthew Ahrens uint64_t td_min_txg; 61*88b7b0f2SMatthew Ahrens int td_flags; 62*88b7b0f2SMatthew Ahrens struct prefetch_data *td_pfd; 63*88b7b0f2SMatthew Ahrens blkptr_cb_t *td_func; 64*88b7b0f2SMatthew Ahrens void *td_arg; 65*88b7b0f2SMatthew Ahrens }; 66fa9e4066Sahrens 67ea8dc4b6Seschrock /* ARGSUSED */ 68ea8dc4b6Seschrock static void 695dabedeeSbonwick traverse_zil_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg) 70ea8dc4b6Seschrock { 71*88b7b0f2SMatthew Ahrens struct traverse_data *td = arg; 72*88b7b0f2SMatthew Ahrens zbookmark_t zb; 73ea8dc4b6Seschrock 74*88b7b0f2SMatthew Ahrens if (bp->blk_birth == 0) 755dabedeeSbonwick return; 765dabedeeSbonwick 77*88b7b0f2SMatthew Ahrens if (claim_txg == 0 && bp->blk_birth >= spa_first_txg(td->td_spa)) 78*88b7b0f2SMatthew Ahrens return; 79*88b7b0f2SMatthew Ahrens 80*88b7b0f2SMatthew Ahrens zb.zb_objset = td->td_objset; 81*88b7b0f2SMatthew Ahrens zb.zb_object = 0; 82*88b7b0f2SMatthew Ahrens zb.zb_level = -1; 83*88b7b0f2SMatthew Ahrens zb.zb_blkid = bp->blk_cksum.zc_word[ZIL_ZC_SEQ]; 84*88b7b0f2SMatthew Ahrens VERIFY(0 == td->td_func(td->td_spa, bp, &zb, NULL, td->td_arg)); 85ea8dc4b6Seschrock } 86ea8dc4b6Seschrock 87ea8dc4b6Seschrock /* ARGSUSED */ 88ea8dc4b6Seschrock static void 895dabedeeSbonwick traverse_zil_record(zilog_t *zilog, lr_t *lrc, void *arg, uint64_t claim_txg) 90ea8dc4b6Seschrock { 91*88b7b0f2SMatthew Ahrens struct traverse_data *td = arg; 92ea8dc4b6Seschrock 93ea8dc4b6Seschrock if (lrc->lrc_txtype == TX_WRITE) { 94ea8dc4b6Seschrock lr_write_t *lr = (lr_write_t *)lrc; 95ea8dc4b6Seschrock blkptr_t *bp = &lr->lr_blkptr; 96*88b7b0f2SMatthew Ahrens zbookmark_t zb; 97ea8dc4b6Seschrock 98*88b7b0f2SMatthew Ahrens if (bp->blk_birth == 0) 995dabedeeSbonwick return; 1005dabedeeSbonwick 101*88b7b0f2SMatthew Ahrens if (claim_txg == 0 || bp->blk_birth < claim_txg) 102*88b7b0f2SMatthew Ahrens return; 103*88b7b0f2SMatthew Ahrens 104*88b7b0f2SMatthew Ahrens zb.zb_objset = td->td_objset; 105*88b7b0f2SMatthew Ahrens zb.zb_object = lr->lr_foid; 106*88b7b0f2SMatthew Ahrens zb.zb_level = BP_GET_LEVEL(bp); 107*88b7b0f2SMatthew Ahrens zb.zb_blkid = lr->lr_offset / BP_GET_LSIZE(bp); 108*88b7b0f2SMatthew Ahrens VERIFY(0 == td->td_func(td->td_spa, bp, &zb, NULL, td->td_arg)); 109ea8dc4b6Seschrock } 110ea8dc4b6Seschrock } 111ea8dc4b6Seschrock 112ea8dc4b6Seschrock static void 113*88b7b0f2SMatthew Ahrens traverse_zil(struct traverse_data *td, zil_header_t *zh) 114ea8dc4b6Seschrock { 1155dabedeeSbonwick uint64_t claim_txg = zh->zh_claim_txg; 116ea8dc4b6Seschrock zilog_t *zilog; 117ea8dc4b6Seschrock 1185dabedeeSbonwick /* 1195dabedeeSbonwick * We only want to visit blocks that have been claimed but not yet 1205dabedeeSbonwick * replayed (or, in read-only mode, blocks that *would* be claimed). 1215dabedeeSbonwick */ 1225dabedeeSbonwick if (claim_txg == 0 && (spa_mode & FWRITE)) 1235dabedeeSbonwick return; 1245dabedeeSbonwick 125*88b7b0f2SMatthew Ahrens zilog = zil_alloc(spa_get_dsl(td->td_spa)->dp_meta_objset, zh); 126ea8dc4b6Seschrock 127*88b7b0f2SMatthew Ahrens (void) zil_parse(zilog, traverse_zil_block, traverse_zil_record, td, 1285dabedeeSbonwick claim_txg); 129ea8dc4b6Seschrock 130ea8dc4b6Seschrock zil_free(zilog); 131ea8dc4b6Seschrock } 132ea8dc4b6Seschrock 133fa9e4066Sahrens static int 134*88b7b0f2SMatthew Ahrens traverse_visitbp(struct traverse_data *td, const dnode_phys_t *dnp, 135*88b7b0f2SMatthew Ahrens arc_buf_t *pbuf, blkptr_t *bp, const zbookmark_t *zb) 136fa9e4066Sahrens { 137*88b7b0f2SMatthew Ahrens int err = 0; 138*88b7b0f2SMatthew Ahrens arc_buf_t *buf = NULL; 139*88b7b0f2SMatthew Ahrens struct prefetch_data *pd = td->td_pfd; 140fa9e4066Sahrens 141*88b7b0f2SMatthew Ahrens if (bp->blk_birth == 0) { 142*88b7b0f2SMatthew Ahrens err = td->td_func(td->td_spa, NULL, zb, dnp, td->td_arg); 143*88b7b0f2SMatthew Ahrens return (err); 144fa9e4066Sahrens } 145fa9e4066Sahrens 146*88b7b0f2SMatthew Ahrens if (bp->blk_birth <= td->td_min_txg) 147*88b7b0f2SMatthew Ahrens return (0); 148fa9e4066Sahrens 149*88b7b0f2SMatthew Ahrens if (pd && !pd->pd_exited && 150*88b7b0f2SMatthew Ahrens ((pd->pd_flags & TRAVERSE_PREFETCH_DATA) || 151*88b7b0f2SMatthew Ahrens BP_GET_TYPE(bp) == DMU_OT_DNODE || BP_GET_LEVEL(bp) > 0)) { 152*88b7b0f2SMatthew Ahrens mutex_enter(&pd->pd_mtx); 153*88b7b0f2SMatthew Ahrens ASSERT(pd->pd_blks_fetched >= 0); 154*88b7b0f2SMatthew Ahrens while (pd->pd_blks_fetched == 0 && !pd->pd_exited) 155*88b7b0f2SMatthew Ahrens cv_wait(&pd->pd_cv, &pd->pd_mtx); 156*88b7b0f2SMatthew Ahrens pd->pd_blks_fetched--; 157*88b7b0f2SMatthew Ahrens cv_broadcast(&pd->pd_cv); 158*88b7b0f2SMatthew Ahrens mutex_exit(&pd->pd_mtx); 159fa9e4066Sahrens } 160fa9e4066Sahrens 161*88b7b0f2SMatthew Ahrens if (td->td_flags & TRAVERSE_PRE) { 162*88b7b0f2SMatthew Ahrens err = td->td_func(td->td_spa, bp, zb, dnp, td->td_arg); 163*88b7b0f2SMatthew Ahrens if (err) 164*88b7b0f2SMatthew Ahrens return (err); 165fa9e4066Sahrens } 166fa9e4066Sahrens 167*88b7b0f2SMatthew Ahrens if (BP_GET_LEVEL(bp) > 0) { 168*88b7b0f2SMatthew Ahrens uint32_t flags = ARC_WAIT; 169*88b7b0f2SMatthew Ahrens int i; 170*88b7b0f2SMatthew Ahrens blkptr_t *cbp; 171*88b7b0f2SMatthew Ahrens int epb = BP_GET_LSIZE(bp) >> SPA_BLKPTRSHIFT; 172*88b7b0f2SMatthew Ahrens 173*88b7b0f2SMatthew Ahrens err = arc_read(NULL, td->td_spa, bp, pbuf, 174*88b7b0f2SMatthew Ahrens arc_getbuf_func, &buf, 175*88b7b0f2SMatthew Ahrens ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb); 176*88b7b0f2SMatthew Ahrens if (err) 177*88b7b0f2SMatthew Ahrens return (err); 178*88b7b0f2SMatthew Ahrens 179*88b7b0f2SMatthew Ahrens /* recursively visitbp() blocks below this */ 180*88b7b0f2SMatthew Ahrens cbp = buf->b_data; 181*88b7b0f2SMatthew Ahrens for (i = 0; i < epb; i++, cbp++) { 182*88b7b0f2SMatthew Ahrens zbookmark_t czb; 183*88b7b0f2SMatthew Ahrens 184*88b7b0f2SMatthew Ahrens SET_BOOKMARK(&czb, zb->zb_objset, zb->zb_object, 185*88b7b0f2SMatthew Ahrens zb->zb_level - 1, 186*88b7b0f2SMatthew Ahrens zb->zb_blkid * epb + i); 187*88b7b0f2SMatthew Ahrens err = traverse_visitbp(td, dnp, buf, cbp, &czb); 188*88b7b0f2SMatthew Ahrens if (err) 189*88b7b0f2SMatthew Ahrens break; 190*88b7b0f2SMatthew Ahrens } 191*88b7b0f2SMatthew Ahrens } else if (BP_GET_TYPE(bp) == DMU_OT_DNODE) { 192*88b7b0f2SMatthew Ahrens uint32_t flags = ARC_WAIT; 193*88b7b0f2SMatthew Ahrens int i, j; 194*88b7b0f2SMatthew Ahrens int epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT; 195*88b7b0f2SMatthew Ahrens 196*88b7b0f2SMatthew Ahrens err = arc_read(NULL, td->td_spa, bp, pbuf, 197*88b7b0f2SMatthew Ahrens arc_getbuf_func, &buf, 198*88b7b0f2SMatthew Ahrens ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb); 199*88b7b0f2SMatthew Ahrens if (err) 200*88b7b0f2SMatthew Ahrens return (err); 201*88b7b0f2SMatthew Ahrens 202*88b7b0f2SMatthew Ahrens /* recursively visitbp() blocks below this */ 203*88b7b0f2SMatthew Ahrens dnp = buf->b_data; 204*88b7b0f2SMatthew Ahrens for (i = 0; i < epb && err == 0; i++, dnp++) { 205*88b7b0f2SMatthew Ahrens for (j = 0; j < dnp->dn_nblkptr; j++) { 206*88b7b0f2SMatthew Ahrens zbookmark_t czb; 207*88b7b0f2SMatthew Ahrens 208*88b7b0f2SMatthew Ahrens SET_BOOKMARK(&czb, zb->zb_objset, 209*88b7b0f2SMatthew Ahrens zb->zb_blkid * epb + i, 210*88b7b0f2SMatthew Ahrens dnp->dn_nlevels - 1, j); 211*88b7b0f2SMatthew Ahrens err = traverse_visitbp(td, dnp, buf, 212*88b7b0f2SMatthew Ahrens (blkptr_t *)&dnp->dn_blkptr[j], &czb); 213*88b7b0f2SMatthew Ahrens if (err) 214*88b7b0f2SMatthew Ahrens break; 215fa9e4066Sahrens } 216fa9e4066Sahrens } 217*88b7b0f2SMatthew Ahrens } else if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) { 218*88b7b0f2SMatthew Ahrens uint32_t flags = ARC_WAIT; 219*88b7b0f2SMatthew Ahrens objset_phys_t *osp; 220*88b7b0f2SMatthew Ahrens int j; 221*88b7b0f2SMatthew Ahrens 222*88b7b0f2SMatthew Ahrens err = arc_read_nolock(NULL, td->td_spa, bp, 223*88b7b0f2SMatthew Ahrens arc_getbuf_func, &buf, 224*88b7b0f2SMatthew Ahrens ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb); 225*88b7b0f2SMatthew Ahrens if (err) 226*88b7b0f2SMatthew Ahrens return (err); 227*88b7b0f2SMatthew Ahrens 228*88b7b0f2SMatthew Ahrens osp = buf->b_data; 229fa9e4066Sahrens /* 230*88b7b0f2SMatthew Ahrens * traverse_zil is just here for zdb's leak checking. 231*88b7b0f2SMatthew Ahrens * For other consumers, there will be no ZIL blocks. 232fa9e4066Sahrens */ 233*88b7b0f2SMatthew Ahrens traverse_zil(td, &osp->os_zil_header); 234fa9e4066Sahrens 235*88b7b0f2SMatthew Ahrens for (j = 0; j < osp->os_meta_dnode.dn_nblkptr; j++) { 236*88b7b0f2SMatthew Ahrens zbookmark_t czb; 237fa9e4066Sahrens 238*88b7b0f2SMatthew Ahrens SET_BOOKMARK(&czb, zb->zb_objset, 0, 239*88b7b0f2SMatthew Ahrens osp->os_meta_dnode.dn_nlevels - 1, j); 240*88b7b0f2SMatthew Ahrens err = traverse_visitbp(td, &osp->os_meta_dnode, buf, 241*88b7b0f2SMatthew Ahrens (blkptr_t *)&osp->os_meta_dnode.dn_blkptr[j], 242*88b7b0f2SMatthew Ahrens &czb); 243*88b7b0f2SMatthew Ahrens if (err) 244*88b7b0f2SMatthew Ahrens break; 245*88b7b0f2SMatthew Ahrens } 246*88b7b0f2SMatthew Ahrens } 247fa9e4066Sahrens 248*88b7b0f2SMatthew Ahrens if (buf) 249*88b7b0f2SMatthew Ahrens (void) arc_buf_remove_ref(buf, &buf); 250fa9e4066Sahrens 251*88b7b0f2SMatthew Ahrens if (err == 0 && (td->td_flags & TRAVERSE_POST)) 252*88b7b0f2SMatthew Ahrens err = td->td_func(td->td_spa, bp, zb, dnp, td->td_arg); 253fa9e4066Sahrens 254fa9e4066Sahrens return (err); 255fa9e4066Sahrens } 256fa9e4066Sahrens 257*88b7b0f2SMatthew Ahrens /* ARGSUSED */ 258*88b7b0f2SMatthew Ahrens static int 259*88b7b0f2SMatthew Ahrens traverse_prefetcher(spa_t *spa, blkptr_t *bp, const zbookmark_t *zb, 260*88b7b0f2SMatthew Ahrens const dnode_phys_t *dnp, void *arg) 261e7cbe64fSgw { 262*88b7b0f2SMatthew Ahrens struct prefetch_data *pfd = arg; 263*88b7b0f2SMatthew Ahrens uint32_t aflags = ARC_NOWAIT | ARC_PREFETCH; 264e7cbe64fSgw 265*88b7b0f2SMatthew Ahrens ASSERT(pfd->pd_blks_fetched >= 0); 266*88b7b0f2SMatthew Ahrens if (pfd->pd_cancel) 267*88b7b0f2SMatthew Ahrens return (EINTR); 268e7cbe64fSgw 269*88b7b0f2SMatthew Ahrens if (bp == NULL || !((pfd->pd_flags & TRAVERSE_PREFETCH_DATA) || 270*88b7b0f2SMatthew Ahrens BP_GET_TYPE(bp) == DMU_OT_DNODE || BP_GET_LEVEL(bp) > 0)) 271fa9e4066Sahrens return (0); 272fa9e4066Sahrens 273*88b7b0f2SMatthew Ahrens mutex_enter(&pfd->pd_mtx); 274*88b7b0f2SMatthew Ahrens while (!pfd->pd_cancel && pfd->pd_blks_fetched >= pfd->pd_blks_max) 275*88b7b0f2SMatthew Ahrens cv_wait(&pfd->pd_cv, &pfd->pd_mtx); 276*88b7b0f2SMatthew Ahrens pfd->pd_blks_fetched++; 277*88b7b0f2SMatthew Ahrens cv_broadcast(&pfd->pd_cv); 278*88b7b0f2SMatthew Ahrens mutex_exit(&pfd->pd_mtx); 279fa9e4066Sahrens 280*88b7b0f2SMatthew Ahrens (void) arc_read_nolock(NULL, spa, bp, NULL, NULL, 281*88b7b0f2SMatthew Ahrens ZIO_PRIORITY_ASYNC_READ, 282*88b7b0f2SMatthew Ahrens ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE, 283*88b7b0f2SMatthew Ahrens &aflags, zb); 284fa9e4066Sahrens 285*88b7b0f2SMatthew Ahrens return (0); 286fa9e4066Sahrens } 287fa9e4066Sahrens 288fa9e4066Sahrens static void 289*88b7b0f2SMatthew Ahrens traverse_prefetch_thread(void *arg) 290fa9e4066Sahrens { 291*88b7b0f2SMatthew Ahrens struct traverse_data *td_main = arg; 292*88b7b0f2SMatthew Ahrens struct traverse_data td = *td_main; 293*88b7b0f2SMatthew Ahrens zbookmark_t czb; 294fa9e4066Sahrens 295*88b7b0f2SMatthew Ahrens td.td_func = traverse_prefetcher; 296*88b7b0f2SMatthew Ahrens td.td_arg = td_main->td_pfd; 297*88b7b0f2SMatthew Ahrens td.td_pfd = NULL; 298fa9e4066Sahrens 299*88b7b0f2SMatthew Ahrens SET_BOOKMARK(&czb, td.td_objset, 0, -1, 0); 300*88b7b0f2SMatthew Ahrens (void) traverse_visitbp(&td, NULL, NULL, td.td_rootbp, &czb); 301fa9e4066Sahrens 302*88b7b0f2SMatthew Ahrens mutex_enter(&td_main->td_pfd->pd_mtx); 303*88b7b0f2SMatthew Ahrens td_main->td_pfd->pd_exited = B_TRUE; 304*88b7b0f2SMatthew Ahrens cv_broadcast(&td_main->td_pfd->pd_cv); 305*88b7b0f2SMatthew Ahrens mutex_exit(&td_main->td_pfd->pd_mtx); 306fa9e4066Sahrens } 307fa9e4066Sahrens 308*88b7b0f2SMatthew Ahrens /* 309*88b7b0f2SMatthew Ahrens * NB: dataset must not be changing on-disk (eg, is a snapshot or we are 310*88b7b0f2SMatthew Ahrens * in syncing context). 311*88b7b0f2SMatthew Ahrens */ 312*88b7b0f2SMatthew Ahrens static int 313*88b7b0f2SMatthew Ahrens traverse_impl(spa_t *spa, uint64_t objset, blkptr_t *rootbp, 314*88b7b0f2SMatthew Ahrens uint64_t txg_start, int flags, blkptr_cb_t func, void *arg) 315fa9e4066Sahrens { 316*88b7b0f2SMatthew Ahrens struct traverse_data td; 317*88b7b0f2SMatthew Ahrens struct prefetch_data pd = { 0 }; 318*88b7b0f2SMatthew Ahrens zbookmark_t czb; 319*88b7b0f2SMatthew Ahrens int err; 320fa9e4066Sahrens 321*88b7b0f2SMatthew Ahrens td.td_spa = spa; 322*88b7b0f2SMatthew Ahrens td.td_objset = objset; 323*88b7b0f2SMatthew Ahrens td.td_rootbp = rootbp; 324*88b7b0f2SMatthew Ahrens td.td_min_txg = txg_start; 325*88b7b0f2SMatthew Ahrens td.td_func = func; 326*88b7b0f2SMatthew Ahrens td.td_arg = arg; 327*88b7b0f2SMatthew Ahrens td.td_pfd = &pd; 328*88b7b0f2SMatthew Ahrens td.td_flags = flags; 329*88b7b0f2SMatthew Ahrens 330*88b7b0f2SMatthew Ahrens pd.pd_blks_max = 100; 331*88b7b0f2SMatthew Ahrens pd.pd_flags = flags; 332*88b7b0f2SMatthew Ahrens mutex_init(&pd.pd_mtx, NULL, MUTEX_DEFAULT, NULL); 333*88b7b0f2SMatthew Ahrens cv_init(&pd.pd_cv, NULL, CV_DEFAULT, NULL); 334*88b7b0f2SMatthew Ahrens 335*88b7b0f2SMatthew Ahrens if (!(flags & TRAVERSE_PREFETCH) || 336*88b7b0f2SMatthew Ahrens 0 == taskq_dispatch(system_taskq, traverse_prefetch_thread, 337*88b7b0f2SMatthew Ahrens &td, TQ_NOQUEUE)) 338*88b7b0f2SMatthew Ahrens pd.pd_exited = B_TRUE; 339*88b7b0f2SMatthew Ahrens 340*88b7b0f2SMatthew Ahrens SET_BOOKMARK(&czb, objset, 0, -1, 0); 341*88b7b0f2SMatthew Ahrens err = traverse_visitbp(&td, NULL, NULL, rootbp, &czb); 342*88b7b0f2SMatthew Ahrens 343*88b7b0f2SMatthew Ahrens mutex_enter(&pd.pd_mtx); 344*88b7b0f2SMatthew Ahrens pd.pd_cancel = B_TRUE; 345*88b7b0f2SMatthew Ahrens cv_broadcast(&pd.pd_cv); 346*88b7b0f2SMatthew Ahrens while (!pd.pd_exited) 347*88b7b0f2SMatthew Ahrens cv_wait(&pd.pd_cv, &pd.pd_mtx); 348*88b7b0f2SMatthew Ahrens mutex_exit(&pd.pd_mtx); 349*88b7b0f2SMatthew Ahrens 350*88b7b0f2SMatthew Ahrens mutex_destroy(&pd.pd_mtx); 351*88b7b0f2SMatthew Ahrens cv_destroy(&pd.pd_cv); 352fa9e4066Sahrens 353*88b7b0f2SMatthew Ahrens return (err); 354fa9e4066Sahrens } 355fa9e4066Sahrens 356*88b7b0f2SMatthew Ahrens /* 357*88b7b0f2SMatthew Ahrens * NB: dataset must not be changing on-disk (eg, is a snapshot or we are 358*88b7b0f2SMatthew Ahrens * in syncing context). 359*88b7b0f2SMatthew Ahrens */ 360*88b7b0f2SMatthew Ahrens int 361*88b7b0f2SMatthew Ahrens traverse_dataset(dsl_dataset_t *ds, uint64_t txg_start, int flags, 362*88b7b0f2SMatthew Ahrens blkptr_cb_t func, void *arg) 363fa9e4066Sahrens { 364*88b7b0f2SMatthew Ahrens return (traverse_impl(ds->ds_dir->dd_pool->dp_spa, ds->ds_object, 365*88b7b0f2SMatthew Ahrens &ds->ds_phys->ds_bp, txg_start, flags, func, arg)); 366fa9e4066Sahrens } 367fa9e4066Sahrens 368*88b7b0f2SMatthew Ahrens /* 369*88b7b0f2SMatthew Ahrens * NB: pool must not be changing on-disk (eg, from zdb or sync context). 370*88b7b0f2SMatthew Ahrens */ 371*88b7b0f2SMatthew Ahrens int 372*88b7b0f2SMatthew Ahrens traverse_pool(spa_t *spa, blkptr_cb_t func, void *arg) 373fa9e4066Sahrens { 374*88b7b0f2SMatthew Ahrens int err; 375*88b7b0f2SMatthew Ahrens uint64_t obj; 376*88b7b0f2SMatthew Ahrens dsl_pool_t *dp = spa_get_dsl(spa); 377*88b7b0f2SMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 378*88b7b0f2SMatthew Ahrens 379*88b7b0f2SMatthew Ahrens /* visit the MOS */ 380*88b7b0f2SMatthew Ahrens err = traverse_impl(spa, 0, spa_get_rootblkptr(spa), 381*88b7b0f2SMatthew Ahrens 0, TRAVERSE_PRE, func, arg); 382*88b7b0f2SMatthew Ahrens if (err) 383*88b7b0f2SMatthew Ahrens return (err); 384*88b7b0f2SMatthew Ahrens 385*88b7b0f2SMatthew Ahrens /* visit each dataset */ 386*88b7b0f2SMatthew Ahrens for (obj = 1; err == 0; err = dmu_object_next(mos, &obj, FALSE, 0)) { 387*88b7b0f2SMatthew Ahrens dmu_object_info_t doi; 388*88b7b0f2SMatthew Ahrens 389*88b7b0f2SMatthew Ahrens err = dmu_object_info(mos, obj, &doi); 390*88b7b0f2SMatthew Ahrens if (err) 391*88b7b0f2SMatthew Ahrens return (err); 392*88b7b0f2SMatthew Ahrens 393*88b7b0f2SMatthew Ahrens if (doi.doi_type == DMU_OT_DSL_DATASET) { 394*88b7b0f2SMatthew Ahrens dsl_dataset_t *ds; 395*88b7b0f2SMatthew Ahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 396*88b7b0f2SMatthew Ahrens err = dsl_dataset_hold_obj(dp, obj, FTAG, &ds); 397*88b7b0f2SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 398*88b7b0f2SMatthew Ahrens if (err) 399*88b7b0f2SMatthew Ahrens return (err); 400*88b7b0f2SMatthew Ahrens err = traverse_dataset(ds, 401*88b7b0f2SMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, TRAVERSE_PRE, 402*88b7b0f2SMatthew Ahrens func, arg); 403*88b7b0f2SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 404*88b7b0f2SMatthew Ahrens if (err) 405*88b7b0f2SMatthew Ahrens return (err); 406*88b7b0f2SMatthew Ahrens } 407fa9e4066Sahrens } 408*88b7b0f2SMatthew Ahrens if (err == ESRCH) 409*88b7b0f2SMatthew Ahrens err = 0; 410*88b7b0f2SMatthew Ahrens return (err); 411fa9e4066Sahrens } 412